MacだってAnsibleで構成管理したい！

# 概要

- Mac を Ansible で構成管理したお話です。
- Ansible をベースに homebrew/homebrew-cask/homesick を用いて、極力少ないコマンドで Mac の開発環境を構築できるようにしました。
- コードはここのリポジトリに上げています :cat: https://github.com/supistar/dotfiles

# ことはじめ

それはある日のこと...

「あ"あ"あ"あ"あ"！！！ド"ッ"ト"フ"ァ"イ"ル"ま"と"め"て"き"え"た"あ"あ"あ"あ"あ"あ"！！！！！」

某科学特捜班のドラマの見過ぎか、思わず上記そのままの叫びをあげてしまった筆者...。[^1]

悲しみに暮れつつも、ちょうど使ってるマシンの OS が Mavericks のままに気付き、
「そういえば Yosemite にしたいと思ってたんや！」
ということで、一念発起してドットファイルなどもまとめて Mac を構成管理しようと思い立ったのでした。

# Macの現状と管理方針

## Macの現状
まずは筆者が開発に利用している Mac (MacBookAir・2年半利用) の現状をまとめると下記の通り。

> - 単純なパッケージは Homebrew でインストールしているものが多い。
> - 一方で、バイナリパッケージは手動インストールしているものが多く、Homebrew Caskに寄せたいと思いつつ手付かずの状況。
> - Ruby は`rvm`・Node は`nvm`で管理。Pythonはそんなに使う機会が無く、Macデフォルトのを騙し騙し使ってきた。が、横の横の人の影響でPythonを書くことが増えてきて `pyenv` で管理できるようにしたいと思っている。
> - ドットファイルの管理ができていないので、GitHubに置きたい（重要：悲劇再発防止）

2年半の間クリーンインストールも特に行わず、同じ環境で使っているとごちゃごちゃしているのを反省する内容... :sweat: 

## 管理方針
そこで「管理をシンプルに」かつ「開発環境をすぐ用意できるようにする」という目的を立て、下記の管理方針を立てました。

> - 構成管理ツールに `Ansible` を用いる
> - アプリケーションは `Homebrew` or `Homebrew Cask` でインストールする
> - 極力少ないコマンドで開発環境が構成できるようにする
> - ドットファイルも構成管理の中に入れる
> - Python/Ruby/Nodeを `anyenv` で管理する

ちなみに上記のようにしたのは、

- Brewfile が直接使えなくなった（変換が必要）なのと、Brewfile を使って再インストール時に警告表示になるのがわかりにくい。
  - ここは Ansible を使うと良い感じになるみたい[^2]。 Ansible 使いたかったし一石二鳥 :+1: 
- `direnv` がどうもしっくりこなかった。逆に `anyenv` がすごくしっくりきた。

という個人的な経緯があるので、もし気になる方はご参考までに。

# そしてAnsibleへ

いくつかのサイト[^2][^3][^4][^5] を参考にさせていただき、構成ができあがりました。
https://github.com/supistar/dotfiles

## 使い方

使い方はいたって簡単。Terminalから下記のコマンドを打ち込むだけ。

**注意：Xcodeは先に入れておきましょう。**

```bash
# こうじゃ (^ω^)
curl -LSfs https://raw.githubusercontent.com/supistar/dotfiles/master/install.sh | bash
```

あとはひたすら待つだけ。
ただ、インストールするパッケージによってはパスワードを聞かれるので
その時はログインしているユーザーのパスワードを入れてください。

# ハマりポイント

さて、ここまで来るのにハマったポイントを備忘録代わりに記しておきます。

## 1. Ansibleの設定ファイルでホームディレクトリを参照したいときは ${HOME} ではなく ~ を利用する

シェルスクリプトと同じ感覚で

```yaml:macbook-NG-Pattern.yml
file: path=${HOME}/Library/Application\ Support/Karabiner   state=directory
```

と書いたら、いまいるディレクトリに `${HOME}` という名前のディレクトリが出来ててズッコケ... (´･ω･`)
ここは素直にこう書きましょう。

```yaml:macbook-OK-Pattern.yml
file: path=~/Library/Application\ Support/Karabiner state=directory
```
  
## 2. Ansibleの設定ファイルでワイルドカードを使いたいときは `command` タスクではなく `shell` タスクを使う

これは書いてある通り、

```yaml:macbook-NG-pattern.yml
command: cp -f /usr/local/opt/ricty/share/fonts/Ricty*.ttf ~/Library/Fonts/
```

ではなく

```yaml:macbook-OK-pattern.yml
shell: cp -f /usr/local/opt/ricty/share/fonts/Ricty*.ttf ~/Library/Fonts/
```

と書くと正しくワイルドカードを解釈してくれます :)

## 3. Wine をインストールする場合は `xquartz` を先にインストールするように

（たぶんWineに限った話では無いのかもしれませんが...）
`xquartz` が入っていないと Wine 関連パッケージ (`wine`, `winetricks`) をインストールするときに失敗します。
Homebrew Cask -> Homebrew の順にパッケージをイントールするようにし、Homebrew Caskのタスクの先頭に xquartz を持ってくるといい感じになります。

## 4. Homebrew-versions の Tap は `pre_task` でしておくと幸せになれるかも（ただしケースバイケース）

何故ケースバイケースかと言うと、筆者の場合は上記の3で Homebrew Cask -> Homebrew の順番にしたため。
@hnakamur さんが作られた `homebrew-packages`[^6] ではすでに `homebrew_packages_taps` という Role Variables があり、そこに記述するとパッケージインストール前に Tap してくれるのですが、`homebrew-cask-packages`[^7] には定義されていないようでうまく動きませんでした。

筆者は Homebrew から `appledoc22`、Homebrew Cask から `java6`/`java7`、あとは個人的に定義した `unity463p2` の環境が欲しかったので、いくつかのリポジトリを予めTapするようにしておきました。
これで安心。

# Ansible管理にした総括

使ってみての感想は「もっと早く使っておけばよかった！」

## 良い点

- 当たり前ですが環境構築が驚くほど楽！
- Homebrew で管理しているパッケージのアップデートも Ansible のコマンドでOK
  - アップデートがあった場合、[changed] の表記が入るので認識しやすい。

```bash
ansible-playbook macbook.yml -i hosts
```

## イマイチな点
- インストール時に、時折パスワードを要求されることがある。
  - パスワード要求に気付かずインストールが終わってないことも。
  - `sudo` オプションを付ければよさそうなんだけど、Homebrew のインストールを `sudo` にするのもなー。という印象 (´･ω･`)
- （Homebrew Cask で管理してるからというのもありますが）アプリケーション自体の自動アップデートが走った場合にCaskで管理してるバージョンと実バージョンに差異が生じる

ただ、これらは改善するともっと快適になりそうなのでもう少し試行錯誤してみようと思います。

---

ちなみに導入後はこんな感じになりました。
フォントを調整したりするだけで、再構築前と同様にバリバリ開発できる環境になるので感動ですね。

![Screen Shot 2015-03-06 at 23.11.52 copy.png](https://qiita-image-store.s3.amazonaws.com/0/11364/d36de7e3-68df-e0ad-8fe7-feaca80dd8f2.png)


Happy management!


# 注釈・参考サイト
[^1]: ドットファイルをGitHubで管理しようとして、`dotfilesdir`に移動＋symlink貼っていたのをすっかり忘れてしまって、`rm -rf ./dotfilesdir` したというオチ... (´･ω･`)
[^2]: http://qiita.com/hnakamur/items/1c27cf0df19fe57ec624
[^3]: http://joe-re.hatenablog.com/entry/2015/01/02/212007
[^4]: http://qiita.com/FGtatsuro/items/1c490abee7061a6ec79e
[^5]: https://github.com/r7kamura/dotfiles
[^6]: https://galaxy.ansible.com/list#/roles/1003
[^7]: https://galaxy.ansible.com/list#/roles/1004