開発メモ#5 : Amazon Linux で knife-solo を使って chef-solo 実行

開発メモその5です。表題どおり EC2 インスタンスの Amazon Linux で knife-solo を使う話。

開発メモ#4 : EC2スナップショットとの差分は chef-solo で解決 - naoyaのはてなダイアリー で、chef-solo を使って EC2 の環境管理をしていると書きました。うち chef-solo の実行は capistrano like な perl のデプロイツール Cinnamon に任せている、という旨を述べました。

が、件のデプロイツール任せだと chef-solo 実行の度にレポジトリ経由でレシピをサーバー側に転送する必要がある。自分は github を使っているので github に push してサーバー側で fetchc される。デプロイツールがこの辺をやってくれるとは言え、レシピの動作確認のためにちゃんと動くことが保証されていないレシピをレポジトリに push する必要があって良くないなと思うようになりました。

knife-solo

chef に同梱されている chef の管理コマンド knife、そのプラグインに当たる knife-solo を使うと、ローカルで作ったレシピをリモートに sync してリモート側で chef-solo を実行してくれる。これなら github を経由しなくていい。

## 手元の OSX
# knife-solo インストール
% gem install knife-solo

# chefレポジトリを作る
% knife solo init chef-repo
% cd chef-repo

# リモートでの chef-solo 実行環境を整える
% knife solo prepare [email protected]-1

# ローカルのレシピを転送しリモートで chef-solo 実行
% knife cook [email protected]-1

なんとこれだけでございます。chef-client や chef-server を使うまでもないけど chef-solo のサーバーサイドでの実行を簡単にしたい!という状況にマッチしてますね。

・・・なのですが、残念ながら knife solo prepare と cook は Amazon Linux ではそのまま動かないのでした。

$ knife solo prepare [email protected]-1
ERROR: RuntimeError: Distro not recognized from looking at /etc/issue. Please fork https://github.com/matschaffer/knife-solo and add support for your distro.

こんな感じのエラーになる。ググラビリティのために載っけておきましょう。

2/4 20:20 追記

knife solo prepare は chef-solo が実行可能かどうかを調べて、もしそうでなければ実行可能になるよう調整する・・・ということをします。要するに、chef-solo が入ってなかったらインストールする。この時インストールされるのは Omnibus Chef Packaging というバージョンの chef で、ruby バイナリそのほか組み込みの独立で動く chef になります。

knife solo cook は Omnibus Chef Packaging で入った chef-solo の PATH なども考慮して chef-solo を実行します。

knife-solo を修正する

というわけで knife-solo を Amazon Linux でも動くようにパッチを当てます。

knife-solo のバージョンは

  • 2月4日現在 github のレポジトリはバージョン 0.2.0.pre1
  • gem install で入る stable は 0.1.0

となってますが、前者はうまく動かなかったので後者にパッチを当てて使います。git tag で v0.1.0 がついてるのでそれを拝借。

% git clone [email protected]:matschaffer/knife-solo.git
% cd knife-solo
% git checkout -b amazonlinux v0.1.0

diff は以下。要するに、/etc/issue を見てディストリビューションを判定するにあたり Amazon Linux の /etc/issue は面倒みてなかったのを、見るようにしてやるだけ。

diff --git a/lib/knife-solo/bootstraps/linux.rb b/lib/knife-solo/bootstraps/linux.rb
index a171f27..74961ac 100644
--- a/lib/knife-solo/bootstraps/linux.rb
+++ b/lib/knife-solo/bootstraps/linux.rb
@@ -104,6 +104,8 @@ module KnifeSolo::Bootstraps
         {:type => "yum_omnibus", :version => "RHEL5"}
       when %r{Scientific Linux.*? 6}
         {:type => "yum_omnibus", :version => "RHEL6"}
+      when %r{Amazon Linux}
+        {:type => "yum_omnibus", :version => "Amazon"}
       when %r{SUSE Linux Enterprise Server 1[12]}
         {:type => "omnibus", :version => "SLES11"}
       when %r{openSUSE 1[12]}

変更が済んだら、パッチ済みの knife-solo を入れる。

% rake install

これで無事 knife solo prepare が動くようになります。

EC2 で knife solo

knife solo prepare では、chef-solo の実行環境が整っているかどうかを調べてなければ chef-solo そのものをインストールするところまで面倒みてくれます。従って、knife solo prepare すれば EC2 インスタンスを立ち上げた直後から chef-solo が使える。わざわざ ssh ログインして rubygems や chef をインストールしたりする必要がない。

立ち上げてすぐ knife solo prepare & cook することで、環境構築を完全に自動化できるわけですなあ。ライフチェンジングですね。

ちょっとその様子を実践すべく、幾つか EC2 の初期環境構築を自動化してみましょう。

ところまでやってみます。

まずは knife solo init で chef レポジトリを作り、git init する。

% knife solo init chef-repo
% cd chef-repo
% git init
% git add .
% git commit -m 'first commit'

スワップ領域を作るレシピを作成しよう。この辺を参考に。

% knife cookbook create mkswap -o site-cookbooks

site-cookbooks/mkswap/receipes/default.rb は以下の感じ。

bash 'create swapfile' do
  not_if { File.exists?('/swap.img') }
  code <<-EOC
    dd if=/dev/zero of=/swap.img bs=1M count=2048 &&
    chmod 600 /swap.img
    mkswap /swap.img
  EOC
end

mount '/dev/null' do # swap file entry for fstab
  action :enable # cannot mount; only add to fstab
  device '/swap.img'
  fstype 'swap'
end

bash 'activate swap' do
  code 'swapon -ae'
end

次は yum の EPEL 有効化。レシピを自分で書いてもいいけど、ここはコミュニティで配布されてるものを使っちゃおう。knife cookbook site vendor yum で、cookbook 以下にダウンロードされる。なお、site vendor を実行するのには http://community.opscode.com/ への登録が必要。登録してプロフィールページから private key を取得して ~/.chef/naoya.pem とかに保存するべし。(保存すべきパスは ~/.chef/knife.rb に設定されてます。)

% knife cookbook site vendor yum

あとは sysstat と mosh を入れるレシピを作る。今後それ以外にも基本的なパッケージを入れるためのレシピとして拡張することも考え名前は base_packages にしました。

% knife cookbook create base_packages -o site-coookbooks

レシピは以下。簡単。

%w{sysstat mosh}.each do |pkg|
  package pkg do
    action :install
  end
 end

これでレシピは揃った。EC2 のマイクロインスタンスを立ち上げて完了したら prepare。

% knife solo prepare [email protected]-1

ちなみに過去にも言及した通り、自分は EC2 インスタンスのホスト名管理は ec2ssh を使ってます。もうこれ3回目な!

prepare すると、nodes 以下に chef-test.ap-northeast-1.json という、ホスト名をファイル名にした json ファイルができている。中身を

{
    "recipes":[
        "mkswap",
        "yum::epel",
        "base_packages"
    ]
}

と書き換え。これで準備は完了。いざ、chef-solo 実行。*1

% knife cook [email protected]-1

スワップが作られて EPEL が有効になって、sysstat や mosh が入ったはず。検証してみよう。

% mosh chef-test.ap-northeast-1
$ free
             total       used       free     shared    buffers     cached
Mem:        608740     404352     204388          0      15192     341780
-/+ buffers/cache:      47380     561360
Swap:      2097148        300    2096848
$ sar 1 1000
Linux 3.2.30-49.59.amzn1.x86_64 (ip-10-152-95-236)      2013年02月04日  _x86_64_        (1 CPU)

09時42分32秒     CPU     %user     %nice   %system   %iowait    %steal     %idle
09時42分33秒     all      0.00      0.00      0.00      1.00      0.00     99.00
09時42分34秒     all      0.00      0.00      0.00      0.00      0.00    100.0

♪上手に焼けました〜!

最後にレシピを git commit して完了です。ちなみに同手順は vagrant でも使えるので、vagrant 側で動作確認して問題なかったら EC2 に適用・・・みたいなこともできますね。vagrant についてはまた後日書きます。

てなわけで、Amazon Linux も knife-solo が疎通することがわかったので Cinnamon との連携部分を knife-solo を使うように書き換えてハッピー☆となる予定です。

*1:設定は solo.rb がデフォルトで使われます