HomebrewとAnsibleでMacの開発環境構築を自動化する
3月20日に13″ rMBP early 2015が手元に届いたので、以下の様なツイートをしながらPlaybookを作っていました。
GUIアプリも含めて全部Homebrewで管理してみようかな。
— まわたりなおと (@mawatarin) 2015, 3月 20
んー?Brewfileで管理できないのか?
http://t.co/g8eBr2tInk
— まわたりなおと (@mawatarin) 2015, 3月 20
うん。Brewfileの代替はこれがよさそうだな。今夜やってみよう。
http://t.co/mxXRd3IGK2
— まわたりなおと (@mawatarin) 2015, 3月 20
例のごとく、そのとき取り組んだことを整理した上で公開しようとしていたわけですが、その日の夕方、@t_wadaさんによって、Mac の開発環境構築を自動化する (2015 年初旬編)という記事が公開されました。内容がほぼ被っているので、私のメモを公開する意義は少ないわけですが、アプローチが違う部分、修正した部分もあるので残しておきます。
Homebrew + Ansibleで、CLI, GUIアプリともに管理します。非常に簡単なので、ぜひ取り組んでいただければと思います。
mawatari/mac-provisioning – GitHub
ちなみに、Ansibleを使わずにやりたい場合は、以下の記事が参考になるかもしれません。
Brewfileはオワコンではない
Homebrew-fileでhomebrewでインストールしたパッケージの管理をする
環境
環境は以下の通りです。工場出荷状態の13″ rMBP early 2015で試しました。
以下の説明はクリーンインストールされたMacOSを前提にしているので、環境によっては違ってくる部分もあると思いますが、その点は留意してください。
念のため、OSの再インストールを3回繰り返してチェックしたので、同じ環境であれば同様の手順で簡単に再現できるはずです。
ソフトウェア | バージョン |
---|---|
MacOS | 10.10.2 |
自動化の準備
まずは、開発環境の構築を自動化するための準備を行います。
Xcodeのインストール
以下のコマンドを実行して、Xcodeをインストールします。
1 | sudo xcodebuild -license |
コマンドラインデベロッパーツールのインストール確認が表示されるので、インストールを選択します。その後、ライセンスの確認も表示されるので、わざわざXcodeを立ち上げる必要もありません。
Homebrewのインストール
続いてHomebrewをインストールします。
1 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" |
Ansibleのインストール
最後にAnsibleをインストールします。
1 2 | brew update brew install ansible |
環境構築
自動化の準備が整ったので、環境構築を行います。
自動化のためのPlaybookの取得
今回作ったPlaybookを公開しているので、それを入手します。
mawatari/mac-provisioning – GitHub
1 2 3 | brew install git mkdir ~/.provisioning && cd $_ git clone https://github.com/mawatari/mac-provisioning.git . |
必要なソフトウェアの編集
web-development.ymlを編集します。編集対象は varsの部分のみで、ここに管理したいソフトウェアを記述するだけです。
web-development.ymlというファイル名に関しては何でも良いですが、個人的には役割ごとにPlaybookを管理したいので、このような名前にしました。Webデザイン用のツールを管理する web-design.ymlとか、ソフトウェアの設定ファイルなどをインポートする initialize.ymlとかを追加していくイメージです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | - hosts: localhost connection: local gather_facts: no sudo: no roles: - homebrew - homebrew-cask vars: # Tap external Homebrew repositories. # # e.g. # - homebrew/binary homebrew_repositories: # Managed Homebrew packages. # # e.g. # - package_name # or # { name: package_name, state: package_state, install_options: [with-baz, enable-debug] } # # state choices: [head, latest, present, absent, linked, unlinked] (default latest) # install_options: string or sequence (default none) homebrew_packages: - readline - openssl - { name: openssl, state: linked, install_options: force } - ansible - bash-completion - git - rbenv - ruby-build # Tap external Homebrew Cask repositories. homebrew_cask_repositories: # Managed Homebrew Cask packages. # # e.g. # - package_name # or # { name: package_name, state: package_state } # # state choices: [present, absent, installed, uninstalled] (default present) homebrew_cask_packages: - firefox - google-chrome - google-japanese-ime - intellij-idea - karabiner - phpstorm - slack - vagrant - virtualbox |
Homebrew Caskオプションの設定
Ansibleのhomebrew_caskモジュールでは指定できないオプションを指定するため、 .bash_profileに追記します。
特に appdirオプションについては、設定を強くオススメします。設定しておかないと、アプリケーションによって /Applicationsだったり、 ~/Applicationsだったりにシンボリックリンクリンクが作られてしまいます。
その他、必要に応じてオプションを追加しましょう。詳しくは公式ドキュメントを参照してください。
How to Use Homebrew-cask
1 2 | echo 'export HOMEBREW_CASK_OPTS="--appdir=/Applications"' >> ~/.bash_profile source ~/.bash_profile |
Playbookの実行
編集が完了したら、Playbookを実行します。homebrew_cask_packagesの最初のインストール時にはパスワードの入力を求められると思います。
1 | ansible-playbook -i hosts -vv web-development.yml |
以上で完了です。定期的に上記コマンドを実行するなどして、ソフトウェアをフレッシュな状態に保ちましょう。 -vvオプションについてはデバッグ情報の出力なので、お好みで。
テスト
構築した環境が正しい状態にあるかをテストします。別記事にまとめたのでそちらを参照してください。
ServerspecでMacの開発環境をテストする
解説
基本的には@hnakamurさんと、@t_wadaさんが公開しているブログと同様なのですが、下記の点を修正しています。
- opensslがアップグレードされない問題を修正した。
- opensslのシンボリックリンク作成を強制するようにした。
- homebrew_packages, homebrew_cask_packagesともに、 Stringか Hashで指定をきるようにした。
- install_optionsに、複数個のオプションを指定できるようにした。また。また、 Stringか Arrayで指定できるようにした。
AnsibleでHomebrew, Cask, Atomエディターのパッケージを管理する – Qiita
Mac の開発環境構築を自動化する (2015 年初旬編) – t-wadaのブログ
opensslがアップグレードされない問題を修正した
brew upgradeが実行されない状態で、 { name: openssl, state: linked }の指定だけだと、 opensslがアップグレードされません。 state: linkedは、あくまでシンボリックリンクを作成するだけだからです。
これに対して、 - opensslを別個に指定することで回避しています。
brew upgradeを実行するタスクを追加するのもよいでしょう。ただし、タスクの順序によっては、 homebrew_packagesのタスクが全て OK表示になってしまうため気をつけましょう。
opensslのシンボリックリンク作成を強制するようにした
brew linkコマンドを使って opensslのシンボリックリンクを作ったことがある方ならわかると思いますが、 --forceオプションを求められます。AnsibleのHomebrewモジュールを使った場合も同様で、 forceオプションを付けなければ、シンボリックリンクは作成されません。
厄介なのが、 forceオプションを与えなかった時も changed表示になるという点です。もちろん、シンボリックリンクは作られていませんので、気付かずにMacに入っている古い opensslを使い続けることになってしまいます。
packagesはStringかHashで指定できるようにした
参考記事の例だと冗長だと感じたので、オプションを付ける必要がない場合は、ソフトウェア名を Stringで指定できるようにしました。
install_optionsに複数個のオプションを指定できるようにした
参考記事のやり方だと、 install_optionsに1つのオプションしか取れません。その点を修正しました。また、1つであった場合に Arrayを強制されると使いづらいので Stringも取れるようにしました。
これらに関しては元のコンセプトを無視しない程度に修正して、PRを送っているので、もし取り込まれたならば、そちらを利用したほうが良いかもしれません。その辺はお好みで。
PR取り込まれました!
イケてない部分
それなりに使えるようにはなっていますが、イケてない部分があります。
- brew install, brew cask install実行時の標準出力が見れない。
- PLAY RECAPはタスクに対する結果なので、例えば、3つのソフトウェアがインストールされたとしても、 changed=1になってしまう。
1. に関しては、割りと致命的な感じがしてます。例えば、 brew install rbenvをした場合だと、 echo 'eval "$(rbenv init -)"' >> ~/.bash_profileを実行するように案内が出るのに、それをキャッチできないのはツライかなと。 brew infoで見れないことはないですが、なんとか、その辺をスマートにできたら良いなと思います。Ansibleマスターからのアプローチをお待ちしております!
あと、 link openssl --forceの件は、目視確認中に気づけましたが、これは見落とす危険性が高いです。このへんはテストを書くなり、何かしらの対処をしたほうが良さそうですね。
参考リンク
以下のページを参考にしました。ありがとうございます。
- AnsibleでHomebrew, Cask, Atomエディターのパッケージを管理する – Qiita
- Ansibleでhomebrewを管理する – 理系学生日記
- homebrew – Package manager for Homebrew – Ansible Documentation
- homebrew_cask – Install/uninstall homebrew casks. – Ansible Documentation
- Mac の開発環境構築を自動化する (2015 年初旬編) – t-wadaのブログ
以上です。