最近サーバセットアップツールのChefを使う機会があったのでメモ。 この手のツールでは今まではPuppetがよく使われていたと思いますが、最近Chefの名前をよく聞くようになりました。
Python界隈だとFabricも聞きます。実際社内でPython使ったプロダクトはあるのでFabricを使ったセットアップスクリプトを使う機会もありますが、個人的にはFabricは記述が自由すぎて管理しにくい印象。
ちょっとしたデプロイ作業等の自動化はともかく、ミドルウェアからセットアップするようなケースでは
- Cookbook/recipeというベースの管理の方が階層構造になっていて管理しやすく分かりやすい
- roleとattributeを使うことで「ちょっと違う構成」にも簡単に対応しやすい
という点でChefを使うメリットが大きい気がしています。
で今回はChef Server/Chef Clientのクラサバ構成でAWS(Amazon Web Service)の環境の自動セットアップをやってみました。
2種類の使い方ができるChef
Chefは
- Chef Server/Clientを使ったクライアント・サーバ構成
- Chef Clientのみを使ったセットアップ
の2つがあります。
今回は前者のクラサバ構成を使っています。この構成を取るメリットはChef Serverで特定の属性を持つノードに同時にコマンドを実行することができるようになるなど、管理がやりやすくなるという点です。
Chef Serverはバックエンドの構成技術が多く(Rabbit MQ、CouhDB等)、インストールがとても面倒だという記述をちょっと前にチャレンジした方々のブログ等で拝見します。
ですが、Debian系のOSであればChefの開発元であるOpscodeのレポジトリが使えるためapt一発でインストール可能です。実際に私も15分程度でインストールは完了しました。 OpscodeのプライマリーがDebianのようで、昔からDebian系OSでのセットアップは比較的容易なようです。 ところでOpscodeの読み方はオプスコードでいいんですかね?DevOpsのオプスだよね…
まずはChef Server/Clientのインストール
以下はSoftware Design 2012年10月号に載っていたインストール手順。 この号はChef特集が組まれていて、Cyber Agentさんで実際に使われている事例なども載っていて良いです。
#パッケージレポジトリの登録
echo “deb http://apt.opscode.com/ `lsb_release -cs`-0.10 main” | tee /etc/apt/sources.list.d/opscode.list
#listの確認
cat /etc/apt/sources.list.d/opscode.list
deb http://apt.opscode.com/ precise-0.10 main
#キーの登録
mkdir -p /etc/apt/trusted.gpg.d
gpg –keyserver keys.gnupg.net –recv-keys 83EF826A
gpg –export packages@opscode.com | tee /etc/apt/trusted.gpg.d/opscode-keyring.gpg > /dev/null
apt-get update
apt-get install opscode-keyring #permanent upgradeable keyring
#システム全体のアップデート
apt-get upgrade
#クライアントの場合
apt-get install chef
#サーバの場合
apt-get install chef chef-server
#インストール中、URL of Chef Serverというプロンプトが出てくると思いますが、ここはChef ServerのURLを入力。
#ここではlocalhostのChef Serverを参照するものとして勧める
http://localhost:4000
#RabbitMQのパスワードの設定なども聞かれるが適宜入力
#インストール完了
chef-client -v
http://localhost:4040(Chef Serverをインストールした場合)にアクセスするとChef WebUIのログイン画面が表示されるはず。 インストールされる各ソフトウェアが使用するポートは以下のようになります。
- Chef Server:4000
- Chef Server WebUI:4040
- CouchDB:5984
- RabbitMQ:5672
- Chef Solr:8983
注意点
私が最初に勘違いしていたのが通信の方向についてです。
Chef Server→Chef Clientの方向にのみ通信が発生すると思っていたんですが、Chef Client→Chef Serverの方向へも通信が発生します。 Chef Clientをインストールした各ノード(ホスト)からChef Serverの4000番ポートに対して自分に適用すべきCookbook等を問い合わせに来ます。 ファイアウォールを設定している場合は注意が必要です。
knife-ec2ツールのインストール
gem install knife-ec2
# knife-ec2コマンドを使用するユーザで
cd ~/.chef/
Chef Serverから対象サーバにrecipeを適用するためには対象サーバにChef Clientがインストールされている必要があります。そもそもRubyが入っていないといけません。Chef Clientのみを使った場合、この辺はシェルスクリプトを組んで解決する必要があります。 ですがknife-ec2コマンドで立ち上げたEC2インスタンスには自動的にChef Clientがインストールされるようです。
knife-ec2でできないこと
AWSのロードバランサELB(Elastic Load Balancing)の設定 ここはknife-ec2からは操作できないようです。ですのでELBにWebサーバぶら下げたりするのはElastic Load Balancing API Toolsを直接叩いてやる必要があります。
Jenkinsから利用するスクリプト
今回JenkinsからChefを利用してEC2インスタンスを立ち上げたいケースだったので、Jenkinsの「ビルド前の処理>シェルの実行」から以下のセットアップスクリプトを呼ぶようにしています。 ビルド後のインスタンスのTerminateもスクリプトを組んでいます。
※エラー処理等してない状態です
Setupスクリプト
#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-
#ロールの決定(general|web|db)
role = ARGV[0]
if !role
role = 'general'
end
#AWSのリージョン
REGION = 'us-east-1'
#AWSのアベイラビリティーゾーン
AVAILABILITY_ZONE = 'us-east-1b'
#一般サーバ(WEB・DB共通)の設定
general_server_set = {
'role' => 'general',
'ami' => 'ami-12345',
'flavor' => 'm1.small',
'ssh_user' => 'root',
'ssh_key_file' => '~/.ssh/dev_auth.pem',
'security_group' => 'Development Servers',
'ip' => '111.111.111.111'
}
#Webサーバの設定
web_server_set = {
'role' => 'web',
'ami' => 'ami-23456',
'flavor' => 'm1.small',
'ssh_user' => 'root',
'ssh_key_file' => '~/.ssh/dev_auth.pem',
'security_group' => 'Development Servers'
}
#DBサーバの設定
db_server_set = {
'role' => 'db',
'ami' => 'ami-34567',
'flavor' => 'm1.small',
'ssh_user' => 'root',
'ssh_key_file' => '~/.ssh/dev_auth.pem',
'security_group' => 'Development Servers'
}
#設定の決定
case role
when 'general'
server_set = general_server_set
when 'web'
server_set = web_server_set
when 'db'
server_set = db_server_set
end
#instance_idを取得する
chef_setup_cmd =<<"EOS"
knife ec2 server create\
-r "role[#{server_set['role'].to_s}]"\
--region #{REGION}\
-Z #{AVAILABILITY_ZONE.to_s}\
-I #{server_set['ami'].to_s}\
-f #{server_set['flavor'].to_s}\
-x #{server_set['ssh_user'].to_s}\
-G '#{server_set['security_group'].to_s}'
EOS
chef_setup_cmd_result = `#{chef_setup_cmd}`
/Instance ID: (.*)\n/ =~chef_setup_cmd_result
instance_id = $1
if !instance_id
exit(0)
end
#EC2 API ToolsでIP割り当て
ec2_cmd = "ec2-associate-address -i " + instance_id.to_s + " " + server_set['ip'].to_s
ec2_cmd_result = `#{ec2_cmd}`
#SSHアクセスしてchef-clientコマンドを実行
if server_set['ssh_user'].to_s!='root'
add_cmd = 'sudo'
end
ssh_cmd =<<"EOS2"
/usr/bin/ssh -i #{server_set['ssh_key_file'].to_s}\
#{server_set['ssh_user'].to_s}@#{server_set['ip'].to_s}\
#{add_cmd} /usr/local/bin/chef-client
EOS2
ssh_cmd_result = `{#ssh_cmd}`
print instance_id + "\n"
print server_set['ip']
Terminateスクリプト
#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-
instance_id = ARGV[0]
if !instance_id
print 'Empty Instance ID'
exit(1)
end
ssh_cmd =<<"EOS2"
knife ec2 server delete #{instance_id} --purge
EOS2
ssh_cmd_result = `#{ssh_cmd}`
print 'Terminate Success'
Cookbookについて
ここには記載できませんが、Cookbookについては既にGithub上に公開されているものが沢山あります。
私はOpscode Public Cookbooksのものをカスタマイズして使っています。
Cent OS、RHEL、Debian、Mac OS等に対応できるような分岐がされているCookbookが殆どでひとまず動かしてみた後カスタマイズしていくのがいいんではないかと思います。
RHEL/Cent OSで実行すると、普段見るのとはちょっと違うディレクトリ構成になると思います。
例えばApacheのCookbookは設定ファイルのディレクトリ構成がDebianライクなものになります。
/etc/apache2/apache2.conf
になるとか。
そもそもCookbookの名前がhttpdじゃなくてapache2だし…
MySQLのCookbookに関してはOpenSSLのCookbookが必要など依存関係も若干あるようなので注意が必要です。
最後に
今回、Jenkinsを使ったCIの中でAWS上で自動でサーバ構築したい(ただし、AMIからEC2立てる方が速い場合もある)というニーズからChefを触り始めましたが、通常案件のサーバ構築自動化にも使えそうな気がしています。
サーバを構築する人によって当然スキルが異なるわけですが、予めサーバパフォーマンスを考えたCookbookを作成しておけばその辺も吸収できるかなと。
- Apacheのmod_*をコメントアウトしておくとか
- MySQLのmy.cnfの設定とか
- O’Reillyの「ハイパフォーマンスWebサイト」に載っているようなフロントエンド高速化どこまでやるの
とか。
最初にCookbook作るのは大変ですが、回り始めると良い循環に入りそうなので地道に進めて行きたいと思います。 おしまい。