詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Fork me on GitHub

Vagrant を使って複数の環境で Go のプログラムをコンパイルする(ファイルの変更監視つき)

書くコードがさまざまな OS で動くことを初めから想定しているような場合には、実際にその環境で動かしてみたい。タイトルのとおり Vagrant仮想マシンを複数立ち上げて、それぞれの中でコンパイルおよびテストができればよいわけです。というので書いてみたのがこちら:

https://github.com/motemen/go-multi-vagrant

とはいえ別に golang に限った何かがあるというわけではないです。

*file というファイル名が並んでいてかっこいいのですが、それぞれ以下のような役割を果たしています。

  • Rakefile: Vagrant セットアップを含めた作業フロー
  • Makefile: プログラムのビルド
  • Berksfile: 仮想マシンに適用する chef レシピ
  • Gemfile: ゲム〜

rake

% rake -T
rake init                               # Initialize required tools (required once, a bit slow)
rake setup                              # Setup required libraries
rake vagrant:make[machine,target]       # Run make on virtual machines
rake vagrant:make_fast[machine,target]  # Run make without starting up machines
rake vagrant:up[machine]                # Start virtual machines
rake vagrant:watch[machine,target]      # Watch local files to invoke make on virtual machines

rakerake default)を実行すると

  1. 必要なプラグインおよびライブラリのインストールがおこなわれ(rake init, rake setup
  2. 仮想マシンが起動し(rake vagrant:up
  3. それぞれの仮想マシンの中で make が実行される結果、テストとビルドが走ります(rake vagrant:make)。

make

  • vagrant ssh して各マシンで make を実行してます。GOPATH の設定のために sh -l してるのがポイントというくらいです。
  • 仮想マシンを扱う rake タスクでは MACHINE 環境変数を設定することで特定のマシンのみを対象とすることができます。
  • rake からは TARGET 環境変数で make のタスクを指定できます。
  • vagrant:make は毎回仮想マシンの起動をしようとするため少し遅くなっていますが、一度起動してしまったあとは vagrant:make_fast を使うようにすると起動処理をすっ飛ばすようになり、こちらのほうが早いです。
% rake vagrant:make MACHINE='precise64 centos-6.5'
bundle install --quiet
bundle exec berks install --path=.vendor/cookbooks
Installing golang (1.3.0) from git: 'git://github.com/NOX73/chef-golang.git' with branch: 'master' at ref: 'b062a3226a2ca1a14f0e62187a6ea870281988fc'
Using build-essential (1.4.2)
vagrant up precise64
Bringing machine 'precise64' up with 'virtualbox' provider...
==> precise64: Checking if box 'hashicorp/precise64' is up to date...
==> precise64: VirtualBox VM is already running.
vagrant up centos-6.5
Bringing machine 'centos-6.5' up with 'virtualbox' provider...
==> centos-6.5: Checking if box 'chef/centos-6.5' is up to date...
==> centos-6.5: VirtualBox VM is already running.
---> Running on precise64
vagrant ssh precise64 -- $SHELL -l -c 'cd /vagrant && make  2>&1 | sed "s/^/[precise64] /"'
---> Running on centos-6.5
vagrant ssh centos-6.5 -- $SHELL -l -c 'cd /vagrant && make  2>&1 | sed "s/^/[centos-6.5] /"'
[precise64] go get -d ./...
[precise64] go test ./...
[precise64] ok          _/vagrant       0.014s
[precise64] go build -o build/main.precise64.vagrant.dominica.local ./...
[centos-6.5] go get -d ./...
[centos-6.5] go test ./...
[centos-6.5] ok         _/vagrant       0.002s
[centos-6.5] go build -o build/main.centos-6.5.vagrant.dominica.local ./...

ファイル監視

ここまで整えるとファイルの変更を監視してビルドを行いたくなるものですが、Vagrant のファイル共有はゲスト側で変更イベントを発生させないらしい。最近のだと rsync ってのもあるけど明示的に実行しないと同期されないので思わぬところでハマりそうなのと仮想マシンそれぞれに変更監視ツールを入れるのも面倒だ……というわけでホスト側で変更を監視し、ゲストはそれを受けて make するだけ、という風にしてみました。

vagrant:watch とすると手元でファイルの変更が監視され、変更された時にそれぞれのマシンで make が走ります。仕組みは見たら分かりますが、標準入出力でイベントを伝えるというシンプルな実装です。

% rake vagrant:watch
---> Listening to changes on precise64
---> Listening to changes on precise32
---> Listening to changes on centos-6.5
---> Files changed: main.go
[centos-6.5] make 
[precise64] make 
[precise32] make 
[precise64] go get -d ./...
[precise64] go test ./...
[precise64] ok          _/vagrant       0.006s
[precise64] go build -o build/main.precise64.vagrant.dominica.local ./...
[precise32] go get -d ./...
[precise32] go test ./...
[precise32] ok          _/vagrant       0.002s
[precise32] go build -o build/main.precise32.vagrant.dominica.local ./...
[centos-6.5] go get -d ./...
[centos-6.5] go test ./...
[centos-6.5] ok         _/vagrant       0.003s
[centos-6.5] go build -o build/main.centos-6.5.vagrant.dominica.local ./...

はてなで一緒に働きませんか?