miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました

Chef-Solo で PHP をインストールしてみた

開発環境、ステージング環境、本番環境と似たような環境を構築する機会は多いわけで、このあたりを自動化したいとは前々から思っていたんですが。

今回 PHP(と pear のパッケージいくつか)をインストールするために Chef というやつを使ってみたので、これについて書いてみます。

結論としては、いちおうインストールできましたが、結構いろいろ難ありでした。

Chef とっかかり

システム自動管理ツールについて

システム自動管理ツールというと Puppet が有名です。システムの構成を自動化するだけであればスクリプトなんかでもできないことはないんですが、Puppet 導入の利点として

では

  • 使い捨てスクリプトの量産を防ぐことによる手間の軽減
  • 管理タスクを誰もが同じ形で定義でき,管理品質を均一化できる
  • 管理タスクを誰もが見える形で定義でき,変更履歴の追跡や監査が可能になる

というのが挙げられています。

個人的にいいなと思ったのは、この 3 点目で。Puppet DashboardRedmine の Initr プラグイン を使うと、ブラウザからノードの一覧と役割が一望できて、サーバ構成を説明する手間が省けるんじゃないかなと期待していたのでした。

Puppet じゃなくて Chef?

ということで Puppet を使いたくなったわけですが、

を読んでしまいまして。自分が使うなら Chef のほうかなと。

Rails に慣れている身なので、設定ファイルが内部 DSLRuby スクリプトとして動作する)のは魅力的です。文法を覚えなくていいのと、柔軟/簡潔な文法で書けることが約束されているので。

Ruby に詳しくない人間に展開することを考えると、外部 DSL である Puppet のほうが強いのかなという気もするんですけど・・・Capistrano なんかでも Ruby の内部 DSL は使われているわけで、Ruby をメインで使わない人も覚えてても損はしないんじゃないかと思います。

Chef の参考 URL

使い方がイメージできなくていろんなサイトを見て回ってました。いくつか挙げておきます。

あとは細かい使い方で迷ったら、公式のドキュメントを読み進めるのが一番手っ取り早かったです。Web 上には情報少ないので。

今回の方針

今回はサーバを使わない Chef-Solo を試してみました。

サーバを使わなかった理由ですが、公式のサーバは

Sign up today to manage up to 5 nodes free.

とか書いてあって制限が面倒に思えたのと、自前サーバのインストールは

によるとすごく大変みたいなので。

サーバを使わないといろいろと活かせないようなんですけど、まずは手始めということで。

今回 Chef や PHP を導入したサーバについて

Rails アプリのデモ用に用意した CentOS 5.5 の環境です。Git や REE(Ruby Enterprise Edition)等がインストール済みのところで検証してしまったので、クリーンな環境では動作しないところがあるかもしれません。

PHP のインストール時には内部で yum install php みたいなコマンドが走ります。--enablerepo 等のオプションなしで目的の PHP がインストールできる環境は、あらかじめ整えておく必要があります。(※デフォルト設定の場合です。ソースからインストール方法もあります。)

Chef-Solo による PHP のインストール

を見比べながらやりました。

rvm、MRI Ruby のインストール&有効化

(追記)※REE が入っていたので rvm 使いましたけど、まっさらな状態であれば yum 等でインストールできる ruby 1.8.7 等で問題なく動作すると思います。

(さらに追記)yum で普通に入れると 1.8.5 が入るみたいですね。あと RVM の利用には git が必要みたいです。

REE が入っている環境だと書きましたが、REE で chef を動作させると pear モジュールのインストールに

/opt/ruby-enterprise-1.8.7-2011.03/lib/ruby/gems/1.8/gems/chef-0.9.14/bin/../lib/chef/shell_out.rb:381:in `fork': Cannot allocate memory - fork(2) (Errno::ENOMEM)

のようなエラーが発生して、うまく動作しませんでした。

また、MRI Ruby についても

については動作したものの

については動作しませんでした。

なので、今回は RVM(複数の Ruby を共存させるツール)を利用して

# 2011-04-25 URL 変更
#bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )
bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
rvm install 1.8.7

として MRI Ruby 1.8.7 をインストールしておいて、

rvm use 1.8.7
ruby --version

として 1.8.7 を有効化&正しく使われていることを確認しておきました。

Chef のインストール
gem install chef --no-rdoc --no-ri

で Chef をインストールします。依存モジュールが多いので --no-rdoc --no-ri しておいたほうが時間かからなくてよいです。今回は chef 0.9.14 がインストールされました。

solo.rb の配置

参考 URL では .chef/solo.rb や ~/solo.rb が使われていましたが、マニュアルの最後のほうに書いてあるとおり、デフォルトの /etc/chef/solo.rb に置くことにします。

mkdir /etc/chef
cat <<\EOS > /etc/chef/solo.rb
file_cache_path "/var/chef-solo"
cookbook_path ["/var/chef-solo/site-cookbooks/opscode", "/var/chef-solo/cookbooks"]
EOS

cookbook_path はサンプルに少し変更を加えて site-cookbooks を追加しています。(理由については後述します。)

なお、パスはフルパスで書かないとエラーになる(/root を ~/ と書いたりはできない)ようなのでご注意ください。

リポジトリのひな形作成
cd /var
git clone git://github.com/opscode/chef-repo.git chef-solo

として作成します。

opscode の cookbook 取得

opscode で cookbook が多数提供されているわけですが、インストールする際は自動的に cpscode が参照されるものの、レシピを参照したいような場合はうまく参照できないようです。

仕方ないので、

cd /var/chef-solo
git clone git://github.com/opscode/cookbooks.git site-cookbooks/opscode

として自前でレシピを取得しておきます。(前の手順で solo.rb で追加したのはこのパスです。)

当初は solo.rb に

recipe_url "https://github.com/opscode/cookbooks/tarball/master"

と書けばいけるかなと期待したんですけど、file_cache_path 配下に opscode-cookbooks-24226fd みたいなディレクトリが作成されてしまい、うまくいきませんでした。

この状態で

chef-solo

を実行すると、エラーなしで終了するはずです。(もし問題が発生して原因がわからない場合は -l debug オプションを付加すると、もう少し詳細なログが出力されるようになります。)

php のレシピ修正(CentOS/Redhat の 32 bit OS の場合のみ)

(2011-04-23 追記)レシピが修正されたようなので、最新版を使えばこの項の修正は不要なはずです。

困ったことに、レシピの templates/centos/php.ini.erb にライブラリのパスが

extension_dir = "/usr/lib64/php/modules"

のようにベタ書きされており、32 bit OS だとうまく動作しません。(centos だけでなく、redhat のほうもそうなっているようです・・・。)

apache2/recipes/default.rb に

    if node[:kernel][:machine] == "x86_64"
      libdir = value_for_platform("arch" => { "default" => "lib" }, "default" => "lib64")
    else
      libdir = "lib"
    end

このような処理がありましたので、これに倣って /var/chef-solo/site-cookbooks/opscode/php/templates/centos/php.ini.erb を以下のように変更しておきます。(Redhat の場合はたぶん redhat/php.ini.erb が使われるので、そちらを修正してください。)

diff --git a/php/templates/centos/php.ini.erb b/php/templates/centos/php.ini.erb
index 747b518..246b355 100644
--- a/php/templates/centos/php.ini.erb
+++ b/php/templates/centos/php.ini.erb
@@ -526,7 +526,11 @@ doc_root =
 user_dir =

 ; Directory in which the loadable extensions (modules) reside.
+<%- if node[:kernel][:machine] == "x86_64" -%>
 extension_dir = "/usr/lib64/php/modules"
+<%- else -%>
+extension_dir = "/usr/lib/php/modules"
+<%- end -%>

 ; Whether or not to enable the dl() function.  The dl() function does NOT work
 ; properly in multithreaded servers, such as IIS or Zeus, and is automatically
@@ -1218,4 +1222,4 @@ soap.wsdl_cache_ttl=86400

 ; Local Variables:
 ; tab-width: 4
-; End:
\ No newline at end of file
+; End:

(追記)いちおう報告しておきました。

node.json の配置

参考 URL によると chef-repo\.chef\chef.json や ~/node.json になっていましたが、

を見た感じだと、ノード毎の設定は /etc/chef にまとまっているようなので、 /etc/chef/node.json を作成することにします。

cat <<\EOS > /etc/chef/node.json
{
  "run_list": [ "recipe[portal_site_php]" ]
}
EOS

今の案件ではいくつかサイトがあるんですが、その中のポータルサイトPHP 環境ということで、今回は portal_site_php という名称でレシピを作成することにしました。

この状態で

chef-solo -j /etc/chef/node.js

を実行すると、portal_site_php というクックブックが見つからないというエラーになるはずです。

PHP インストール用の cookbook 作成
cd /var/chef-solo
rake new_cookbook COOKBOOK=portal_site_php

として cookbook を作成します。(参考 URL に記載があったとおり、サーバを使っていないので knife は使えず、rake で代用しています。)

を参考にしつつ、

  • cookbooks/portal_site_php/recipes/default.rb

の末尾に以下のように設定を追加します。(モジュールその他のオプションは環境に合わせて変えてください。)

include_recipe "php"

package "php-pgsql" do
  action :install
end

%w(mdb2 mdb2_driver_pgsql Pager HTTP_Upload xml_serializer-beta Crypt_Blowfish).each do |package_name|
  php_pear package_name do
    action :install
  end
end

php_pear "Mail" do
  version "1.1.14"
  action :install
end

php_pear "Mail_Mime" do
  version "1.5.2"
  options "--nodeps"
  action :install
end

php_pear "Mail_mimeDecode" do
  version "1.5.0"
  options "--nodeps"
  action :install
end

php_pear 内部で pear コマンドが呼ばれるので、pear のインストールを保証するために include_recipe "php" を実行しています。
また、必須ではないようですが cookbooks/portal_site_php/metadata.rb 末尾に以下を追加しておきます。(ついでに他の属性もそれらしく変更しておいたほうがいいと思います。)

depends          "php"

この状態で

chef-solo -j /etc/chef/node.json

とすると、

  • PHP
    • その依存モジュールである Apache
  • レシピに記載した pear モジュール

のインストールが行われるはずです。

ちなみに 37signals のほうにも PHP の cookbook はあったんですが、PEAR に対応してない&ちょっと特殊な設定みたいなので opscode のほうを使いました。

問題点

  • 結構な頻度で pear.php.net とか pecl.php.net への接続がタイムアウトになります。(初回は必ず失敗しているかも・・・。)
    • 再実行すればうまくいくようですが、これだと自動化しづらいのでどうしたものやら。
  • CentOS は動作の対象外だったり、上記の PHP のように動作が怪しいレシピになっていたりするようです。
    • 安心して使えるようになるのはまだ先かも?
  • どこかのサイトに書いてたとおり、Chef 関連の用語は検索に引っ掛けるのが難しい。
    • "chef pear" とかで検索してすごく脱力しました・・・。

今後やりたいこと

  • せっかくなので Chef サーバを使ってみたいところ。
  • Chef サーバを使わないにしても、/var/chef-solo の内容をチームのリポジトリに配置しておいて、これをチェックアウト→chef-solo 実行で環境構築はできるので、サーバの環境設定スクリプトの代替くらいには使えるかも。

その他気になる情報

  • Cookbook Shelves - Composable Configurations
    • 外部の shelve を使う方法。
    • 今回は cookbook_path を増やす形で対応しましたが、特定の cookbook を使いたいだけならこの方法で動作すると思います。

2011-06-02 追記

環境の構築についていろいろ書きましたが、もっと簡単にセットアップできるようにしてくれている方が。

CentOS5上にChef環境を用意するためのYumレポジトリを用意したので、 それを使って手っ取り早く試してみます。

ただし、今回は64ビット版のみしかYumレポジトリを用意していないため、OSはCentOS 5.3 64bit Plainを選択してください。

とのこと。CentOS 64-bit を使っている方はこれを使わせてもらうとよさげ。

「Chef のサーバ構築はすごく大変」と書きましたが、Capistrano ですぐに行えるようにしているそうで。Chef 以外にも活かせそうなノウハウですね。