今回は簡便ながら、るびまにchefについての記事を寄稿しましたのでお知らせです。
Rubyist Magazine 0035 号
なんでも7周年記念だそうで、おめでとうございます!
こういった活動を7年続けるということはすごいことだと思います。
ちなみにDECOLOGはまだ5年目です。確か。


それはみんながよろこぶことなのか

# バージョンのチェックを行い、バージョンが想定と違っていたらインストールを実行する
# サーバ稼働中の予期しないアップグレードを防ぐため、/usr/local/src/PHP_VERSION_CHECK_REQUIRED
# というファイルが存在する場合のみ処理が行われる。
buildtool_check_version "php" do
  action :check
  input '|/usr/local/bin/php -v'
  regex /^PHP ([0-9.]+)/
  version node[:php][:version]
  only_if "cat /usr/local/src/PHP_VERSION_CHECK_REQUIRED"
  notifies :create, "cookbook_file[/usr/local/src/#{node[:php][:tarball]}]", :immediately
  notifies :install, "buildtool_make_install[php]", :immediately
  pecl_packages.each do |package_name, install_name|
        if node[:php][:extension][package_name.to_sym] then
        notifies :run, "execute[pecl-install-#{package_name}-force]", :immediately
        end
  end
end
# PHPのコンパイルオプションが変わっている場合はインストールを実行する
# サーバ稼働中の予期しない再コンパイルを防ぐため、/usr/local/src/PHP_VERSION_CHECK_REQUIRED
# というファイルが存在する場合のみ処理が行われる。
# ただしPHPがインストールされていない場合は必ずインストールが実行される。
file "/usr/local/src/PHP_CONFIG_OPTION" do
  content node[:php][:config_option]
  only_if "cat /usr/local/src/PHP_VERSION_CHECK_REQUIRED || ! /usr/local/bin/php -v"
  notifies :create, "cookbook_file[/usr/local/src/#{node[:php][:tarball]}]", :immediately
  notifies :install, "buildtool_make_install[php]", :immediately
end
cookbook_file "/usr/local/src/#{node[:php][:tarball]}" do
  action :nothing
  source node[:php][:tarball]
  mode "0644"
end
buildtool_make_install "php" do
  action :nothing
  tarball node[:php][:tarball]
  srcdir "php-#{node[:php][:version]}"
  config_option node[:php][:config_option]
  notifies :restart, "service[httpd]"
end
buildtool_check_version "php" do
actions :check # バージョンチェックをする Resource の定義 attribute :input, :kind_of => String, :required => true attribute :regex, :kind_of => Regexp, :required => true attribute :version, :kind_of => String, :required => trueとresourcesに定義をし
action :check do
  begin
    versionstring = IO.read(new_resource.input)
    if new_resource.regex =~ versionstring
      version = $1
      if version != new_resource.version
        Chef::Log.info("Version check for #{new_resource.name}: expected=#{new_resource.version}, actual=#{version}")
        new_resource.updated_by_last_action(true)
      end
    else
      Chef::Log.info("Version check failed: '#{versionstring}' is not match #{new_resource.regex}")
      new_resource.updated_by_last_action(true)
    end
  rescue
    Chef::Log.info("Version check failed: #{$!}")
    new_resource.updated_by_last_action(true)
  end
end
とprovidersに実際の動作を記述します。buildtool_check_version "php" do action :check input '|/usr/local/bin/php -v' #ココ! regex /^PHP ([0-9.]+)/ #ココ! version node[:php][:version] #ココ!と、利用時に指定した値が入ります。
version node[:php][:version]は
default[:php][:version] = "5.x.x" default[:php][:tarball] = "php-" + default[:php][:version] + ".tar.bz2" default[:php][:config_option] = "--with-libdir=lib64 \ ~後略~
include_recipe "buildtool"しておく必要があります。
only_if "cat /usr/local/src/PHP_VERSION_CHECK_REQUIRED"

「 この前はありがとう!!久々メッチャ楽しかった~ みんながいる前だったからちょっと恥らっちゃったけど、2人っきりだったら私も同じ気持ちだったょ(はぁと 恥ずかしいけど・・・ 次は2人っきりで会えませんか?? 返事楽しみに待ってます(はぁと 」
rake new_cookbook COOKBOOK=php※ただし「knife cookbook create」を使えと怒られます。が、knifeコマンドはあらかじめセットアップをしておかないと正しく動作しないので、今回はこれで。
attributes definitions files libraries providers recipes resources templates metadata.rb README.rdocいらないものもたくさんあるので、いらないことに気づいたタイミングで消したらいいと思います。
{chef-repo}/cookbook/php/files/default
直下に置いておきます。{chef-repo}/cookbook/php/templates/default
直下に置いておきます。{chef-repo}/cookbook/php/recipes/default.rb
include_recipe "apache"こんな感じでapacheのレシピを発動させます。
package "curl-devel" package "libjpeg-devel" package "libpng-devel" ~後略~
<Resource>※前回のエントリ参照
Recipe内で行う操作を抽象化して宣言文ぽくしたもの。パッケージ管理、デーモン管理、ファイル管理、コマンド実行などが用意されている。

$knife node show {domain}
~前略~
    "platform_version": "5.x",
    "fqdn": "hoge.example.jp",
~中略~
    "domain": "xxx.xxx.xx",
    "os": "linux",
    "idletime": "13 days 13 hours 28 minutes 20 seconds",
    "network": {
      "default_interface": "eth0",
      "interfaces": {
        "lo": {
          "flags": [
            "UP",
            "LOOPBACK",
            "RUNNING"
          ],
          "addresses": {
            "::1": {
              "scope": "Node",
              "prefixlen": "128",
              "family": "inet6"
            },
            "127.0.0.1": {
              "netmask": "255.0.0.0",
              "family": "inet"
            }
          },
          "mtu": "16436",
          "encapsulation": "Loopback"
        },
        "eth0:xxx.xxx": {
          "flags": [
            "UP",
            "BROADCAST",
            "RUNNING",
            "MULTICAST"
          ],
~後略~
# Server port for sending active checks ServerRoot "/usr/local/apache" ServerName <%= node[:fqdn] %> ←ココ!!
default[:apache][:version] = "2.2.xx"と書いておいて、apacheのrecipeに
buildtool_make_install "apache" do
  action :install
  tarball node[:apache][:tarball]
  srcdir "httpd-#{node[:apache][:version]}" ←ココ!!
  config_option configure_option()
  not_if {check_compile_setting}
  notifies :create, "template[/etc/httpd/httpd.conf]"
  notifies :restart, "service[httpd]"
end
と書いておけば、基本的にはこの2.2.xxのapacheをインストールさせることができます。


ReverseProxyA(xxx.xxx.xxx.xxx)→ReverseProxyB


[0] {
array(key1 => value, key2 => value, key3 => value ・・・)
},
[1] {
 array(key1 => value, key2 => value, key3 => value ・・・)
}
:
:
[n] {
 array(key1 => value, key2 => value, key3 => value ・・・)
}
<?php
class   My_Redis_AdViewLog extends My_Redis {
    const   KEY_PREFIX = "ad_view";
    function    __construct($last_hour=false) {
        // redisのDBは時間(h)と同期をとる。つまり0~23の範囲をとる。
        $time = strtotime(($last_hour ? "-1 hour" : "now"));
        $index = date("G", $time);
        parent::__construct(REDIS_SERVER_AD_VIEW, $index);
    }
    function logging($ad_id, $carrier) {
        $this->increment($ad_id."/".$carrier);
    }
parent::__construct(REDIS_SERVER_AD_VIEW, $index);
$this->increment($ad_id."/".$carrier);

2010-10-20 14:05:35,769 INFO org.apache.hadoop.ipc.Server: IPC Server handler 15 on 9001, call heartbeat(org.apache.hadoop.mapred.TaskTrackerStatus@51c293f8, true, true, -1) from 192.168.0.xxx:44035: error: org.apache.hadoop.mapred.DisallowedTaskTrackerException: Tasktracker denied communication with jobtracker: tracker_hdslave1.domain.jp:localhost.localdomain/127.0.0.1:44034
org.apache.hadoop.mapred.DisallowedTaskTrackerException: Tasktracker denied communication with jobtracker: tracker_hdslave1.domain.jp:localhost.localdomain/127.0.0.1:44034
    at org.apache.hadoop.mapred.JobTracker.heartbeat(JobTracker.java:1246)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:481)
    at org.apache.hadoop.ipc.Server$Handler.run(Server.java:890)
はて?jobtrackerからクラスタへの接続が許可されないとな?includeファイルが読めてない?tcp 0 0 ::ffff:192.168.0.5:9000 :::* LISTEN 220 2464200901 8483/java tcp 0 0 ::ffff:192.168.0.5:9001 :::* LISTEN 220 2464201589 8766/java (省略)
258 HADOOP_OPTS="$HADOOP_OPTS -Dhadoop.root.logger=${HADOOP_ROOT_LOGGER:-INFO,console}"
    259 if [ "x$JAVA_LIBRARY_PATH" != "x" ]; then
    260   HADOOP_OPTS="$HADOOP_OPTS -Djava.library.path=$JAVA_LIBRARY_PATH"
    261 fi
→  262 HADOOP_OPTS="$HADOOP_OPTS -Djava.net.preferIPv4Stack=true"
    263
    264 # run it
    265 exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"
262行目の1行が編集した部分です。$ sudo netstat -plten | grep java tcp 0 0 192.168.0.5:9000 0.0.0.0:* LISTEN 220 2480561580 29797/java tcp 0 0 192.168.0.5:9001 0.0.0.0:* LISTEN 220 2480562441 30112/java (省略)

| includeファイル | excludeファイル | 扱い | 
|---|---|---|
| 含まれていない | 含まれていない | ノードへ接続不可 | 
| 含まれていない | 含まれている | ノードへ接続不可 | 
| 含まれている | 含まれていない | ノードへ接続可 | 
| 含まれている | 含まれている | ノードは接続可で、脱退させられる | 
| includeファイル | excludeファイル | 扱い | 
|---|---|---|
| 含まれていない | 含まれていない | Trackerへ接続不可 | 
| 含まれていない | 含まれている | Trackerへ接続不可 | 
| 含まれている | 含まれていない | Trackerへ接続可 | 
| 含まれている | 含まれている | Trackerへ接続不可 | 
$ echo "hdslave3.domain" >> /home/hadoop/hadoop/conf/hosts.include $ /home/hadoop/rsync.sh※includeファイルにはサーバーのFQDNを記述します。
$ /home/hadoop/hadoop/bin/hadoop dfsadmin -refreshNodes
$ echo "hdslave3" >> /home/hadoop/hadoop/conf/slaves $ /home/hadoop/rsync.sh
$ /home/hadoop/hadoop/bin/stop-all.sh $ /home/hadoop/hadoop/bin/start-all.sh
$ echo "hdslave3.domain" >> /home/hadoop/hadoop/conf/hosts.exclude $ /home/hadoop/rsync.sh
$ /home/hadoop/hadoop/bin/stop-mapred.sh $ /home/hadoop/hadoop/bin/start-mapred.sh
$ /home/hadoop/hadoop/bin/hadoop dfsadmin -refreshNodes
$ hadoop/home/hadoop/bin/hadoop dfsadmin -refreshNodesStateがDecommission in progress から Decommissionedへ変更したらデータ退避完了です。
$ grep -v "hdslave3" /home/hadoop/hadoop/conf/hosts.include >> /home/hadoop/hadoop/conf/hosts.include $ grep -v "hdslave3" /home/hadoop/hadoop/conf/hosts.exclude >> /home/hadoop/hadoop/conf/hosts.exclude $ grep -v "hdslave3" /home/hadoop/hadoop/conf/slaves >> /home/hadoop/hadoop/conf/slaves $ /home/hadoop/rsync.sh
$ /home/hadoop/hadoop/bin/stop-all.sh $ /home/hadoop/hadoop/bin/start-all.sh
$ /home/hadoop/hadoop/bin/hadoop dfsadmin -refreshNodes

$ ssh hdmaster $ sudo su - hadoop $ umask 002 $ wget http://ftp.kddilabs.jp/infosystems/apache/hadoop/core/stable/hadoop-0.18.3.tar.gz $ tar xzf hadoop-0.18.3.tar.gz $ mv hadoop-0.18.3 hadoopこれで/home/hadoop/hadoopに展開されています。
$ mkdir -p /home/hadoop/tmp $ mkdir -p /home/hadoop/filesystem/dfs $ mkdir -p /home/hadoop/logsHadoopで使用するディレクトの作成です。
$ vi /home/hadoop/hadoop/conf/masters
hdmasterマスターのhostです。
$ vi /home/hadoop/hadoop/conf/slaves
hdslave1 hdslave2スレーブのhost一覧です。スレーブを追加したらこのファイルにhostを追加していきます。
$ vi hadoop/conf/hadoop-env.sh
>>> export JAVA_HOME=/usr/java/latest export HADOOP_LOG_DIR=/home/hadoop/logs >>>Hadoop環境にJavaのパスを設定します。
$ vi hadoop/conf/hadoop-default.sh
>>>
<property></property>
  <name>hadoop.tmp.dir</name>
  <value>/home/hadoop/tmp/hadoop-${user.name}</value>
<description>A base for other temporary directories.</description>
>>>
Hadoopの一時ディレクトリのパスを設定します。$ vi hadoop/conf/hadoop-site.sh
>>> <configuration> <property> <name>fs.default.name</name> <value>hdfs://hdmaster:9000</value> </property> <property> <name>mapred.job.tracker</name> <value>hdmaster:9001</value> </property> <property> <name>dfs.name.dir</name> <value>/home/hadoop/filesystem/dfs/name</value> </property> <property> <name>dfs.data.dir</name> <value>/home/hadoop/filesystem/dfs/data</value> </property> <property> <name>mapred.system.dir</name> <value>/home/hadoop/filesystem/mapred/system</value> </property> <property> <name>mapred.local.dir</name> <value>/home/hadoop/filesystem/mapred/local</value> </property> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>mapred.job.tracker.handler.count</name> <value>20</value> </property> <property> <name>mapred.map.tasks</name> <value>50</value> </property> <property> <name>mapred.reduce.tasks</name> <value>10</value> </property> </configuration> >>>サービス起動に必要な最低限の設定です。
$ ssh hdmaster $ sudo su - hadoop $ rsync --delete --progress -av hadoop hdslave1: $ rsync --delete --progress -av hadoop hdslave2: $ rsync --delete --progress -av hadoop hdclient:
$ vi /home/hadoop/rsync.sh
#!/bin/sh HOST_LIST="hdslave1, hdslave2, hdclient1" cd /home/hadoop for host in $HOST_LIST ; do rsync --delete --progress -av hadoop $host: done
$ chmod 755 /home/hadoop/rsync.sh
$ ssh hdmaster $ sudo su - hadoop $ /home/hadoop/hadoop/bin/hadoop namenode -format $ /home/hadoop/hadoop/bin/bin/start-all.shnamenodeのフォーマットはセットアップの際に1度行っておけばOKです。
$ ssh hdclient $ sudo su - hadoop $ /home/hadoop/hadoop/bin/hadoop jar hadoop-0.18.3-examples.jar sudoku src/examples/org/apache/hadoop/examples/dancing/puzzle1.dta