レシピの作成を通してChefの具体的な使用イメージをつかもう

2013年12月20日(金)
喜納 健

第2回では、実際にChefを使用して“システムを状態で管理する”とはどの様なことか体験してみましょう。簡単なレシピの作成を通してChefを使用する流れを紹介します。

実際にChefを動かしてみよう!

まず始めにお試し用の環境を1台用意しましょう。今回想定している環境は表の通りです。
システム要件については、下記のサイトが参考になります。

System Requirements

項目
環境
1 OS CentOS release 6.4
※インストールパッケージは最小構成
2 アーキテクチャ 64bit
3 メモリ 1GB
4 HDD 10GB
OSインストール後の設定
1 使用ポート
(ファイアウォールの設定)
80番
2 ユーザー
(ホームディレクトリ)
user01
(/home/user01)
3 sudoコマンドの設定 user01 ALL=(ALL) /usr/bin/chef-solo
4 Yumリポジトリの設定 CentOS release 6.4のリポジトリ

chef-soloのインストールと設定

(1)インストーラのダウンロード

chef-soloをインストールします。Opscode社でオムニバス(Omnibus)インストーラと呼ばれるインストーラが提供されています。すぐに利用できるため、ここではオムニバスインストーラを使用した方法をご紹介します。

下記のサイトからインストーラを入手します。

Install Chef

今回想定する環境では、図1にある赤枠の様に指定します。

図1:Opscode社提供オムニバスインストーラダウンロードサイト(クリックで拡大)

(2)chef-soloのインストール

パッケージを取得したら、rpmコマンドを使用してインストールします。rootユーザーで以下のコマンドを実行します。

# rpm -ivh /tmp/chef-11.8.0-1.el6.x86_64.rpm
・・・省略・・・
Thank you for installing Chef!
#

chef-soloがインストールされていることを確認しましょう。

# chef-solo -v
Chef: 11.8.0
#

オムニバスインストーラは、Chefが稼動するのに必要な全てのファイルを/opt/chef 以下に展開します。

インストーラを使用しない場合は、Chefの実行に必要なRubyとRubyパッケージ管理ツールであるGemのインストールが必要になりますが、オムニバスインストーラを使用すればRubyとGemも組み込まれた状態でインストールされます。

(3)設定

ここからは、Chef操作用に用意したユーザーアカウントuser01で作業を行います。
クックブックを格納するディレクトリ/home/user01/cookbooksを作成します。

続いて、クックブックの作成などを行う設定ツールであるKnifeとレシピにもとづいて構築・設定変更を行う単体プログラムchef-soloの設定を行います。クックブックは、レシピや配布ファイル、メタデータをまとめたものです。基本的には、クックブック単位で管理します。

まず、Knifeの設定を行います。/home/user01/.chefディレクトリ作成後、/home/user01/.chef/knife.rbファイルを作成し以下の通りに記載します。

knife.rb

cookbook_path [ "/home/user01/cookbooks" ] ♯クックブック格納先。

次に、chef-soloの設定を行います。/home/user01/solo.rbを作成し以下の通りに記載します。ここでは、ログの出力先をuser01のホームディレクトリ以下にしていますが、必要に応じて変更して下さい。

solo.rb

log_level                :info ♯ログの出力レベル。
log_location             "/home/user01/logfile" ♯ログの出力先。
cookbook_path [ "/home/user01/cookbooks" ] ♯クックブック格納先。

knife.rb、solo.rbそれぞれに“cookbook_path”を設定しています。knife.rbではKnifeがクックブック操作する際に使用するパスを、solo.rbではchef-soloがクックブックを読み込む際に使用するパスを指定しています。

それぞれのファイルの詳細な設定は、Opscode社の下記のサイトに説明があります。

solo.rb
knife.rb

クックブックの作成

それでは、クックブックを作成してみましょう。ここでは、“sample_book”という名前のクックブックを作成します。

(1)テンプレートの展開

下記のコマンドを実行すると、クックブックのテンプレートが展開されます。

# knife cookbook create sample_book
** Creating cookbook sample_book
** Creating README for cookbook: sample_book
** Creating CHANGELOG for cookbook: sample_book
** Creating metadata for cookbook: sample_book
#

クックブックは、レシピや配布するファイルの格納先が決まっており、誰が作成してもどこに何があるかは見当がつくようになっています。上記コマンドを発行すると、以下の様なファイル・ディレクトリが作成されます。ここでは、配布する静的ファイルを格納する“files”とレシピを格納する“recipes”ディレクトリを使用します。

$ tree cookbooks/sample_book
cookbooks/sample_book
├── CHANGELOG.md
├── README.md
├── attributes
├── definitions
├── files
│   └── default
├── libraries
├── metadata.rb
├── providers
├── recipes
│   └── default.rb
├── resources
└── templates
    └── default

クックブックの詳細な説明については、下記のサイトが参考になります。

About Cookbooks

(2)レシピの作成

試しに簡単なレシピを作成してみましょう。

ここでは、リソース(Resource)を使用してレシピを作成します。
まず、リソースについて説明しましょう。リソースは、レシピで状態を定義するために作成された言語(DSL )です。例えば、“ユーザーが作成されている”“ディレクトリが作成されている”など同じフォーマットで様々な状態を定義できます。基本的なフォーマットは以下の通りです。

<リソースタイプ> "<リソース名>" do
   <属性(Attribute)> "<属性値>"
   action :<アクションタイプ>
end

リソースで状態を定義する対象や、それに対するアクションには主に以下のものがあります。

カテゴリ リソース例 主なアクション
ユーザー user 作成/削除/変更/ロック/アンロック
グループ group 作成/削除/変更
ディレクトリ directory 作成/削除
パッケージ apt_package/gem_package/rpm_package/yum_package インストール/アップグレード/削除
ファイル cookbook_file/file/remote_file/template 作成/削除/touch
シンボリックリンク
ハードリンク
link 作成/削除

下記のリファレンスページに、上記リソースも含めた各リソースに関する説明があります。属性の説明やサンプルも豊富に例示されていますので参考になると思います。リソースを組み合わせると数多くの状態が定義できます。

Resources and Providers Reference

それでは、リソースを使用して実際にレシピを作成してみましょう。下記のレシピでは、/tmp以下にsampleというファイルがある状態を定義しています。
/home/user01/cookbooks/sample_book/recipesディレクトリにsample_recipe.rbという名前のレシピファイルを以下の通りに作成します。

sample_recipe.rb

file "/tmp/sample" do
  owner "user01"
  group "user01"
  mode "0644"
  action :create
end

chef-soloの実行

(1)実行するレシピ・クックブックの登録

ノード(chef-client/chef-soloを実行するマシン)に実行するレシピを設定します。ここではファイル名をnode.jsonとし、先程作成したレシピをランリストに設定しています。基本的なフォーマットは以下の通りです。

{
  "run_list": [
      "recipe[<クックブック名>::<レシピ名>]"
   ]
}

/home/user01/node.jsonファイルを作成し以下の通りに記載します。下記のファイルは、ノード固有の変数やランリストと呼ばれる実行レシピリストを定義します。

node.json

{
  "run_list": [
      "recipe[sample_book::sample_recipe]"
   ]
}

これで準備完了です。

ちなみにクックブックを作成すると、recipesディレクトリにdefault.rbが作成されますが、このファイルは、ランリストに設定する際に名前を省略できるレシピファイルです。下記の通りに設定すると、default.rbレシピが適用されます。

{
  "run_list": [
      "recipe[sample_book]"
   ]
}

つまり、下記の設定と同じです。

{
  "run_list": [
      "recipe[sample_book::default]"
   ]
}

(2)実行

それでは、chef-soloを実行してみましょう。/home/user01で以下のコマンドを実行します。root権限が必要となるため、ここではsudoを使用して実行します。

$ sudo chef-solo -c solo.rb -j node.json
[sudo] password for user01: 
Starting Chef Client, version 11.8.0
Compiling Cookbooks...
Converging 5 resources
Recipe: apache::default
・・・省略・・・
Chef Client finished, X resources updated
$

/tmp以下に、“sample”という名前のファイルが存在することを確認しましょう。ファイルのowner・group・modeも定義した内容になっているはずです。

$ ls -lh /tmp
・・・省略・・・
-rwxr-xr-x. 1 user01 user01   0 X月 X X:X X sample
・・・省略・・・
$

Chefはレシピとノードの状態を比較し、異なる場合のみ変更を行います。そのため、レシピの定義と同じ状態でchef-soloを何度実行しても同じ実行結果になります。このように何度実行しても同じ状態になる特徴は、冪等性(べきとうせい)と呼ばれています。

次に、Webサーバのレシピ作成を通して、ファイルの配布やパッケージのインストールなど、Chefでできることについて具体的に紹介します。

Webサーバのレシピを作成してみよう!

(1)レシピを作成する範囲

下記の構築をchef-soloで行います。

  1. Apacheパッケージのインストール
  2. httpd.confファイルの配布
  3. HTMLファイルを配布するディレクトリの作成
  4. HTMLファイルの配布
  5. httpdサービスの起動

(2)クックブックの作成

新たに“apache”という名前のクックブックを作成します。

# knife cookbook create apache

まず、配布するファイルを作成します。
今回配布するのは、2. と4. で定義しているhttpd.confとsample.htmlファイルです。
/home/user01/cookbooks/apache/files/defaultディレクトリに作成します。各ファイルの設定を掲載しておきます。

httpd.conf

Listen 80

ServerRoot "/etc/httpd"

DocumentRoot "/var/www/html"

User apache Group apache  ErrorLog logs/error_log     Options FollowSymLinks     AllowOverride None

sample.html

<html>
 <body>
  <h1>Hello Chef!</h1>
 </body>
</html>

次に、/home/user01/cookbooks/apache/recipes/default.rbに以下を追記します。

default.rb

(クリックで拡大)

以下、リソースごとに各パートについて説明します。

1. Apacheパッケージのインストール(package リソース)

“package”リソースは、パッケージの状態を定義するリソースの1つです。
パッケージとは、例えばRPMやGemパッケージです。パッケージのインストール・削除された状態の定義の他、バージョンの指定も可能です。
1. では、Apacheのパッケージがインストールされた状態を定義しています。

2. httpd.confファイルの配布(cookbook_fileリソース)

“cookbook_file”リソースは、ファイルの状態を定義するリソースの1つです。
2. では、ownerやgroupを指定してファイルの状態を定義しています。ファイルの中身については、クックブックの“files”ディレクトリに意図している内容のファイルを格納しておき、クックブックの“source”属性で配置したファイルを指定します。

3. HTMLファイルを配布するディレクトリの作成(directoryリソース)

“directory”リソースは、ディレクトリの状態を定義するリソースです。
3. では、ディレクトリの状態を定義しています。“directory”リソースを使用すれば、ディレクトリが作成された状態の他、削除された状態の定義も行えます。

4. HTMLファイルの配布

4. は、2. と同様です。

5. httpdサービスの起動(serviceリソース)

“service”リソースは、サービスの状態を定義するリソースです。
5. では、Webサーバのサービスである“httpd”サービスが起動した状態を定義しています。

リソースは、順序立てて定義する必要があります。例えば、1. と5. の順序を逆にした場合、Apacheパッケージがインストールされていない状態でサービスの起動を試みてエラーになります。

パッケージ・ファイルの削除を行う場合は、“削除された状態”を定義しchef-soloを実行する必要があります。レシピの定義部分を削除しただけで実環境のパッケージやファイルが削除されることはありませんので注意が必要です。

最後に、作成したapacheレシピをランリストに設定します。/home/user01/node.jsonファイルを以下の様に設定します。

node.json

{
  "run_list": [
      "recipe[apache]"
   ]
}

(3)実行

これで準備完了です。chef-soloを実行してみましょう。

$ sudo chef-solo -c solo.rb -j node.json

chef-soloの実行が完了致しましたら、ブラウザからWebページを閲覧してみましょう。

http://ノードホスト名またはIPアドレス/sample/sample.html

図2:サンプルページ閲覧画面(クリックで拡大)

/etc/httpd/conf/httpd.confも配布した内容になっていることを確認してみて下さい。

紹介したリソースの他にもファイルの中身をテンプレート化して、ノードに応じて変数部分に値を代入して配布する“template”リソースやユーザーの状態を定義する“user”リソース等があります。是非試してみて下さい。

レシピ作成の予備知識

レシピを作成する際に知っておくと便利なことを3点ご紹介します。

(1)状況に応じたリソースの適用

“DBの初期化が未実施の場合に初期化を行う”など、環境に応じてリソースを適用するかどうか判定する場合もあります。その様な時は、ガード(Guard)と呼ばれる機能を使用することで、OSの種類やファイルの有無などノードの状態に応じてリソース適用の是非を指定できます。

具体的には、“not_if/only_if”文を使用して、レシピで定義したリソースを適用する条件を指定します。

Guard 説明
not_if 戻り値が true の時、リソースを適用しない。
(リソースの適用をスキップさせたい時に使用する)
only_if 戻り値が true の時のみ、リソースを適用する。

“not_if/only_if”文の後に、ShellコマンドまたはRubyのブロックを指定します。指定した判定文の戻り値から定義した状態を適用するか判定します。Shellコマンドの場合はリターンコードが0、Rubyブロックの場合は“true”であるかどうかで戻り値を判定します。

例えば、PostgreSQLインストール直後のDB初期化で使用する際に、初期化で作成されるpostgresql.confファイルの有無から、初期化を行うかどうかをガードで判定します。postgresql.confファイルが存在しない場合、初期化が行われます。

execute "initiallze database" do
  command "service postgresql initdb"
  action :run
  not_if "test -f /var/lib/pgsql/data/postgresql.conf"
end

(2)柔軟にレシピを活用する

上記で紹介したWebサーバのクックブックでは、default.rbファイルに全てのリソースを定義しましたが、レシピ名.rb を作成し1つのクックブックに複数のレシピを作成することができます。実際にレシピを使用していく場合は、共通して適用する部分と構築・運用する環境に応じて個別に適用する部分とで分けておいた方が流用しやすいです。
例えば、SELinuxという名前のクックブックを作成した場合、enforcing・permissive・disabledそれぞれのレシピを用意しておけば、SELinuxの設定に頼らず同じクックブックを使用できます。

作成したクックブックから1つのレシピを実行する場合は、ランリストに以下の様に設定します。

node.json

{
  "run_list": [
      "recipe[ selinux::enforcing ]"
   ]
}

レシピの中で他のクックブックにあるレシピを呼び出すよう定義することでもできます。
例えば、yumクックブックから、apache用のリポジトリを登録するapache_repoレシピを呼び出す場合は、レシピの中で以下の様に定義します。

include_recipe "yum::apache_repo"

package "httpd" do
  action :install
end

・・・省略・・・

その他レシピの書き方については、下記のページが参考になります。
Recipe DSL

(3)コミュニティで公開されているクックブックを利用する

Opscode Community Siteでは、Chefユーザー間でクックブックが共有されています。「Databases」や「Web Servers」など、カテゴリ別にクックブックが整理されており、クックブックを作成する時に参考になると思います。作者によってレシピの中身も異なり、それぞれライセンスが設定されていますのでよく確認して利用しましょう。

図3:Opscode Community Site(クリックで拡大)

Opscode Community Site

公開されているクックブックをみると気づかれると思いますが、レシピはRubyで柔軟に作成できます。Rubyの知識がある方はリソースの開発もできます。

ちなみに、Opscode社のWebサイトでChefを使用する上で知っておくと良いRuby の知識がまとめて紹介されています。こちらも参考になります。

Just Enough Ruby for Chef

第2回は、chef-soloを使用してレシピの作成から適用までの流れを紹介しました。
第3回は、Chef Serverを紹介します。Chef Serverはレシピやノード情報(JSONファイルも含む)を管理する機能を備えており、多数のノードを効率よく管理できます。第3回をお楽しみに!

※記載の会社名、製品名は、それぞれの会社の商標もしくは登録商標です。

株式会社 日立ソリューションズ

(株)日立ソリューションズ、オープンソース技術開発センタにてクラウド関連技術の調査に従事。Hadoop関連のプロジェクトで大規模クラスタの構築を担当したことを機に、システム構築・運用自動化について調査を行っている。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています