Vagrantで簡単に隔離された開発環境を構築できるようになって久しいが、その後も不満な点がいくつかあった。
最近になって一応満足できる解決策を見つけたので記述する。
細かな点やVagrantの使い方次第ですぐに解決できるものはさておき、主な不満点は下記のようなものだった。
- 設定やツールのカスタマイズ管理
- 私の場合は開発環境には最新のRubyが入っていてほしいし、「いつもの」Vim設定やZsh設定が為されていてほしい。
- 関連リポジトリのチェックアウト
- 関連する複数のソースリポジトリをチェックアウトしてきてそれらをまとめて1つのVagrant環境内で開発したいことがよくある。
しかし、もはやgit clone
とかタイプすることすら面倒だし、環境を作り直すたびにどのリポジトリをチェックアウトすれば良いのか覚えておくのは嫌になる。
- 関連する複数のソースリポジトリをチェックアウトしてきてそれらをまとめて1つのVagrant環境内で開発したいことがよくある。
- 以上すべてのバージョン管理
- 当然のことながら、
Vagrantfile
を含めて以上すべての設定はバージョン管理されていてほしい。私は設定を忘れる自信があるし、間違えて設定ファイルを上書きする自信もあるからだ。
- 当然のことながら、
方針
以上の問題を解決するために次のような方針を取った。
- 各種設定ファイル(主にdotfiles)をまとめたプライベートgitリポジトリを作る
- 設定ファイルをチェックアウトしてきて適切な箇所に配置し、更にツールをインストールする手順をChefで記述する
- このcookbookは独立したgitリポジトリで管理する
- このcookbookが依存するcookbookはBerkshelfで管理する。
- 関連リポジトリおよび上記cookbookをチェックアウトするための設定をgclientで書く
- cookbookはberkshelfにチェックアウトさせても良かったが、気分でgclientに管理させることにした。
- 関連リポジトリはホストマシンにチェックアウトしておいてVagrantfileの設定でゲストマシンにマウントする
利用例
以上の方針の例が https://github.com/yugui/bazel-workspace である。Bazelを追いかけつつGolang用ビルドルールを開発するのに使っている。
このワークスペースで作業を開始するには次のステップを踏む。
ワークスペース自体をチェックアウトする
$ git clone git@github.com:yugui/bazel-workspace.git
$ cd bazel-workspace
$ ls
Berksfile Berksfile.lock Vagrantfile data_bags/ roles/
gclientで関連リポジトリをチェックアウトする
$ gclient sync
Syncing projects: 100% (4/4), done.
$ ls
Berksfile Berksfile.lock Vagrantfile bazel/ cookbooks/ data_bags/ roles/ rules_go/ skydoc/
なおチェックアウトの設定ファイルである.gclient
は次のようになっている。
solutions = [
{
"name": "bazel",
"url": "https://bazel.googlesource.com/bazel@master",
},
{
"name": "rules_go",
"url": "https://github.com/bazelbuild/rules_go.git@master",
},
{
"name": "skydoc",
"url": "https://github.com/bazelbuild/skydoc.git@master",
},
{
"name": "cookbooks",
"url": "git@github.com:yugui/local-cookbooks.git@master",
},
]
Vagrantで環境を作る
$ vagrant up
...
- あらかじめvagrant-berkshelfプラグインを入れてあるのでまずBerkshelfが走る。
Berkshelfが設定用cookbookの依存関係を解決してくれる。 -
Vagrantfile
の設定に従って関連リポジトリはゲストマシン内にマウントされる - 更にcookbookに従って、dotfilesがチェックアウトされ、設定ファイルが配置され、開発ツールがインストールされる。
Vagrant.configure('2') do |config|
config.vm.box = 'ubuntu/trusty64'
config.ssh.forward_agent = true
config.vm.synced_folder "rules_go", "/src/rules_go"
config.vm.synced_folder "bazel", "/src/bazel"
config.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2222,
auto_correct: true
%w[ master ].each_with_index do |name, i|
config.vm.define(name) do |c|
c.vm.hostname = name
c.vm.provision :chef_solo do |chef|
chef.version = '12.10.40'
chef.data_bags_path = "data_bags"
chef.roles_path = %w[ roles ]
chef.json = {}
%w[ bazel ].each do |name|
chef.add_role name
end
end
end
end
end
まとめ
以上により、次の利点が得られた。
- dotfilesリポジトリやcookbookは再利用できるので、
Vagrantfile
内のrunlistを弄るだけでいつでも事前定義済みの環境設定を組み合わせて好みの開発環境を作れる-
Vagrantfile
,Berksfiles
と.gclient
だけコピーして修正すれば異なる開発環境を簡単に作れる
-
- 開発対象のリポジトリをチェックアウトする手順も構成管理されている
- 開発対象のリポジトリはまずホストマシンにチェックアウトされているし、各種設定はChefで自動化されている。このためゲストVMが壊れても失われるものはない。ゲストVMは気軽に作りなおせるし、再現できる
- 以上を実現するための
Vagrantfile
,Berksfile
および.gclient
自体もバージョン管理されている
補遺 - gclient
gclient
はChromiumプロジェクトが利用しているメタチェックアウトツールで、depot_tools
というツール群の1つである。これを利用するといくつものバージョン管理リポジトリからまとめてソースコードをチェックアウトしてくることができる。
機能としてはAndroidプロジェクトのrepo
にも近いが、repo
とは異なりgit以外のシステムもサポートしている。
また、gclientにはチェックアウト時に任意のスクリプトを実行するhook機能がある。
これを利用するとチェックアウトされたソースをポストプロセスしたり、未サポートのバージョン管理システムに対応したりもできる。
たとえば、私はgolangのプロジェクトではリポジトリに対してgo generate
を掛けたり、gom
でgolangプロジェクトをチェックアウトしたりしている。