この記事は クラウドワークスAdvent Calendar 2015 14日目の記事になります。(風邪をひいて一日遅れましたごめんなさい><)
今までの Mac 環境構築の歴史
最初は、インストールしたアプリケーションの手書きメモとホームディレクトリの dotfiles を dropbox 配下に移動しシンボリックリンクへ張替えを行う自前シェルスクリプトがあっただけでした。
アプリをインストールする度に、手元のメモを更新するという温かみのある日々(もちろん頻繁に更新を忘れる)、そんな日常に颯爽と現れた Github Boxen 1 !
Puppetを使ったプロビジョニングをローカルに適用するとか胸熱すぎる!さよなら僕の *.txt
*.sh
たち!
こうして冪等性と共に楽しい日々を送っていたのですが、半年ほどで異変が起き始めます。
まずboxen適用の実行時間がひたすら遅くなりはじめ、rubyの新バージョンをインストールしたいのに boxen 本家のアップデートを待つ羽目になり(仕方ないので手で入れようものならboxenに削除されてしまいます。冪等性の名のもとに)、いざアップデートしたら非互換の変更により僕が育てた boxen はエラーが発生し、ついに適用すらできなくなりました。2 マジFuxdajfkjfa
こうしてもはやスクラップ状態と化した Mavericks とはファイルシステムごとおさらばし、乗り換えた先が Ansible + homebrew_module 3 !
YAMLによる簡潔な記述で動作も軽快な Ansible とはパートナーとして仲良くやっていける!そう確信して意気揚々と playbook を育てていきました。
そんな日々にやってきた OS X Yosemite アップグレード!
いつものように ansible-playbook
コマンドを叩けばエラーの嵐!エラーを潰すために必要になる様々なコマンドを playbook に叩き込んでいくうちに、簡潔だった yaml がインデントとコマンドだらけになっていきました。。
そしてある日、 Ansible 自体のアップデートをしたら複雑化した僕の playbook は呆気無く実行できなくなってしまいました。 マジFufjdsk%^@(*&^@&!##!!!jljfldsakjkljxda!!!
思う所
環境構築を自動化したくてツールを使ってきたのですが、振り返ってみればツールの変化についていくことが精一杯で(むしろ振り切られて...)、自動化したいタイミングでいつもメンテが必要になっており、僕は自動化の恩恵を全く預かっていないことに気づきました....!!
mac の環境構築を行う頻度(新しいmac買った時、macが壊れた時、OSアップグレード時..etc) は短くても半年に一回程度ですが、現代のプロビジョニングツールの変遷はそれよりも早いようです。。
現在の構成
色々と考えた末、今(2015年末)の僕の mac の環境構築は下記のツールを組み合わせて、それらをインタラクティブに呼び出すシェルスクリプトで構成しています。
- homebrew + homebrew-cask + homebrew-brewdle
- パッケージとアプリの管理
- mackup
- dotfiles, ディレクトリ, アプリ設定の管理
- crontab
- バックアップ
ポイントは crontab
4 を用いてバックアップを自動化することで、プロビジョニングツール使用時に発生する 構成ファイルを編集(playbook, Brewfileなど)
-> 構成を適用
という手順を省略しています。
つまり、普段はいつも通り brew install hoge
や brew uninstall fuga
等で管理するだけでよく、初回の環境構築の時だけ専用のシェルスクリプトを呼べば良いようになっています。
homebrew + [homebrew-cask] (https://github.com/caskroom/homebrew-cask) + homebrew-brewdle 5
homebrew + homebrew-cask でパッケージとアプリケーションをほぼカバーでき、インストールするパッケージ/アプリのリストは homebrew-brewdle の Brewfile という形式で管理できます。
参考用の僕の Brewfile
は長いので、記事の一番下に記述しておきます。
※ MacAppStore からインストールするアプリはカバーできていないのですが、だれか良い方法があったら教えて下さい。
2016/04/23 追記
homebrew-brewdle
に MacAppStore をCLIで扱える mas-cli のサポートが追加されました。
Add Mac App Store support using mas-cli. by mikemcquaid · Pull Request #172 · Homebrew/homebrew-bundle
現時点では master
ブランチにしか入っていないので、明示的にリポジトリを設定すると使えるようになります。
$ brew install argon/mas/mas # mas-cli のインストール
$ brew tap homebrew/brewdler git@github.com:Homebrew/homebrew-bundle.git
$ brew update
バックアップ
homebrew-brewdle には dump
コマンドで Brewfile にインストールしているパッケージ/アプリの一覧をファイルに書き出す機能があるので、これを crontab
4 に設定し現在の構成を自動的にバックアップするようにしています。
@daily cd /your/brewfile/directory && brew brewdle dump --force && git add Brewfile && git commit -m "auto commit of Brewfile dump `date "+\%Y-\%m-\%d \%H:\%M:\%S"`" && git push
僕は git 管理下にしていますが、単に Dropbox 等の配下でもいいと思います。
@daily cd ~/Dropbox && brew brewdle dump --force
アップデート
パッケージ(homebrew) とアプリケーション(homebrew-cask) は crontab
で週次アップデートするようにしています。
@weekly time nice -n19 brew update && time nice -n19 brew upgrade && time nice -n19 brew cleanup && for c in `brew cask list`; do ! brew cask info $c | grep -qF "Not installed" || time nice -n19 brew cask install $c; done && time nice -n19 brew cask cleanup && for c in /opt/homebrew-cask/Caskroom/*; do vl=(`ls -t $c`) && for v in "${vl[@]:1}"; do \rm -rf "$c/$v"; done; done
参考リンク
mackup
mackup
は dotfiles や アプリケーションの設定を dropbox 等に同期してくれるアプリです。
といってもやっていることは単純で、実ファイルをコピーしてシンボリックリンクに置き換えているだけで、特に dotfiles については同様のことを自前で書いている人も多いのではないでしょうか?
使い方は mackup backup
コマンドを実行すれば終わりです。
この mackup は dotfiles に加えてかなりの数のアプリケーションの設定ファイルをサポートしているのでオススメです。
デフォルトに加えてバックアップしたいファイル/ディレクトリがある場合の設定ファイルの書き方も簡単ですし、Dropbox以外にも多数のストレージをサポートしています。参考までに僕のmackup設定ファイルはこちらです。
[application]
name = My personal synced files and dirs
[configuration_files]
.gitignore_global
.config
.bundle
.chef
.z
.zsh_history
Gemfile
Gemfile.lock
Documents
Movies
Music
Pictures
バックアップ
この mackup のコマンドを crontab に設定しておくことで新しいアプリの設定も自動的にバックアップされるようにしています。
@daily yes | mackup backup
環境構築用シェルスクリプト
あらかじめ Dropbox だけは同期しておき、このスクリプトを呼んで y
を連打するだけで環境構築を終えられるようになっています。
インタラクティブにしている理由は、OSアップグレード時などですんなり入らず途中で終了することもよくあるので、途中から再開しやすくするためです。
#!/bin/bash
BREWFILE_DIR=/your/brewfile/directory
ask() {
printf "$* [y/n] "
local answer
read answer
case $answer in
"yes" ) return 0 ;;
"y" ) return 0 ;;
* ) return 1 ;;
esac
}
set -e
if ask 'xcode install?'; then
xcode-select --install
fi
if ask 'Homebrew install?'; then
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew doctor
brew install caskroom/cask/brew-cask
fi
if ask 'execute brew brewdler(Brewfile)?'; then
brew tap Homebrew/brewdler
pushd $BREWFILE_DIR
brew brewdler
popd
fi
if ask 'restore setting from mackup? (need Dropbox directory)'; then
mackup restore
fi
if ask "Do you want to install ruby by rbenv-rubybuild?"; then
INSTALL_RUBY_VERSION="$( rbenv install -l | peco)"
brew link readline --force
MAKE_OPTS="-j 4" RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)" rbenv install $INSTALL_RUBY_VERSION
fi
OSXの設定
OSXの設定でコマンドで設定できるものはシェルスクリプトでやるようにしています。ですが、カバー率が低くGUIでポチポチと設定が必要なものも多いので、なにかいい方法はないですかね。。
## mac setting
if ask "set 'locate' command?"; then
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist
fi
if ask 'set visible dotfiles in finder?'; then
defaults write com.apple.finder AppleShowAllFiles TRUE
killall Finder
fi
if ask 'set fullpath title at finder?'; then
defaults write com.apple.finder _FXShowPosixPathInTitle -bool yes
killall Finder
fi
if ask 'set always expand save dialog?'; then
defaults write -g NSNavPanelExpandedStateForSaveMode -bool yes
fi
if ask 'set mute in mac booting sound?'; then
sudo nvram SystemAudioVolume=%80
fi
# @see https://discussionsjapan.apple.com/thread/10153604
if ask 'set clamshell mode off? (for multi display sleep)'; then
sudo nvram boot-args="niog=1"
fi
最後に
他にもここでは紹介していないですが、作業ディレクトリ圧縮+バックアップスクリプトなどを駆使して、いつ何時いまこの瞬間にmacが突然死しても、半日くらいで元の状態のマシンを構築できる体制を整えています。
ツールの移り変わりもあるので、来年の今頃はどんなツールを使っているかわかりませんが、新しいmacを買った時の時間の節約や最悪の事態の回避のために、常にブラッシュアップを続けていきたいと思います。
より良い方法やツッコミ、お待ちしております!
P.S. Brewfile
tap 'caskroom/cask'
tap 'homebrew/brewdler'
tap 'homebrew/dupes'
tap 'homebrew/services'
tap 'homebrew/versions'
cask 'java'
cask 'xquartz'
brew 'autoconf'
brew 'autossh'
brew 'awscli'
brew 'icu4c'
brew 'boost'
brew 'bsdmake'
brew 'cmake'
brew 'colordiff'
brew 'csshx'
brew 'go'
brew 'direnv'
brew 'xz'
brew 'gettext'
brew 'dwdiff'
brew 'elasticsearch'
brew 'exiftool'
brew 'pkg-config'
brew 'x264'
brew 'lame'
brew 'libvo-aacenc'
brew 'xvid'
brew 'libpng'
brew 'freetype'
brew 'openssl'
brew 'ffmpeg'
brew 'fortune'
brew 'gdbm'
brew 'ghi'
brew 'jpeg'
brew 'libtiff'
brew 'little-cms2'
brew 'ghostscript'
brew 'ghq'
brew 'gnu-getopt'
brew 'git-now'
brew 'heroku-toolbelt'
brew 'hub'
brew 'libtool'
brew 'imagemagick'
brew 'jbig2dec'
brew 'oniguruma'
brew 'jq'
brew 'libevent'
brew 'libffi'
brew 'libyaml'
brew 'mackup'
brew 'mecab'
brew 'mecab-ipadic'
brew 'memcached'
brew 'pcre'
brew 'nginx'
brew 'packer'
brew 'peco'
brew 'readline'
brew 'postgresql'
brew 'proctools'
brew 'q'
brew 'ruby-build'
brew 'rbenv'
brew 'rbenv-binstubs'
brew 'reattach-to-user-namespace'
brew 'redis'
brew 'rmtrash'
brew 'source-highlight'
brew 'spark'
brew 'terminal-notifier'
brew 'terraform'
brew 'the_silver_searcher'
brew 'tig'
brew 'tree'
brew 'watch'
brew 'wget'
brew 'youtube-dl'
brew 'z'
brew 'zsh'
brew 'caskroom/cask/brew-cask'
brew 'homebrew/dupes/apple-gcc42'
brew 'homebrew/versions/mysql56'
brew 'homebrew/versions/node012'
cask '1password'
cask 'adobe-creative-cloud'
cask 'alfred'
cask 'atom'
cask 'bartender'
cask 'burn'
cask 'caffeine'
cask 'cheatsheet'
cask 'chefdk'
cask 'clipy'
cask 'cyberduck'
cask 'disk-inventory-x'
cask 'dockertoolbox'
cask 'dropbox'
cask 'evernote'
cask 'flickr-uploadr'
cask 'flux'
cask 'github-desktop'
cask 'google-chrome'
cask 'google-drive'
cask 'google-japanese-ime'
cask 'google-photos-backup'
cask 'handbrake'
cask 'hosts'
cask 'imageoptim'
cask 'istat-menus'
cask 'iterm2'
cask 'karabiner'
cask 'licecap'
cask 'maczip4win'
cask 'mou'
cask 'rubymine'
cask 'sequel-pro'
cask 'shiftit'
cask 'skitch'
cask 'skype'
cask 'slack'
cask 'sublime-text'
cask 'vagrant'
cask 'virtualbox'
cask 'vlc'
cask 'zoomus'
-
mac では cron は非推奨で launchd を使うべきなようですが、launchd の記法を覚えるのが面倒でぼくは crontab 使ってます。>< ↩ ↩2
-
この記事を書いている最中に調べたら、homebrew-brewdle は homebrew-bundle に変更された(正確には戻った)ようです。Rename to
brew bundle
. · Homebrew/homebrew-bundle@2c59ed1 ですが、僕は brew-bundle で試していない+今もhomebrew-brewdleで動くので、記事中では homebrew-brewdle で統一します。 ↩