chef-soloで環境設定

chefはサーバ構成管理ツールです。構成を設定ファイルとして書き残しておき、 chefを実行すればそのとおりにサーバを構築してくれます。また、何度実行し ても同じように構築してくれますし、サーバ構成をいじったとしても修正して くれます。

というわけで、chefを使ってみたのでそのメモ。

事前準備

chefはrubyで作られていますので、rubyが必要です。また、chef自体のインス トールにはgemが楽ちんです。

% gem install chef

chefにはサーバなどがありますが、今回は単独で実行できる chef-solo のみ を使います。

雛形作成

後述するcookbookなどの雛形を作ってくれるRakefileがopscodeのサイトにあ ります。

githubのopscodeから取ってきます。

% git clone git://github.com/opscode/chef-repo.git

この構成をそのまま使うのが吉です。また、ここにあるRakefileを使うことで、 cookbookの雛形作成も楽に出来ます。

cookbook

cookbookとはRecipeなどの設定ファイルをひとまとめにしたディレクトリ。そ の中身はcookbookは以下のディレクトリで構成されます。

  • attributes

  • definitions

  • files

  • metadata.rb

  • providers

  • recipes

  • resources

  • templates

これらは上記Rakefileを使えば、

% rake new_cookbook COOKBOOK=test

と打つだけで雛形を作ってくれます。

recipe

レシピです。このレシピに書いてあるとおりにサーバが設定されます。

例えば、ディレクトリを作ってリンクを張る、という設定はこんな感じです。

directory "/tmp/tmpdir" do
  mode "0755"
  action :create
end

link "/tmp/link" do
  to "/tmp/tmpdir"
end

ここで、"directory"と"link"をResourceと呼びます。Resourceは順番に意味が ありますので、directory -> link の順番で呼ばれます。

Resourceにはいろいろあって、例えば、remote-fileというResourceはsourceで 指定した、cookbook/files以下にあるファイルを指定の場所にコピーします。 ディレクトリまるごとの場合はremote-directoryを使います。

 remote_directory "/tmp/dir" do
   source "tmpdir"
   owner "apache"
   group "apache"
   mode "0755"
end

また、templateというresourceを使うと、cookbook/template以下にある、erb で書いたテンプレートファイルに値を埋めてファイルを作成してくれます。

詳しくは Resourceの説明 を見てください。

これらのResourceは「何度繰り返しても同じ結果になります」大事です。英語 で言うと、idempotentです。冪等性(べきとうせい)とも言います。

shell scriptでmkdir hogeと二回打つと、二回目は「File exists」というエラー になりますよね?(-p使えという話もありますが)しかし、chefを使った場合で はエラーになりません。これはchefが自動的に判断して実行しないからです。

また、templateであれば、もし手動でなにかを書き換えていた場合にはその変 更は書き潰されますし、ownerを変更した場合はchefのレシピ通りに戻されます。

script Resource

script Resourceはbash、ruby、Pythonなどのスクリプトを実行出来ます。強力 な反面、idempotentではなくなる場合もあるため、使用には注意が必要です。 できるだけ使わない方がいいでしょう。

とはいえ、make installが必要な場合等はあるんですけどね。

Action

httpd.confを書き換えたらhttpdをreloadする、などのように、「この Resourceを実行したらこのResourceを実行する」などはnotifiesを使います。

このあたりは Rubyマガジン Chef でサーバ管理を楽チンにしよう! (第 2回) を参考にしてみて ください。

chef-soloの実行

最低限CookbookとRecipeがあればchef-soloは実行できます。以下の二つのファ イルを作成しましょう。defaultではsolo.rbは /etc/chef/solo.rb を見に行く ようです。

chef.json

chef-soloを実行するターゲットの設定ファイル

solo.rb

cookbookのパスなどを設定

{
  "run_list": [
    "recipe[test]",
    "recipe[test::test2]"
 ]
}

run_list内のrecipeは複数書けます。ここで[test::test2]とあるのは、

test/
    recipes/
            default.rb
            test2.rb

のtest2.rbを実行しますということです。solo.rbはこう書きます。

file_cache_path "/tmp/chef-solo"
cookbook_path ["/path/to/cookbooks", "/path/to/cookbooks2"]
role_path "/path/to/roles"
log_level :debug

主にパス設定ですね。cookbook_pathは複数設定出来ます。role_pathは複数設 定出来ません。

さて、この二つのファイルを用意しておけばあとは以下のコマンドを打つだけです。

% sudo chef-solo -c /path/to/solo.rb -j /path/to/chef.json

log_levelをdebugにしているのでかなり多くの情報がずらずらーっと出てくる と思います。

attributes

ここまでで一通りできるのですが、もう一つattributesを覚えておくと今後便利です。

attributesとは、recipeやテンプレートで使える変数を外出ししたものです。

例えば、 cookbook/attributes/default.rb にこう書きます。

default["apache"]["version"] = "2.2.22"
default["apache"]["conf_dir"] = "/usr/local/apache/conf/"

こう書いておくと、Recipeでたとえばこう書けます。

template "#{node.apache.conf_dir}/httpd.conf" do
  source "httpd.conf"
  owner "apache"
  group "apache"
  mode "0644"
end

また、テンプレートの中で

ServerRoot "/usr/local/apache-<%= node.apache.version %>"

と書けます。

このattributesはjsonの中で上書きできます。

"override_attributes": {
      "apache": {"version": "2.4.2", "conf_dir": "/etc/apache/conf/"}
},

このように変数をレシピの外に出しておくことで、レシピを変えることなく環 境に合わせた設定ができます。

definitions

definitionは自分で新しいResourceを作れる仕組みです。definitionを使うことで、 何度も同じResourceを定義する必要がなくなります。

definitionは cookbook/definitionsの下に、例えば postgresql_func.rb とい う名前で作ります。

define :postgresql_func, :action => :create, :owner => "postgres" do
  # 名前がpostgresql_func、デフォルトの設定が残り
  contrib = node.postgresql.contrib_dir
  # node.postgresql.contrib_dirはattributesで設定

  case params[:action]
  when :create
      execute "psql -1 -f #{contrib}/#{params[:mod]}.sql  #{params[:name]}" do
        # params[:name] はpostgres_funcの引数
        user "postgres"
        not_if "psql -At1 -c \"SELECT prosrc FROM pg_proc \" #{params[:name]} | grep '#{params[:func]}'", :user => "postgres"
    end

  when :drop
    execute "psql -1 -f #{contrib}/uninstall_#{params[:mod]}.sql
    #{params[:name]}" do
      user "postgres"
      not_if "psql -At1 -c \"SELECT prosrc FROM pg_proc \" #{params[:name]} | grep '#{params[:func]}'", :user => "postgres"
    end
  end
end

こうしておけば、あとはrecipeの中でこう使えます。

postgresql_func "template1" do
  mod "dblink"
  func "dblink_connect"
end

postgresql_funcの引数(ここでは"template1")が params[:name] として渡さ れます。

なお、definition自体はその中で包含するResourceで置き換えられます。つま り、実際にはdefinitionというResourceは作られません。そのため、 definitionに対してActionを送ることは出来ません。もしResourceに対して Actionを送りたければ Provider を使うとのことです。

role

roleはattributeの設定やrun_listの設定をまとめたものです。使うには以下の ように solo.rb にrole_pathを加えておきます。(cookbook_pathとは違い、複 数指定できません)

file_cache_path "/var/chef-solo"
cookbook_path "/var/chef-solo/cookbooks"
role_path "/var/chef-solo/roles"

で、実際のroleはこんな感じ。

/var/chef-solo/roles/test.json

{
 "name": "test",
 "default_attributes": { },
 "override_attributes": { },
 "json_class": "Chef::Role",
 "description": "This is just a test role, no big deal.",
 "chef_type": "role",
 "run_list": [ "recipe[test]" , "recipe[test2]"]
}

こういうファイルを作っておけば、あとは chef.json は

{ "run_list": "role[test]" }

と書くだけで、test roleが適用されます。attributeなんかもroleの中に書い ておけるので、依存性が低くなります。

Comments

comments powered by Disqus