Gclient, VagrantおよびChefによる開発環境管理


Vagrantで簡単に隔離された開発環境を構築できるようになって久しいが、その後も不満な点がいくつかあった。
最近になって一応満足できる解決策を見つけたので記述する。

細かな点やVagrantの使い方次第ですぐに解決できるものはさておき、主な不満点は下記のようなものだった。

  • 設定やツールのカスタマイズ管理
    • 私の場合は開発環境には最新のRubyが入っていてほしいし、「いつもの」Vim設定やZsh設定が為されていてほしい。
  • 関連リポジトリのチェックアウト
    • 関連する複数のソースリポジトリをチェックアウトしてきてそれらをまとめて1つのVagrant環境内で開発したいことがよくある。 しかし、もはやgit cloneとかタイプすることすら面倒だし、環境を作り直すたびにどのリポジトリをチェックアウトすれば良いのか覚えておくのは嫌になる。
  • 以上すべてのバージョン管理
    • 当然のことながら、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 [email protected]: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は次のようになっている。

.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": "[email protected]:yugui/local-cookbooks.git@master",
    },
]

Vagrantで環境を作る

$ vagrant up
...
  1. あらかじめvagrant-berkshelfプラグインを入れてあるのでまずBerkshelfが走る。 Berkshelfが設定用cookbookの依存関係を解決してくれる。
  2. Vagrantfileの設定に従って関連リポジトリはゲストマシン内にマウントされる
  3. 更にcookbookに従って、dotfilesがチェックアウトされ、設定ファイルが配置され、開発ツールがインストールされる。
Vagrantfile
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

まとめ

以上により、次の利点が得られた。

  1. dotfilesリポジトリやcookbookは再利用できるので、Vagrantfile内のrunlistを弄るだけでいつでも事前定義済みの環境設定を組み合わせて好みの開発環境を作れる
    • Vagrantfile, Berksfiles.gclientだけコピーして修正すれば異なる開発環境を簡単に作れる
  2. 開発対象のリポジトリをチェックアウトする手順も構成管理されている
  3. 開発対象のリポジトリはまずホストマシンにチェックアウトされているし、各種設定はChefで自動化されている。このためゲストVMが壊れても失われるものはない。ゲストVMは気軽に作りなおせるし、再現できる
  4. 以上を実現するためのVagrantfile, Berksfileおよび.gclient自体もバージョン管理されている

補遺 - gclient

gclientはChromiumプロジェクトが利用しているメタチェックアウトツールで、depot_toolsというツール群の1つである。これを利用するといくつものバージョン管理リポジトリからまとめてソースコードをチェックアウトしてくることができる。
機能としてはAndroidプロジェクトのrepoにも近いが、repoとは異なりgit以外のシステムもサポートしている。

また、gclientにはチェックアウト時に任意のスクリプトを実行するhook機能がある。
これを利用するとチェックアウトされたソースをポストプロセスしたり、未サポートのバージョン管理システムに対応したりもできる。
たとえば、私はgolangのプロジェクトではリポジトリに対してgo generateを掛けたり、gomでgolangプロジェクトをチェックアウトしたりしている。