前々回、前回でItamaeの基本的な使い方とレシピの書き方を解説しました。今回はノード属性の使い方について解説します。
ノード属性(node attributes)
Itamaeのレシピはできるだけ汎用的にし、様々なホストで利用できる形にするのが理想です。汎用的になっていることで再利用性が高まりますし、プラグインとして公開することもできます。
レシピを汎用的なものにするためには、レシピ自体に設定値などをハードコードせず、ホスト固有の情報などを実行時に注入できる必要があります。このようにレシピやテンプレートから実行時に設定した値を参照できる仕組みとしてノード属性(node attributes)があります。
Itamaeの実行時のオプションに--node-json
を渡すと、JSONの内容がノード属性として設定され、その値がレシピ内から参照できるようになります。
--node-json
でJSONを指定した場合、レシピ内ではnode
を使って参照できます。
このようにJSONでnginxのバージョンを指定できるようにしておくと、ホストやロールごとにバージョンを変更することができ、柔軟にプロビジョニングを行えるようになります。
また、JSONの代わりにYAMLを指定することもできます。
テンプレートからの利用
node
はレシピだけではなくテンプレート内からも参照することができます。テンプレートの使い方については前回の記事を参照してください。設定ファイルを動的に生成する場合に有用です。
このようなレシピを書いておくと、ホストごとにworker_processes
を設定できます。
デフォルト値の指定
このようなレシピをJSONを指定せず実行すると、値が見つからずエラーになってしまいます。値が設定されなかった場合にデフォルト値を利用するように設定することでこれを防げます。
デフォルト値を設定するにはreverse_merge!
メソッドを利用します。reverse_merge!
は値が設定されていない場合のみ値を設定するメソッドです。
このメソッドを利用するとJSONで値が設定された場合にはその値を使って、設定されていない場合はデフォルト値を使うレシピを書けます。
この場合、大部分のホストでは1.9.3-1+trusty0
を利用して、特定のホストやロールでは他のバージョンを利用する、といったことが可能になります。また、reverse_merge!
を使ってロールごとにデフォルト値を変更することもできます。例えば、appサーバとproxyサーバでnginxのプロセス数を変更したい場合、以下のように記述できます。
appロールでは1プロセス、proxyロールではauto(nginxレシピのデフォルト値)が使われ、更に上書きしたい場合は--node-json
や--node-yaml
を指定することができます。
バリデーション
デフォルト値を設定せず、必ず値をJSONから渡す必要があるような場合、バリデーションルールを書いておくと実行前にエラーが発見できます。また、他のレシピからinclude_recipe
されるような場合、そのレシピで必要な値を明示する意味も兼ねることができます。
バリデーションはvalidate!
を呼ぶことで実行できます。例えば、先ほどのnginxの例だと
このように記述すると、node['nginx']['version']
が指定されていて、かつStringになっていることが保証されます。このバリデーションはレシピの実行前に行われるので、実行時のエラーを防ぐことができます。バリデーションルールにはオプショナルな値の指定や、正規表現も指定できます。
例えば、上記のレシピに誤ったノード属性を指定すると、エラーが出力され、レシピの実行が中止されます。
nodeを参照する際の注意点
node
はRubyのHash(厳密にはHashie::Mash)なので、存在しないキーを参照した場合にエラーにならずnil
が返ってきます。例えば、テンプレートで存在しないキーを参照すると
生成される設定ファイルは
このようになります。これを防ぐには、
- デフォルト値を設定する
- バリデーションルールを記述し、実行前に中止する
fetch
を使って値を参照する
といった方法があります。1、2はここまでで紹介したとおりです。3のfetch
を使うと、存在しないキーを参照した時に例外が発生するため、nilが返ってきて設定が空になることが防げます。多少記述が冗長になるのが難点です。
ホスト情報の取得
何も設定しなくても、メモリのサイズやOSの種類などのホスト情報はデフォルトでnode
経由で取得できるようになっています。これを利用すると、例えば、ディストリビューションごとにインストールするパッケージを変更することができます。
また、AWSのEC2インスタンスの場合、EC2特有の値も取得できます。
ホスト情報の取得はSpecinfraのHost Inventory機能を利用しているので、取得できる値の詳細はSpecinfraのドキュメントをご参照ください。
プラグイン
このホスト情報取得機能はプラガブルになっていて、取得項目の拡張が可能になっています。例えば、specinfra-ec2_metadata-tagsを使うと、EC2インスタンスのタグが取得できるようになります。
このようにRoleタグを参照して、読み込むレシピを変更することも可能になります。
コマンドの実行結果を使ってレシピを構築する
レシピを動的に変化させ、汎用的にするもう一つの方法としてrun_command
があります。レシピやテンプレートとrun_command
を呼ぶと、コマンドの実行結果(SSH実行の場合、SSH越しの対象サーバでの結果)が取得できます。
まとめ
今回は設定を外から注入しレシピを汎用的に開発する方法を紹介しました。
次回は汎用的なレシピや独自リソースをプラグインとして公開するための方法をご紹介します。