Chef Solo の Environments

今年3月に入門Chef Soloを書いた時点では、Chef Solo は Environments の機能をサポートしてなかったため解説は省略しました。

その後、Chef はバージョン 11.6.0 (現在は 11.8.2) で Chef Solo での Environments をサポートし、入門Chef Solo で推薦している knife-solo も 10月末にリリースされた 0.4.0 から Environments をサポートしました。というわけで、現状 Chef と knife-solo が最新版であれば Environments を利用することができます。

たまたま今手をつけている仕事で Environments のことを調べたので備忘録的に記しておきます。

Environments とは

Chef の Environments は、例えば development や production など環境ごとに設定内容を切り分ける場合に使える機能です。Rails における RAILS_ENV みたいなものだと思えばだいたい合ってる。実際には環境ごとに設定を切り分けると言っても、できることは Attribute の値を環境によって差し換えることができる、程度。

つまり、Attribute によってうまく環境差を吸収するようなクックブックを構成しておく必要はあります。

Environments の使い方

Environments を使うには、まずノードオブジェクト (nodes/localhost.json とかのあれ) に、値をセットする。

{
  "environment": "development",
  "run_list":[
    "recipe[hello]"
  ]
}

二行目の environment ですね。

次に、environments/ ディレクトリ以下に development.json という名前で、その環境に依存する設定などを書く。

{
  "name": "development",
  "description":"This is it",
  "chef_type": "environment",
  "json_class": "Chef::Environment",
  "default_attributes": {
    "hello": {
      "message": "This is development environment"
    }
  },
  "override_attributes": {}
}

ここでは default_attributesnode['hello]['message'] で参照されるべき属性を指定しました。

デバッグのために、environments で設定した値を出力するレシピを用意。

# site-cookbooks/hello/recipes/default.rb
log node[:hello][:message]

試しにサーバーを converge (クックブックを適用) してみるとどうなるか。

$ bundle exec knife solo cook localhost
Running Chef on sandbox...
Checking Chef version...
Installing Berkshelf cookbooks to 'cookbooks'...
Uploading the kitchen...
Generating solo config...
Running Chef...
Starting Chef Client, version 11.8.2
Compiling Cookbooks...
Converging 1 resources
Recipe: hello::default
  * log[This is development environment] action write

Chef Client finished, 1 resources updated

ごちゃごちゃ出てますが、* log[This is development environment] action write となって確かに先の値が参照できていることがわかります。

development とは別の環境、たとえば production が欲しいとなったら、environments/production.json を用意する。

{
  "name": "production",
  "description":"This is it",
  "chef_type": "environment",
  "json_class": "Chef::Environment",
  "default_attributes": {
    "hello": {
      "message": "This is production environment"
    }
  },
  "override_attributes": {}
}

そしてそれをノードオブジェクトに指定してやれば OK。

{
  "environment": "production",
  "run_list":[
    "recipe[hello]"
  ]
}

で、converge すると

Running Chef on sandbox...
Checking Chef version...
Installing Berkshelf cookbooks to 'cookbooks'...
Uploading the kitchen...
Generating solo config...
Running Chef...
Starting Chef Client, version 11.8.2
Compiling Cookbooks...
Converging 1 resources
Recipe: hello::default
  * log[This is production environment] action write

Chef Client finished, 1 resources updated

確かに production.json 側の値が使われているのがわかります。

なお、knife solo で converge する場合

$ bundle exec knife solo cook localhost -E production

として -E オプションで一時的に環境を切り替えることもできます。

ちなみに Environments の中で指定した default_attributes や override_attributes は、クックブック内の同値やレシピ、あるいは Role よりも高い優先順位で上書きされるので、それら優先度の低い場所で定義した初期値を Environments によって切り替える、ということができます。その辺詳しくは

このドキュメントに載ってます。

cookbook のバージョンロック

ちなみに Environments 内で指定できる値に cookbookcookbook_versions という属性があって

...
  "cookbook_versions": {
    "couchdb": "= 11.0.0"
  },
...

こんな感じで書くと、各環境でのクックブックのバージョンをロックすることができる・・・のですがこの機能は Chef Solo ではなく Chef Server の機能ですね。バージョン、とここでいってるのは Chef Server にクックブックをアップロードしたときに付与されるバージョンのこと。詳しくは Chef + Environments = Safer Infrastructure - Speaker Deck この辺をみると分かるのですが、このバージョンロックの機能を使うとより安全にプロダクション環境のクックブックのアップデートができたりしますよ、ということです。

というわけで、Chef Solo では効果のない機能です、たぶん。

まとめ

  • 最新版の Chef Solo + knife-solo では Environments が使える
  • development, testing, staging, production とかで切り分けたい設定があったら利用を検討すると良い
  • Environments で設定した Attribute は高い優先度を持つ
  • ただし、クックブックのバージョンをロックする機能は Chef Solo では関係ない

というものでした。