capistrano + chef-soloで構成管理する
問題
VMをぽこぽこ作りながらあれこれツールを入れて試してみたりしたいという時に、chefを使って構成管理はしたいけど、chef-serverを入れるのは面倒、というか、構成パッケージの記述・インストールだけできればいいという要求からするとオーバスペックなように感じるのだし、また、ホストの管理にはcapistranoを使っているので、cap実行側のみで処理が完結する方がよいという場合もあろうかと思う。
前提
- デプロイ先ホストには、公開鍵認証でログインできるものとする(capを使うので)
- デプロイ先ホストでは、既にgit, chef-soloが使える状態であるものとする(そこまではなんらかの方法でがんばる)
解決案
そこで、chef-soloという、chef-serverなし、スタンドアロンにレシピの実行を行うコマンドをcapで実行するようにしてみる方法を試してみた。例として、GrowthForecastを動かすホストの構成管理を取り上げる。ディレクトリ構成は以下の通り。
├── .carton ├── .git ├── .gitignore ├── .gitmodules ├── Capfile ├── Makefile.PL ├── carton.lock ├── config │ ├── chef.json │ ├── deploy.rb │ └── supervisor.ini ├── local └── modules ├── GrowthForecast └── chef-repo
chef-repoを作成、submoduleにする
今回はGrowthForecastに必要なパッケージ(Alien::RRDtoolを入れるのに必要なパッケージ)のみですが、それに限らず、共通に使いまわせるレシピをあれこれと書いていきます。とりあえず、以下のようなrole構成にしました(リストの階層が継承関係を示す)。
- role[base]: 大元のrole
- role[supervisor]: supervisor使う用
- role[perlbrew] (opscodeで共有されているものに手を入れたもの): Perlのプロダクトを動かす用
- role[growthforecast]: GrowthForecastに特化したrole。今回はこれを使う。
chef-soloの実行
chef-soloを実行するタスクは以下の通り。
namespace :chef do task :solo do sudo <<-"EOS", :pty => true chef-solo -c #{deploy_to}/current/modules/chef-repo/config/solo.rb -j #{deploy_to}/current/config/chef.json EOS end end
また、上記コード内のconfig/chef.jsonは以下の通り。
{ "run_list": [ "role[growthforecast]" ] }
chef-soloの設定ファイルは、chef-soloリポジトリ内にconfig/solo.rbとして置かれている。
require 'pathname' basedir = Pathname.new(__FILE__).realpath.dirname.parent file_cache_path "/tmp/chef-repo" cookbook_path (basedir + "cookbooks").to_s role_path (basedir + "roles").to_s
- config/chef.jsonにrun_listを、
- modules/chef-solo/config/solo.rbにchef-soloの設定を書くようにする
というふたつのルールを導入することで、capのタスクを一般的に使えるようにしている。同様のディレクトリ構成を取ることで、他のプロダクトについても
$ cap chef:solo
と実行することで、config/chef.jsonに書かれた、個々のアプリケーションの構成に必要なroleでもって、かつ、chef-reposに蓄積された共通のレシピを利用して、構成管理を行える。
問題点
- submoduleにしている関係上、全てのホストにchef-repos一式が存在することになって、冗長な感じがする。
- capを叩かないと構成変更を更新することができない(自動的に更新したりしない)
- 実行速度が遅かったりする?
冗長であるとはいえ、複雑なchef-serverを介することなくcap + gitrepositoryだけで管理できるのは、気軽でよい感じがする。
その他
chefには直接関係ないが、以下のようなことも行っている
- GrowthForecastを直接使うのではなく、そのGitリポジトリをsubmoduleにする。
- Perlモジュールの管理はcartonで行うことにする。モジュールの増減は、システム側というよりはアプリの都合でころころ変わることになるだろうので、chefでやるよりcartonだとか、rubyでいえばbundlerだとかでやる方がいい感じがする。
carton:install
というタスクを用意した
- growthforecastの起動にはsupervisorを用いている。
supervisor:(start|stop|restart)
などといったタスクを用意した