ChefでCookbookを作成するときのちょっとしたコツ 9選

こんにちは。斎藤です。

Chefで構築の自動化ができる事はわかっていても、Cookbookをどう記述すればいいのかピンとこない場合があります。そんなときに使えそうなコツをピックアップしてみました。

「Chefを使ってみたいけどいまいちとっかかりがわかりづらい」「あれ、これはどうやるんだ?」、そんなときにご覧頂けたら幸いです。

※Chef 10.16.2で確認しました。また、RHEL, CentOSで利用する事を前提に説明しています。

Cookbookに同梱したRPMファイルから直接インストールする

cookbook_fileとpackageリソースを組み合わせて実行します。

下記の例は、MySQLサーバをRPMファイルを用いてインストールします。

  • "MySQL-server-5.5.29-1.el6.x86_64.rpm"ファイルをあらかじめ "files/default" 内に保存します。
  • recipeを次の通り記述します。
    ファイルは/tmpに展開されたあと、サーバにインストールされます。
    checksumはsha256です。"shasum -a 256 [FILENAME]"で取得できます。無くても良いのですが、ファイルの破損や改ざんをチェックできるよう入れると良いかと思います。
filename = "MySQL-server-5.5.29-1.el6.x86_64.rpm"
file_checksum = "bce0132e86a23b19e1ba229e0411de39cdbde538f922c244d056ecaf3f054cb1"

cookbook_file "/tmp/#{filename}" do
  source "#{filename}"
  checksum "#{file_checksum}"
end

package "MySQL-server" do
  action :install
  provider Chef::Provider::Package::Rpm
  source "/tmp/#{filename}"
end 

リモートサーバにあるtarファイルを展開する

remotefileとscriptリソースを組み合わせて実行します。remote_fileは、リモートサーバにあるファイルをhttp経由で取得し、指定した場所に保存します。scriptリソースを使うと、ChefのDSLだけでは実行できない処理を実現できます。なお、scriptにはPerl, Python, Ruby, cshも利用できます。

下記の例は、Wordpressのソースコードを展開しています。

filename = "wordpress-3.5.tar.gz"
install_dir = "/var/www/html"
remote_uri = "http://wordpress.org/wordpress-3.5.tar.gz"
file_checksum = "def1d094dbd3fcc52208d4e63ae4c31901dfd97e9b4cd619b7d017fd342972ab"

remote_file "/tmp/#{filename}" do
  source "#{remote_uri}"
  checksum "#{file_checksum}"
end

script "install_wordpress" do
  interpreter "bash"
  user        "root"
  code <<-EOL
    install -d #{install_dir}
    tar zxvf /tmp/#{filename} -C #{install_dir}
  EOL
end

条件に合致したときのみ実行する

not_ifとonly_ifがあります。only_ifは評価結果がtrue(return値が0)の時に実行、not_ifはonly_ifの逆です。

下記の例は、"db-"とつくホスト名のサーバのみにmysql-serverパッケージをインストールします。

package "mysql-server"
  action :install
  only_if "echo $(hostname) | grep -q 'db-'"
end

あるリソースが実行されたときのみに実行する

例えば、パッケージのインストールが実行されたときのみ、合わせて実行したいリソースを紐づけるときに用います。

1点、注意があります。合わせて実行したいリソースのアクションは、nothingとします。入れ忘れてしまうと毎回動いてしまいますので、気をつけてください。

下記の例は、MySQLをインストールしたときだけ、my.cnfを作成します。既にインストールされている場合は、my.cnfは作成されません。手元で2回実行して試してみてください。

template "/etc/my.cnf" do
  source "my.cnf.erb"
  mode 0644
  owner "root"
  group "root"
  action :nothing
end

package "mysql-server" do
  action :install
  notifies :create, resources( :template => "/etc/my.cnf" )
end

なお、複数のリソースを実行したい場合は、実行したい順にnotifies属性を増やせばOKです。

ファイルをコピーする

ファイルをコピーするとき、executeやscriptリソースを用いてシェルを呼び出す方法がありますと、fileリソースを用いる方法もあります。

fileリソースを用いた方法は、実行直前にファイルの有無を確認して実行でき、ファイルが無い場合のエラーをハンドリングしやすくなります。

file "/var/www/html/index.html" do
  content IO.read( "/tmp/hoge.html" )
end

ループする

同じ処理を繰り返すときに便利です。

%w{
  bzip2
  curl
  dmidecode
}.each do |pkgname|
  package "#{pkgname}" do
    action :install
  end
end

構文チェック

Cookbookの構文チェックを行う事ができます。

$ knife cookbook test mysql-server
checking mysql-server
Running syntax check on mysql-server
Validating ruby files
Validating templates

Dry Run (whyrun)

chef-soloでは、Dry Run(空実行)を行えます。Cookbookの実行時エラーが出ないかをある程度調べる事が出来ます。オプションは"-W"または"--why-run"になります。

注意点があります。remote_fileやcookbook_fileなど、Cookbook実行中の状態遷移に依存するリソースは、「ファイルが無い」などの実行時エラーになります。本記事では「Cookbookに同梱したRPMファイルから直接インストールする」と「リモートサーバにあるtarファイルを展開する」が、それにあたります。こればかりは、実際に実行してみないとわかりません。

$ chef-solo -W

絞って実行

chef-soloでは、指定したCookbookのみを実行する事が出来ます。オプションは"-o"です。roleやrun_listにリストアップされているCookbookを絞って再実行したい場合に用います。

$ chef-solo -o mysql-server

最後に

初めてChefに取り組まれる方は、ぜひchef-soloで試してみてください。Chefサーバを立ち上げて利用するとなると、準備にchef-soloを用いるより時間がかかります。また、デバッグもchef-soloのほうが比較的行いやすいかと思います。

使い方は、Web上にある事例やOpscodeにあがっているCookbookを読むことで、手っ取り早く理解できました。最後に、よくよくドキュメントを読むと良いのではないでしょうか。

それでは、ごきげんよう。

参考文献

Chef Documentation - http://docs.opscode.com/

株式会社ハートビーツのインフラエンジニアから、ちょっとした情報をお届けします。