opscodeのphpのcookbookを解説してみる

 2013/03/12
このエントリーをはてなブックマークに追加

みなさんお料理頑張ってますか?僕は毎日cookbookのrecipeみながらkitchenでknife使ってChef気分です(意味不明)。 今日はopscodeが提供しているphpのcookbookをみて中身を解説したいと思います。 コードはここです。https://github.com/opscode-cookbooks/php(なお、build-essentialとxmlとmysqlのcookbookに依存性がありますので、それぞれ入手してください)

この記事の目的は、標準的なcookbookの構成の把握とopscodeでのcookbookの作り方の紹介とそれを利用したカスタマイズ方法を紹介することです。

ディレクトリ構成

まずソースコードのディレクトリ構成をみてみます。当たり前ですが通常のcookbookのディレクトリ構成と同じです。

├── CHANGELOG.md
├── CONTRIBUTING
├── Gemfile
├── LICENSE
├── README.md
├── attributes
├── metadata.rb
├── providers
├── recipes
├── resources
├── templates
└── test

attributes

attributes ではレシピの中で使う変数が定義されています。ここでの設定値は、実際にChef-ClientやChef-Soloを動かすときに値を上書きできます。 attributes/default.rb を抜粋したものが以下になります。

lib_dir = kernel['machine'] =~ /x86_64/ ? 'lib64' : 'lib'

default['php']['install_method'] = 'package'
default['php']['directives'] = {}

case node["platform_family"]
when "rhel", "fedora"
  default['php']['conf_dir']      = '/etc'
  default['php']['ext_conf_dir']  = '/etc/php.d'
  default['php']['fpm_user']      = 'nobody'
  default['php']['fpm_group']     = 'nobody'
  default['php']['ext_dir']       = "/usr/#{lib_dir}/php/modules"
  if node['platform_version'].to_f < 6 then
    default['php']['packages'] = ['php53', 'php53-devel', 'php53-cli', 'php-pear']
  else
    default['php']['packages'] = ['php', 'php-devel', 'php-cli', 'php-pear']
  end
when "debian"
  default['php']['conf_dir']      = '/etc/php5/cli'
  default['php']['ext_conf_dir']  = '/etc/php5/conf.d'
  default['php']['fpm_user']      = 'www-data'
  default['php']['fpm_group']     = 'www-data'
  default['php']['packages']      = ['php5-cgi', 'php5', 'php5-dev', 'php5-cli', 'php-pear']
else
  default['php']['conf_dir']      = '/etc/php5/cli'
  default['php']['ext_conf_dir']  = '/etc/php5/conf.d'
  default['php']['fpm_user']      = 'www-data'
  default['php']['fpm_group']     = 'www-data'
  default['php']['packages']      = ['php5-cgi', 'php5', 'php5-dev', 'php5-cli', 'php-pear']
end

default['php']['url'] = 'http://us.php.net/distributions'
default['php']['version'] = '5.3.10'
default['php']['checksum'] = 'ee26ff003eaeaefb649735980d9ef1ffad3ea8c2836e6ad520de598da225eaab'
default['php']['prefix_dir'] = '/usr/local'

default['php']['configure_options'] = %W{--prefix=#{php['prefix_dir']}
                                          --with-libdir=#{lib_dir}
                                          --with-config-file-path=#{php['conf_dir']}
                                          --with-config-file-scan-dir=#{php['ext_conf_dir']}
(中略)
                                          --with-mysql
                                          --with-mysqli=/usr/bin/mysql_config
                                          --with-mysql-sock
                                          --with-sqlite3
                                          --with-pdo-mysql
                                          --with-pdo-sqlite}

3行目で、このcookbookのデフォルトのインストール手段はパッケージ(Redhat系ならyum Debian系ならapt-get)を使ってインストールすることにしています。このinstall_methodの値は、実際のレシピで読み込むモジュールの切り替えのために使われています。この値を外部から’source’に設定すればtarballをダウンロードして自前でビルドします。

case文の箇所では、OSの種類を判定して、ディレクトリ名やユーザー名やインストールするパッケージを切り分けています。特にrhelファミリーの場合はバージョンが5までの場合と6以降の場合でインストールするパッケージを変えることになっています。よく見て頂くと分かりますが、ここでインストールしているパッケージにマルチバイト文字を扱うのに必須なmbstring用のモジュールが入っていません。従って外部からこのdefault[‘php’][‘packages’]の値を書き換える(設定する)必要があります。例えば

{ :php => {:packages => ["php", "php-devel", "php-cli", "php-pear", "php-mbstring"] }}

な感じになります。もっとも、このpackagesの値がOSのバージョンによって異なっているため、外部からハードコードな値を設定するのが適切ではない可能性もあります。その場合は別のcookbookを新たに作成した上で、このopscodeのrecipeをinclude_recipeを使って読み込んだ上で、値を上書きするアプローチになります(最後に解説します)。

最後のブロックはtarballをダウンロードしてインストールする場合に使われます。なんかPHPのバージョンが古い気がしますが、この値も外部から書き換えられます。その際は併せてchecksumも指定する必要があります。またconfigureオプションのデフォルト値もここで設定されています。

recipes

recipesの中は以下のような構成になっています。

├── default.rb
├── module_apc.rb
├── module_curl.rb
├── module_fileinfo.rb
├── module_fpdf.rb
├── module_gd.rb
├── module_ldap.rb
├── module_memcache.rb
├── module_mysql.rb
├── module_pgsql.rb
├── module_sqlite3.rb
├── package.rb
└── source.rb

phpをインストールしようとした際に最初に参照されるのがdefault.rbです。

include_recipe "php::#{node['php']['install_method']}"

# update the main channels
php_pear_channel 'pear.php.net' do
  action :update
end

php_pear_channel 'pecl.php.net' do
  action :update
end

このソースはシンプルです。というのも、先ほどattributesで設定されたinstall_methodに応じて違うレシピを読み込んでいるからです。デフォルトではpackage.rbが読み込まれます。phpをソースからインストールするように

{ :php => { :install_method => "source" }}

としている場合は、source.rbが読み込まれます。ちなみにソースからインストールしようとするとlibmcrypt-develが標準のyumレポジトリからインストールできないので、そのままのconfigureオプションだとインストールに失敗します(ヽ(`Д´#)ノ ムキー!!)。

パッケージでのインストールの場合は、package.rbが利用されますがこちらもシンプルです。

node['php']['packages'].each do |pkg|
  package pkg do
    action :install
  end
end

template "#{node['php']['conf_dir']}/php.ini" do
  source "php.ini.erb"
  owner "root"
  group "root"
  mode "0644"
end

予めattributesで指定しておいたpackagesの配列の値に従ってpackageをインストールします。yumかapt-getかは自動で判断されます。その上で、予め用意されているphp.iniのテンプレートに値を埋め込んで配置します。 なお、このディレクトリにあるmodule_*.rbはphpの様々なモジュールを個別にインストールできるようにしたものです。例えばmemcache用のモジュールをインストールしたければ、runlistの設定などでphp::module_memcacheを追加してください。他も同様です。ただし、このmodule_*.rbは非推奨モジュールになっておりいずれ廃止されるとのことです(READMEにあります。ご指摘感謝>@iakioさん)

templates

設定ファイルのひな形はtemplatesの中に配置します。templatesディレクトリは以下のような構成です。

├── centos
│   └── php.ini.erb
├── debian
│   └── php.ini.erb
├── default
│   ├── extension.ini.erb
│   └── php.ini.erb
├── redhat
│   └── php.ini.erb
└── ubuntu
    └── php.ini.erb

どのディレクトリの中のテンプレートを利用するかは、設定対象のOSによって判断されます。該当するものがない場合はdefaultの中のものが利用されます。CentOSの場合、変数が自動で代入される箇所は以下になります。

extension_dir = "< %= node['php']['ext_dir'] %>"
< % node['php']['directives'].each do |directive, value| -%>
< %= "#{directive}=\"#{value}\"" %>
< % end -%>

最初の行は拡張モジュールを配置するディレクトリで、/usr/lib/php/modulesまたは/usr/lib64/php/modules になります。このパスもattributesの中で設定されます。 またattributesの中でdefault[‘php’][‘directives’] = {}と設定されていますが、この値を外部から指定すればそれが、 キー=“値”の形でphp.iniに書き込まれます。

resourcesとproviders

resourceとproviderによって独自の処理を追加することが出来ます。 ここでは、pearとpear_channelという2つが定義されています。中身はソースを見て頂くと分かりやすいですが、実際にサーバ上でおこなうコマンドをゴリゴリと書いています。 それによってrecipes/default.rbにある

php_pear_channel 'pear.php.net' do
  action :update
end

のような処理を実行することが出来ます。また自分で

php_pear "PhpDocumentor" do
  preferred_state "stable"
  version "1.4.3"
  action :install
end

のような処理を書くことも出来ます(他のcookbookでやる場合はinclude_recipeでここで紹介しているphpのcookbookを設定する必要はあります)

ちょっと応用

ここで紹介したopscodeのphpのcookbookを使ってさらに自分用にカスタマイズする方法を紹介します。 まずは、opscodeのcookbookがおいてあるのと同じ階層に新しいcookbookを作ります。knifeコマンドを使う場合はこんな感じ (cookbookの名前はかなり適当ですw)

knife cookbook create oreore_php -o .

次に依存関係を定義するために、metadeta.rbを編集します。追加するのは最終行です。 これによってphpのcookbookで定義されているresourceを含めて全て利用可能です。

name             'oreore_php'
maintainer       'ryuzee'
maintainer_email 'ryuzee@gmail.com'
license          'All rights reserved'
description      'Installs/Configures oreore_php'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'
depends          "php"

次にrecipeを作成(recipes/default.rb)します。中身は以下のようにしてください (冒頭のファイルコメントは省略)。

include_recipe "php" 

そして自分用のattributeの設定(attributes/default.rb)をします。今回はデフォルトのタイムゾーンを東京にしたいのと、インストールするパッケージを増やしたいので以下のようにします。

default['php']['directives'] = { "date.timezone" => "Asia/Tokyo" }

case node["platform_family"]
when "rhel", "fedora"
  if node['platform_version'].to_f < 6 then
    default['php']['packages'] = ['php53', 'php53-devel', 'php53-cli', 'php53-mbstring', 'php-pear']
  else
    default['php']['packages'] = ['php', 'php-devel', 'php-cli', 'php-mbstring', 'php-pear']
  end
end

以上で準備が完了です。作ったoreore_phpのcookbookを適用してみてください(Vagrant+Chef-soloが簡単です)

 2013/03/12
このエントリーをはてなブックマークに追加

サイト内検索


著作

寄稿

Latest post: