Knife Sousを使って複数サーバーでChef Solo

複数サーバーでChef Soloを使うのにCapistranoとchef-soloを組み合わせてやっていたけど、最近モダンなやり方を勉強しようと思っていろいろ調べていたら、Knifeのプラグインとして動くKnife Sousなるものを見つけた。

少し触ってみただけだけど、まあいいかんじ。

Knife Sous

RakeライクなDSLで環境ごとのネームスペースを設けてノードを管理できる、と言うのがKnife Sousの特徴。
加えて特定のネームスペースに属する複数ホストへのknife soloを一気に実行できる。

設定ファイルを書いた上で以下のように使う。

$ knife sous bootstrap production
$ knife sous bootstrap production web1 # 一つだけ実行も可能
$ knife sous prepare vagrant
$ knife sous cook vagrant

同じ作者によるsous-chefというものもあるが、Knife Sousはknifeのプラグインとして作り直された物で、開発が継続しているのはKnife Sousの方。

ちなみにchef-sousで副シェフって意味らしい。

導入

gemコマンドかGemfileに書くかで適宜インストール。何を悩むというのです。

$ gem install knife_sous

設定

$ knife solo init chef-repo

で作られたchef-repoの中にいるという前提。

nodes/nodes.rbを作成して編集する。
これは例えば以下のような内容になる。

namespace :production do |production|
  production.node :web1,
  node_config: 'nodes/web.json',
  hostname: '192.168.0.101',
  user: 'root'
end

node :vagrant, node_config:'nodes/some_node.json'

以下のコマンドでサンプルの設定ファイルができるので、それを元に編集するのもいい。

$ knife sous init .

動的にnodeを定義

nodes.rbには当然のようにRubyのコードを書ける。
つまり動的にnodeを定義することが可能。

namespace :production do |production|
  {web1: '192.168.0.101', web2: '192.168.0.102'}.each do |host, ip|
    production.node host,
    node_config: 'nodes/web.json',
    hostname: ip,
    user: 'root'
  end
end
  
node :vagrant, node_config:'nodes/some_node.json'

nodes.rbをDRYにできるので良い。というかできないと辛い。
工夫次第でCapistranoでroleを使ってやっているようなことも可能だろう。

なお動的に書いた場合にはnamespaceの入れ子がうまくいかないぽい。

xargsを使って並列実行

複数サーバーがある場合、knife sousは直列実行されるので遅い。
並列実行したい場合はパイプを使う。

$ knife sous list|grep production|xargs -L 1 -P 2 knife sous cook

泥臭いけどハヤイ。

knife sousのオプションで並列度が指定できたりすると美しいかもしれない。

対案の+Capistranoと比べて

今はCapistrano+chef-soloの統合されたソリューションとしてroundsmanというものがあり、Capistranoと組み合わせるならオレオレで書くよりこれを使うとよいかもしれない。

しかし補助としてCapistranoを使うよりも、Knife Sousの方が純正ツールのプラグインとして、より統合された形になるので取っつきやすく、管理もしやすい。

というわけでKnife Sousの方がいいんじゃないかなー。