HomebrewとAnsibleでMacの開発環境構築を自動化する


3月20日に13″ rMBP early 2015が手元に届いたので、以下の様なツイートをしながらPlaybookを作っていました。

例のごとく、そのとき取り組んだことを整理した上で公開しようとしていたわけですが、その日の夕方、@t_wadaさんによって、Mac の開発環境構築を自動化する (2015 年初旬編)という記事が公開されました。内容がほぼ被っているので、私のメモを公開する意義は少ないわけですが、アプローチが違う部分、修正した部分もあるので残しておきます。
Homebrew + Ansibleで、CLI, GUIアプリともに管理します。非常に簡単なので、ぜひ取り組んでいただければと思います。
mawatari/mac-provisioning – GitHub

ちなみに、Ansibleを使わずにやりたい場合は、以下の記事が参考になるかもしれません。
Brewfileはオワコンではない
Homebrew-fileでhomebrewでインストールしたパッケージの管理をする

環境

環境は以下の通りです。工場出荷状態の13″ rMBP early 2015で試しました。
以下の説明はクリーンインストールされたMacOSを前提にしているので、環境によっては違ってくる部分もあると思いますが、その点は留意してください。
念のため、OSの再インストールを3回繰り返してチェックしたので、同じ環境であれば同様の手順で簡単に再現できるはずです。

ソフトウェアバージョン
MacOS10.10.2

自動化の準備

まずは、開発環境の構築を自動化するための準備を行います。

Xcodeのインストール

以下のコマンドを実行して、Xcodeをインストールします。

mac-provisioning-by-homebrew-and-ansible-01

コマンドラインデベロッパーツールのインストール確認が表示されるので、インストールを選択します。その後、ライセンスの確認も表示されるので、わざわざXcodeを立ち上げる必要もありません。

Homebrewのインストール

続いてHomebrewをインストールします。

Ansibleのインストール

最後にAnsibleをインストールします。

環境構築

自動化の準備が整ったので、環境構築を行います。

自動化のためのPlaybookの取得

今回作ったPlaybookを公開しているので、それを入手します。
mawatari/mac-provisioning – GitHub

必要なソフトウェアの編集

web-development.ymlを編集します。編集対象は varsの部分のみで、ここに管理したいソフトウェアを記述するだけです。
web-development.ymlというファイル名に関しては何でも良いですが、個人的には役割ごとにPlaybookを管理したいので、このような名前にしました。Webデザイン用のツールを管理する web-design.ymlとか、ソフトウェアの設定ファイルなどをインポートする initialize.ymlとかを追加していくイメージです。

Homebrew Caskオプションの設定

Ansibleのhomebrew_caskモジュールでは指定できないオプションを指定するため、 .bash_profileに追記します。
特に appdirオプションについては、設定を強くオススメします。設定しておかないと、アプリケーションによって /Applicationsだったり、 ~/Applicationsだったりにシンボリックリンクリンクが作られてしまいます。
その他、必要に応じてオプションを追加しましょう。詳しくは公式ドキュメントを参照してください。
How to Use Homebrew-cask

Playbookの実行

編集が完了したら、Playbookを実行します。homebrew_cask_packagesの最初のインストール時にはパスワードの入力を求められると思います。

以上で完了です。定期的に上記コマンドを実行するなどして、ソフトウェアをフレッシュな状態に保ちましょう。 -vvオプションについてはデバッグ情報の出力なので、お好みで。

テスト

構築した環境が正しい状態にあるかをテストします。別記事にまとめたのでそちらを参照してください。
ServerspecでMacの開発環境をテストする

解説

基本的には@hnakamurさんと、@t_wadaさんが公開しているブログと同様なのですが、下記の点を修正しています。

  • opensslがアップグレードされない問題を修正した。
  • opensslのシンボリックリンク作成を強制するようにした。
  • homebrew_packages, homebrew_cask_packagesともに、 StringHashで指定をきるようにした。
  • install_optionsに、複数個のオプションを指定できるようにした。また。また、 StringArrayで指定できるようにした。

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取り込まれました!

イケてない部分

それなりに使えるようにはなっていますが、イケてない部分があります。

  1. brew install, brew cask install実行時の標準出力が見れない。
  2. PLAY RECAPはタスクに対する結果なので、例えば、3つのソフトウェアがインストールされたとしても、 changed=1になってしまう。

1. に関しては、割りと致命的な感じがしてます。例えば、 brew install rbenvをした場合だと、 echo 'eval "$(rbenv init -)"' >> ~/.bash_profileを実行するように案内が出るのに、それをキャッチできないのはツライかなと。 brew infoで見れないことはないですが、なんとか、その辺をスマートにできたら良いなと思います。Ansibleマスターからのアプローチをお待ちしております!
あと、 link openssl --forceの件は、目視確認中に気づけましたが、これは見落とす危険性が高いです。このへんはテストを書くなり、何かしらの対処をしたほうが良さそうですね。

参考リンク

以下のページを参考にしました。ありがとうございます。

以上です。