VagrantとChefSoloを使って、まちクエストの開発環境構築を自動化
はじめまして。@nushu123と申します。
某IT系企業でネットワークエンジニアとしてBGPを触ったり、営業としてクラウドサービスに関わったりしていました。
最近はwebサービス開発に興味があり、@jishihaさんの下でお手伝いをさせていただくことになりました。
まずは、VagrantとChefSoloを使って、まちクエストの開発環境構築の自動化に取り組みました。 今回は、VagrantとChefSoloの主な操作手順と、ハマったポイントについて紹介したいと思います。
1. まちクエスト開発環境構築の自動化のポイント
- コマンド一発で、開発環境deployができる事
- 今までは各自のローカルPCで環境を準備していました。環境に依存するエラーが発生した場合、トラブルシュートに時間を要していました。
- まさにvagrantの出番といったところです
- 開発環境deploy時に、サンプルdataの登録もあわせて実施したい
- 開発メンバー間で共有できる事
- すでにgithubで共有しているrepositoryに対して、VagrantfileとChef関連ファイルを追加する事で対応できます。
実際に開発メンバーに使ってもらい、vagrant up
コマンド一発で無事起動できることが確認できました。
現在、まちクエストのrepositoryにmergeしてもらっています。
2. Vagarnt、ChefSoloって何?
Vagrant(ベイグラント)はVirtualBoxのフロントエンドに相当するツールです。vagrantコマンドなどを使ってコマンドラインから簡単に新しい仮想マシンを削除したり、不要なVMを削除したりできます。
オープンソースとして公開されています。各種ドキュメントは下記で公開されています。
http://www.vagrantup.com/
VagrantはVM作成後のソフトウェア構築の自動化にも対応しており、その場合はshellやChefSolo,Puppet,Ansibleなどのdeploy toolと連携します。今回は、ChefSoloを使用します。Chef自体に興味があったためです。
Chef(シェフ)は Ruby製のサーバ構成管理ツールです。ファイルに記述した設定内容に応じて自動的にユーザーの作成やパッケージのインストール、設定ファイルの編集などを行います。Chefではサーバ・クライアント式のモデルで、クライアント側からサーバ側に情報を問い合わせるPULL型のシステムアーキテクチャとなります。knifeコマンドを使って操作します。大規模構成ならばこれでいいのですが、小規模もしくは1台で試しに触っている人にとっては、サーバの構築は煩わしく感じられ、それがChefの敷居の高さになっていました。
そこで、Chefのスタンドアロン版であるChefSoloの登場です。1台のマシンでChefの動作が完結します。knife soloコマンドを使って操作します。
Chefに関するドキュメントは下記ですが、量が多く挫折するので、今はskipする事にします。慣れてきたら見ることにしましょう。
http://docs.opscode.com/
各ソフトウェアの構成手順をまとめたものがcookbookです。下記サイトでは、様々なcookbookが公開されています。これらのcookbookはマルチOS対応になっているものが多いので、簡単に試す事ができて便利です。ただし、これらのcookbookは動作を保証するものではないので注意が必要です。
Chefに慣れてきたら、cookbookを自作にも挑戦してみましょう。
http://community.opscode.com/cookbooks
3. 環境説明、install
今回はMBAで環境を用意します。
ローカル環境
- MBA(MacOSX10.9、メモリ8GB、HDD250GB)
ソフトウェア
- VirtualBox 4.2.18
下記からDL,installします。
https://www.virtualbox.org/wiki/Downloads - Vagrant 1.3.5
下記からDL,installします。
http://downloads.vagrantup.com/ - Ruby 1.9.3p327
rbenvを使用 - Bundler 1.3.5
ローカルMBAのCLIより、下記コマンドを実施$ gem install bundler
- VirtualBox 4.2.18
Vargrant plugin
4. Vagrant実行方法
ここでは簡単なVagrantの使い方について説明します。
適当なディレクトリを作成し、移動
$ mkdir vagrant-test
$ cd vagrant-test
仮想マシンのイメージとして、precise64(Ubuntu12.04 64bit版)を指定し、初期化を実施。Vagrantfileが作成される。
$ vagrant init precise64 http://files.vagrantup.com/precise64.box
作成したVagrantfileをもとに、仮想マシンを作成、起動
$ vagrant up
$ vagrant ssh
仮想マシンを停止
$ vagrant halt
仮想マシンを削除
$ vagrant destroy
5. Vagrant+ChefSolo実行方法
上記の手順で、仮想マシンの作成とsshアクセスまで確認できたと思います。 しかし、これだと単純に仮想マシンを起動しただけなので、VirtualBoxを使っているのと変わりません。 いよいよVagrantの真価発揮です。
今回は、下記対応手順について説明します。 * rubyバージョン管理システム(rvm)をinstallし、ruby-1.9.3-p448とbundlerをinstall。 公開されているcookbookを使用 * MySQLとapacheをinstall。 こちらは、chefのpackageリソースを使って、apt-getでinstallします。
一般的にはまずは公開されているcookbookを使ってchefに慣れた後、自分でcookbookを作成する事が多いようです。 公開されているcookbookはマルチOS対応で便利な反面、オーバーヘッドが多いので、自分が必要とするものだけを記述して見通しをよくした方が良さそうです。
4で作成してディレクトリで、bunle initでGemfileを生成。その後、Gemfileを編集。今回は、berkshelfとknife-soloを追加します。(bundle initはGemfileを生成するだけなので、いきなりvi Gemfileとしても問題ないはず)
どちらも現時点の最新版がinstallされます。(berkshelf 2.0.10とknife-solo 0.4.0)
chefではknifeコマンドを使って操作するのですが、chef soloではknifeコマンドのサブコマンドのknife soloコマンドを使います。
次のbundle installで、knifeとknife soloコマンドがinstallされます。
$ bundle init
$ vi Gemfile
source "https://rubygems.org"
gem "berkshelf"
gem "knife-solo"
bundle installを実行
$ bundle install --path vendor/bundle
berks initを実行し、Berksfileを生成。GemfileとVagrantfileのOverwriteするか聞かれますが、nでskipします。
$ bundle exec berks init
create Berksfile
create Thorfile
create .gitignore
run git init from "."
conflict Gemfile
Overwrite xxx/vagrant-test/Gemfile? (enter "h" for help) [Ynaqdh] n
skip Gemfile
conflict Vagrantfile
Overwrite xxx/vagrant-test/Vagrantfile? (enter "h" for help) [Ynaqdh] n
skip Vagrantfile
Successfully initialized
今回は使用しないので、Thorfileを削除します。って今回Thor始めて知りました。 あと、.gitignoreのGemfile.lock行を消しておきます。この辺りは好みの問題かもしれませんが。。。
$ rm Thorfile
$ vi .gitignore
- snip -
Gemfile.lock # この行を削除
- snip -
Berkfileを編集し、サードパーティのrvm cookbookを定義
$ vi Berksfile
site :opscode
cookbook 'apt'
cookbook 'rvm', github: 'fnichol/chef-rvm'
knife soloコマンドでchef用にディレクトリを初期化。cook-books、rolesディレクトリ等が作成されます。
$ bundle exec knife solo init .
$ tree -L 2
.
├── Berksfile
├── Gemfile
├── Gemfile.lock
├── Vagrantfile
├── cookbooks
├── data_bags
├── environments
├── nodes
├── roles
├── site-cookbooks
└── vendor
└── bundle
8 directories, 4 files
サードパーティのcookbookをinstall
$ bundle exec berks install --path cookbooks
自分のcookbookを作成して、recipeを作成。
$ bundle exec knife cookbook create myapp -o site-cookbooks/
$ vi site-cookbooks/myapp/recipes/default.rb
%w{apache2 mysql-server}.each do |each|
package "#{each}" do
action :install
end
end
service "apache2" do
action[ :enable, :start]
supports :status => true, :restart => true, :reload => true
end
service "mysql" do
action[ :enable, :start]
supports :status => true, :restart => true, :reload => true
end
Berksfileに自分のcookbookを追加
$ vi Berksfile
site :opscode
cookbook 'apt'
cookbook 'rvm', github: 'fnichol/chef-rvm'
cookbook 'myapp', path: './site-cookbooks/myapp' # この行を追加
Vagrantfileのprovisionに作成したrecipeを記載 あわせて、config.vm.network行を追加しておきます。(後でapacheの動作確認で使います)
$ vi Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
config.vm.network :forwarded_port, guest: 80, host: 8080
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["./cookbooks", "./site-cookbooks"]
chef.add_recipe "rvm::system"
chef.add_recipe "rvm::vagrant"
chef.add_recipe "myapp" # myapp::default を省略した記載方法
chef.json = {
"rvm" => {
"default_ruby" => "ruby-1.9.3-p448",
"global_gems" => [
{"name" => "bundler"}
]
}
}
end
end
それでは、このVagrantfileのprovisionを実際に反映させましょう。下記コマンドで、Vagrnatfileの上述のprovision部分を読み込みます。
$ vagrant provision
もしくは、下記のように、step4で作成した仮想マシンを一旦削除し、あらためて仮想マシンを作成してもいいです。
vagrant1.3.0以降では、最初のvagrant up
実行時にprovision部分の読み込みを実行します。(詳細は後述)
$ vagrant destroy
$ vagrant up
$ vagrant ssh
仮想マシン上のrubyのバージョンを確認し、ruby-1.9.3-p448になっている事を確認します。
$ ruby -v
ruby 1.9.3p448 (2013-06-27 revision 41675) [x86_64-linux]
MySQLアクセスにもアクセスしてみましょう。
$ service mysql status
$ mysql -uroot
apacheが起動している事を確認しましょう。
$ service apache2 status
ローカルPCのブラウザからアクセスできることを確認
http://localhost:8080
6. ハマりポイント
- 自分で作成したcookbook使用時、BerksfileとVagarantfileの書き方
Berksfileでpath:を記載するのがポイントです。
$ vi Berksfile
-snip-
cookbook 'myapp', path: './site-cookbooks/myapp'
$ vi Vagrantfile
-snip-
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["./cookbooks", "./site-cookbooks"]
-snip-
chef.add_recipe "myapp"
-snip-
end
- rvm cookbook使用時、BerksfileとVagarantfileの書き方
コメント部分がポイントです。
$ vi Berksfile
site :opscode
cookbook 'apt' # この行を忘れずに
cookbook 'rvm', github: 'fnichol/chef-rvm'
- snip -
$ vi Vagrantfile
- snip -
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["./cookbooks", "./site-cookbooks"]
- snip -
chef.add_recipe "rvm::system"
chef.add_recipe "rvm::vagrant" # この行を忘れずに
- snip -
chef.json = {
"rvm" => {
"default_ruby" => "ruby-1.9.3-p448",
"global_gems" => [
{"name" => "bundler"}
]
}
}
end
特にBerksfileでcookbook 'apt'
を記載しなかった場合、下記エラーが発生しました。
- snip -
[2013-11-04T08:25:53+00:00] INFO: execute[install system-wide RVM] ran successfully
================================================================================
Error executing action `install` on resource 'package[libxml2-dev]'
================================================================================
Chef::Exceptions::Exec
----------------------
apt-get -q -y install libxml2-dev=2.7.8.dfsg-5.1ubuntu4.1 returned 100, expected 0
- snip -
- 初めて
vagrant up
実行の注意ポイント
下記errorが発生します。
FATAL: ArgumentError: You must specify at least one cookbook repo path
その場合下記コマンドを実施すると正常起動しました。
vagrant reload
vagrant provision
これは~/.berkshelf
が存在しない場合、vagrant up
実施時に発生する事象です。
berkshelf3.0で修正済と記載がありますが、berkshelf3.0.0.beta2で試したところ、依然NGでした。
https://github.com/RiotGames/vagrant-berkshelf/issues/78
MacOSで、synced_folder(nfs有効)で起動失敗する場合、/etc/exports
を削除後、touchコマンドで/etc/exports
を再作成し、nfsd停止、起動をするとsynced_folderが正常起動します。
http://www.1x1.jp/blog/2013/08/vagrant_synced_folder_with_nfs.html
nfsを使ったほうがdiskアクセスの性能が良いです。(但し、nfs機能はMacOSのみサポート) http://docs.vagrantup.com/v2/synced-folders/nfs.html
また、vagrant up
実行途中でnfs mountのpwを聞かれたら、ローカルPCのrootのPWを入力してください。
もしrootユーザを設定していない場合は、下記を参考にrootを有効にして下さい。
http://support.apple.com/kb/ht1528?viewlocale=ja_JP&locale=ja_JP
- Vagrant 1.3.0から
vagrant up
動作変更
vagrant upコマンドでVagrantfileのprovision部分が実行されるのは最初の1回目だけです。
(vagrant halt
実行後)2回目以降の仮想マシンの起動でprovision部分を実行したい場合、下記コマンドを実行する必要があります。
(ChefSoloを使っている場合、Chefの冪等性の動作のため、基本的に毎回provision部分を実行する必要性はないはずですが、まちクエストは事情により、毎回provisionで特定のrecipeを実行する必要性があるのです)
$ vagrant up --provision
https://github.com/mitchellh/vagrant/blob/master/CHANGELOG.md
- bundler 1.4.0.pre.1以降、bundle installの並列処理ができるようになっています
Bundlerで並列処理??bundle installを爆速で処理する方法。
今回のまちクエストの開発環境構築では、あまり効果がなかったのとpreということもあり、利用は見合わせました。
ただし、bundle installの時間短縮をしたい場合も出てくると思うので、覚えておくといいです。
7. サンプル
上記で説明したファイルをgithubに保存しますのでご参照下さい。
Github Vagrant-test
8. まとめ
- まちクエストの開発環境Vagrant化の経験をもとに、Vagrant+ChefSoloの主な操作方法およびハマりポイントについて説明しました。
- 今回説明で用いたソフトウェアおよびバージョンは、実際のまちクエストで使用しているソフトウェア、バージョンとは異なる部分があります。ご了承ください。
- 今後の課題
- 今回まちクエストのアプリケーション部分の自動化については、chefのbashリソースを用いて、shellスクリプトを実行しています。
最近になって、chefのdeploy resourceを知ったのですが、本当はdeploy resourceを使って自動化した方がよさげです。
また、まちクエストではcapistranoを使って管理しているので、deploy resourceとの親和性もよさそうです。
http://docs.opscode.com/resource_deploy.html
- 今回まちクエストのアプリケーション部分の自動化については、chefのbashリソースを用いて、shellスクリプトを実行しています。
9. 参考情報
今っぽい Vagrant + Chef Solo チュートリアル
Berkshelfベースにvagrant, chef(knife-solo)環境を簡単に構築する方法
dotinstall Vagrant入門
入門Chef Solo - Infrastructure as Code
dotinstall Chef入門
RubyistMagazineChef でサーバ管理を楽チンにしよう! (第 1 回)