Chefを使ってみる(3) CookbookとRecipe

毎週書くつもりが、あっという間に3週間空いてしまった。。

気を取り直して、今回はCookbookについてもう少し掘り下げたいと思います。

Cookbookのさわりの部分は、前回の記事で書いてあります。
この記事では、以下の記事の手順でインストールがされていることを前提に解説します。
Chefを使ってみる(2) Cookbookについて
Chefを使ってみる

Cookbookを使って簡単にApacheをインストールすることが出来ましたが、実際はサーバやサービスごとに設定を変える必要があるので、それら個別の設定をCookbookで指定する方法について説明します。

まずは、インストール済みのApacheに対してvirtual hostを書き換えるrecipeと作成します。

cd /home/ubuntu/chef-repo/cookbook/apache2/

recipeやtemplateの中で変わるような値を指定したい場合は、cookbookのattributeとして作成します

attributeの追加

vi attributes/default.rb

default["apache"]["document_root"] = "/var/www/sparkgene"
default["apache"]["domain_name"] = "sparkgene.com"
default["apache"]["sites_available_dir"] = "/etc/apache2/sites-available/"

recipeの作成

templateに渡す値は、variablesに指定します。

vi recipe/edit_virtualhost.rb

template "#{node["apache"]["sites_available_dir"]}default" do
  source "site_available/sparkgene.com"
  owner "apache"
  group "apache"
  mode "0644"
  variables(
    :domain_name => node["apache"]["domain_name"],
    :doc_root => node["apache"]["document_root"]
  )
end

templateを作成

recipeから受け取った値は<%= @キー名 %> で指定します
(erbはテンプレートの拡張子

mkdir -p templates/ubuntu/site_available
vi templates/ubuntu/site_available/sparkgene.com.erb

<VirtualHost *:80>
        ServerAdmin webmaster@<%= @domain_name %>

        DocumentRoot <%= @doc_root %>
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory <%= @doc_root %>>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>

        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
        <Directory "/usr/lib/cgi-bin">
                AllowOverride None
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                Order allow,deny
                Allow from all
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/access.log combined

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>

templateについて少し補足すると、上記の例でtemplateの作成場所を「templates/ubuntu/site_available」としているのは、templateとfileに関しては、OSごとバージョンごとに変わる可能性があるので、chefはcookbook内のtemplateを探す際に複数の場所から探しだそうとします。
探す順番と場所は以下のとおりです。

  1. OSのバージョンを含めたディレクトリ
  2. OS名のディレクトリ
  3. defaultディレクトリ

これは、chefがcookbookでnodeを構成する際に、同じcookbookでも色んなOS上で実行しても、同じように構成できるようにしているためです。
opscodeから提供されているnginxのcookbookを見るとそれがよく分かるんじゃないかと。
https://github.com/opscode-cookbooks/nginx

これでrecipeの準備は出来ました。
しかし、前回の設定では以下の様にnodeに対してapache2のデフォルトレシピしか設定していません。

knife node run_list add chefnode1 "recipe[apache2]"

上記のコマンドで「"recipe[apache2]"」と書いてますが、これ暗黙的に「"recipe[apache2::default]"」と書いたのと同じ事です。
今のままでは、chef-clientを実行してもdefaultのrecipeしか適用されません。

knife node run_list add chefnode1 "recipe[apache2::edit_virtualhost]"

とさらにrecipeを追加することは可能ですが、どんどん増えてきたら。。

冒頭で触れたように、実際はサーバには色々なミドルウエアなどインストールする必要があり、今回の例のようにapacheだけ入れれば終わりというものではありません。

そこで登場するのがroleです。
roleについて

”roleはnodeに対して特定のパターンとプロセスを定義する方法です” と書かれているように、nodeの状態を整えるために複数のrecipeを順序立てて定義することができます。

早速roleを作ってみましょう。
roleは、chef-repo/rolesに置きます。

cd /home/ubuntu/chef-repo/roles

今回のサーバはwebサーバを想定しているので、そんな名前で作りましょう。

roleの書き方

vi web_server.rb

name "web_server"
description "Web server role."
run_list "recipe[apache2]","recipe[apache2::edit_virtualhost]"

保存したら作成したroleをchefに登録します。

knife role from file /home/ubuntu/chef-repo/roles/web_server.rb

登録されたroleは以下のコマンドで確認できます。

knife role list

web_server

roleの詳細を見る時は、

knife role show web_server

chef_type:           role
default_attributes:
description:         Web server role.
env_run_lists:
json_class:          Chef::Role
name:                web_server
override_attributes:
run_list:
  recipe[apache2]
  recipe[apache2::edit_virtualhost]

これで、apacheをインストールして、バーチャルホストを設定してくれるroleの準備ができました。

では、このroleをnodeに指定します。
最初にノードの状態を見ましょう。
knife node show chefnode1

Node Name:   chefnode1
Environment: _default
FQDN:        ip-1-1-1-1.ap-northeast-1.compute.internal
IP:          1.1.1.1
Run List:    recipe[apache2]
Roles:       
Recipes:     apache2
Platform:    ubuntu 12.04
Tags:

最初に設定したrecipeが残っているのでこれを削除します。

knife node run_list remove chefnode1 "recipe[apache2]"

chefnode1:
  run_list:

run_listからrecipeが削除されました。

作成したroleをrun_listに追加します。

knife node run_list add chefnode1 "role[web_server]"

chefnode1:
  run_list: role[web_server]

完成したので、chef-clientを実行して適用しましょう。

knife ssh "name:chefnode1" "sudo chef-client" -x ubuntu -i /home/ubuntu/.ssh/MY_KEY.pem

対象のサーバにSSHで入ってVirtualHostが設定されているかを見ます。

cat /etc/apache2/sites-available/default

<VirtualHost *:80>
        ServerAdmin webmaster@sparkgene.com

        DocumentRoot /var/www/sparkgene
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory /var/www/sparkgene>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>

        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
        <Directory "/usr/lib/cgi-bin">
                AllowOverride None
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                Order allow,deny
                Allow from all
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log

        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/access.log combined

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>

ちゃんと設定されました!

/var/www/sparkgene に index.htmlを作成して、ブラウザからアクセスしてみると、ページも表示されました。
(上記のrecipeでは、/var/www/sparkgeneディレクトリの作成と、apacheの再起動は飛ばしているので、手動でやりました)

テンプレートを使うと環境やサービスによって値が異なるものに対して動的に設定をすることができます。
また、roleを使って一連のrecipeをnodeに適用する方法がわかったと思います。

このへんの機能を使いはじめると、色々なことができることが分かってきたと思います。

次回は、環境(本番、開発)での管理について書こうと思います。