【Chef Solo】attributeはどう使い分けるべきか。

92件のシェア(ちょっぴり話題の記事)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、せーのです。
Chef SoloやKnife SoloにChef Server同様environmentがサポートされてから、レシピの書き方が一気に広がりました。
広がった結果、Attributeをどこに書いていいのか迷う人も多いのではないでしょうか。私は迷います。
Chefは結構ゆるーい感じなので、特に「こういう場合にはここに書きなさい」という決まりがあまりありません。
この「決まりがない」というのがクセモノで、ついついAttributeをバラバラに書いてしまい、Cookbookが会社の共有資産になった時に余計な値が埋め込まれる、という事例が多発したりしないでしょうか。私はします。

Attributeには順位があり、より上位の場所にAttributeを書くと下位の値が上書きされます。まずこの順番を体感で覚えておくことが重要です。
Attributeの順位はドキュメントに書いてあります。

英語ですね。ややこしいですね。ざっくり解説します。

Attributeが書けるファイル

Attributeが書けるファイルはAttributeファイル、recipeファイル、Environmentファイル、Roleファイルの4つとchef client起動時にOhaiが自動設定するAutomatic Attributeです。
上書きされる順番は弱い順にAttribute→recipe→Environment→Roleになります。
ただし、これが一部入れ替わったりします。ですが、感覚的にはこれで覚えてしまって問題ないかと思います。
そしてAutomatic Attributeは親玉です。ジョーカーです。最強です。誰も勝てません。

Attributeの強さ

Attributeの強さは弱い順にdefault→force_default→normal→override→force_override→automaticと分かれています。
これと上のファイルを組み合わせる、というのが基本です。 つまりAttributeファイルに書いたdefaultのattributeはEnvironmentファイルに同名のdefault attributeを書いた場合上書きされ、それはさらにrecipeファイルに書いたforce_defaultのattributeで上書きされる、、、といった具合です。

そうなると5種類のファイル × 6種類の強さで30パターンあるように見えますが、attributeのパターンは全部で15種類になります。つまり、組み合わせによって書けないパターンもあるのです。

組み合わせ方と上書き順

それを踏まえたattributeの組み合わせ方と上書きの順番はこのようになります。
attrtest2

四角で囲った部分が間違いやすいポイントです。roleやenvironmentにはforce_default attributeは書けないということ、override attributeの上書き順が何故か変わっていることに注意してください。

では、軽く実践してみましょう。

軽く検証

今回は簡単にApacheを入れてWebルートに当たる/var/www/html/index.htmlを作ります。そのbody部分を上書きしてみます。
サーバーはVirtualBoxでもVMWareでも何でも良いのですが、AWSコンサルティングらしくEC2を使ってみたいと思います。

まずcookbookを作ります。今回は[attrtest]という名前にします(chef soloとknife soloを使います。予めインストールしてください)。

knife solo init chef-repo
cd chef-repo/
knife cookbook create attrtest -o site-cookbooks

次にrecipeです。

#yumのfastestmirrorとアップデートをする。
yum_package "yum-fastestmirror" do
	action :install
end

execute "yum-update" do
	user "root"
	command "yum -y update"
	action :run
end

#apacheを入れる
package "httpd" do
	action :install
end 

#apacheの起動
service "httpd" do
	action [:start, :enable]
end 

#ルートindex.htmlの記述
template "/var/www/html/index.html" do
	source "index.html.erb"
	mode 0644
	variables(
		:message=>node['attrfrom']['message']
	)
end

この['attrfrom']['message']にattributeの変数を埋めていきます。

次に表示部分であるindex.htmlのテンプレート、index.html.erbを書いていきます。

<!DOCTYPE html>
<html>
	<head>
		<title>Attribute overrides test</title>
	</head>

	<body>
		This Attribute message from <%= @message %>.
	</body>
</html>

最下位であるAttributeファイルにdefaultでattributeを書いてみます。

default['attrfrom']['message']="attribute file"

それではサーバーにchefを入れてレシピを流してみましょう。
EC2の場合はssh接続とほぼ変わらない形でknifeコマンドが流せます。

knife solo prepare ec2-user@XXX.XXX.XXX.XXX -i [EC2のkey pair(パーミッションを600にする)]
knife solo cook ec2-user@XXX.XXX.XXX.XXX -i [EC2のkey pair(パーミッションを600にする)]

すると最後の方にテンプレートの結果が出ますのでそれで確認できます。

* template[/var/www/html/index.html] action create
    - create new file /var/www/html/index.html
    - update content in file /var/www/html/index.html from none to 0fd886
        --- /var/www/html/index.html	2014-06-05 06:42:36.733322208 +0000
        +++ /tmp/chef-rendered-template20140605-21177-y1k9x9	2014-06-05 06:42:36.745322116 +0000
        @@ -1 +1,11 @@
        +
        +
        +
        +		
        +	
        +
        +
        +		This Attribute message from attribute file.
        +	
        +
    - change mode from '' to '0644'

一応ブラウザで確認しても同じ内容が書かれています。
attrtest1

ちなみに同じattributeを同じ場所に書くと、下に書いた方で上書きされます。
site-cookbooks/attrtest/attributes/default.rb

default['attrfrom']['message']="attribute file"
default['attrfrom']['message']="attribute file below"
* template[/var/www/html/index.html] action create
    - update content in file /var/www/html/index.html from 0fd886 to 629c4c
        --- /var/www/html/index.html    2014-06-05 06:42:36.745322116 +0000
        +++ /tmp/chef-rendered-template20140605-25243-ibn15w    2014-06-05 07:00:03.130583375 +0000
        @@ -5,7 +5,7 @@
        -       This Attribute message from attribute file.
        +       This Attribute message from attribute file below.
            
         

次にこれをenvironmentで上書きしてみます。
/environments/attr.json

{
	"name": "attr",
	"description": "attribute overrides test",
	"chef_type": "environment",
	"json_class": "Chef::Environment",
	"default_attributes": {
		"attrfrom": {
			"message":"environment file"
		}
	}
}
* template[/var/www/html/index.html] action create
    - update content in file /var/www/html/index.html from 0fd886 to d93bbd
        --- /var/www/html/index.html    2014-06-05 07:07:48.069424054 +0000
        +++ /tmp/chef-rendered-template20140605-27484-3kd2py    2014-06-05 07:12:04.317591645 +0000
        @@ -5,7 +5,7 @@
        -       This Attribute message from attribute file.
        +       This Attribute message from environment file.
            
         

まとめ

こんな感じで上書きされることを理解すれば、あとはどこに何を書くか、をルール化してしまうのが楽です。
ちなみに私は

Attributeファイル=>文言変更
recipeファイル=>テスト的に変えたいものがある時のみ。本番では消す。
Environmentファイル=>development(開発),alpha(実験用)、staging(テスト)、production(本番)でのIPやOSバージョンの違い。同じ構成が複数台ある時もここで区別。
Role=>ミドルウェアのバージョン違い

でdefaultとoverrideのみ使います。

参考にしてみてください。