ここまで4回、
Capistranoを使ってItamaeを複数ホストに対して実行する
CapistranoはRubyで書かれたデプロイツールで、
まず、cap install
で初期ファイルを生成します。
$ cd itamae-repo $ bundle init # Gemfileがない場合 $ echo 'gem "capistrano"' >> Gemfile $ bundle install $ bundle exec cap install STAGES=production
config/
を以下のように修正します。itamae:apply
タスクでitamae local
が実行されるようにしています。また、itamae:apply
の前にdeploy
を実行するように指定しているので、/tmp/
にコードがデプロイされます。
set :application, ‘itamae’
set :repo_url, '[email protected]:your/itamae-repo.git'
set :deploy_to, '/tmp/itamae-repo'
# この部分はAWS EC2のAPIを呼ぶなどして、動的に定義すると良いかもしれません
role :app, [‘app-1’]
namespace :itamae do
# apply前にdeployを実行します
task :apply => [:deploy] do
# bootstrap.rbを実行します
recipe = File.join(fetch(:release_path), 'bootstrap.rb')
on roles(ENV['ROLES'].split(',')) do
# 対象ホスト側にItamaeがインストールされている必要があります
execute "itamae", "local", recipe
end
end
end
itamae:apply
タスクでItamaeを実行できます。
$ bundle exec cap production itamae:apply ROLES=app (中略) DEBUG [ed621171] Command: /usr/bin/env itamae local /tmp/itamae-repo/releases/20150927150652/bootstrap.rb DEBUG [ed621171] [0m INFO : Starting Itamae... DEBUG [ed621171] [0m DEBUG [ed621171] [0m INFO : Recipe: /tmp/itamae-repo/releases/20150927150652/bootstrap.rb DEBUG [ed621171] [0m[32m INFO : execute[echo Hello] executed will change from 'false' to 'true' DEBUG [ed621171] [0m INFO [ed621171] Finished in 0.317 seconds with exit status 0 (successful).
このように非常に簡単に複数台へのItamaeの実行が実現できます。上記の例ではitamae ssh
を使わずitamae local
を利用しています。itamae ssh
はitamae local
に比べ速度が遅いため、itamae local
は対象ホストにitamae
がインストールされている必要があるので、
もちろん、itamae ssh
を使うことも可能です。その場合はrun_
内でItamaeを実行しましょう。詳しくはCapistranoのドキュメントを参照してください。
PackerとItamaeを使ってAWS EC2用のイメージを作成する
PackerとItamaeを使ってAWS EC2のイメージ
まず、
$ wget https://dl.bintray.com/mitchellh/packer/packer_0.8.6_darwin_amd64.zip $ unzip packer_0.8.6_darwin_amd64.zip
Packerの設定ファイルを書きます。以下をubuntu.
として保存しますvpc_
、subnet_
、/path/
は環境に合わせて書き換えます)。
{
"builders": [{
"type": "amazon-ebs",
"region": "ap-northeast-1",
"source_ami": "ami-46990446",
"instance_type": "t2.micro",
"ssh_username": "ubuntu",
"ssh_timeout": "5m",
"ami_name": "ubuntu-trusty-hvm",
"vpc_id": "vpc-abcdef",
"availability_zone": "ap-northeast-1c",
"subnet_id": "subnet-abcdef",
"associate_public_ip_address": true,
"run_tags": {
"Name": "packer-tmp-ubuntu-trusty-hvm"
}
}],
"provisioners": [
{
"type": "file",
"source": "/path/to/itamae-repo",
"destination": "/tmp/itamae-repo"
},
{
"type": "shell",
"inline": [
"curl -s https://packagecloud.io/install/repositories/ryotarai/itamae/script.deb.sh | sudo bash",
"sudo apt-get install itamae",
"sudo /opt/itamae/embedded/bin/itamae local /tmp/itamae-repo/bootstrap.rb",
"sudo rm -rf /tmp/itamae-repo"
]
}
]
}
Packerの設定ファイルにはbuilders
とprovisioner
を指定する必要があり、amazon-ebs
file
Provisionerを使って、/path/
を転送しています)、itamae
コマンドを実行しています。
あとはpacker build
コマンドに上記の設定ファイルを与えれば、
$ AWS_ACCESS_KEY_ID=foo AWS_SECRET_ACCESS_KEY=bar ./packer build ubuntu.json amazon-ebs output will be in this color. ==> amazon-ebs: Prevalidating AMI Name... ==> amazon-ebs: Inspecting the source AMI... (中略) ==> amazon-ebs: Provisioning with shell script: /var/folders/tj/0g3ny7c94mq9s_2dtbzk0hbr0000gn/T/packer-shell612616353 (中略) amazon-ebs: INFO : Starting Itamae... amazon-ebs: INFO : Recipe: /tmp/itamae-repo/bootstrap.rb amazon-ebs: INFO : execute[echo Hello] executed will change from 'false' to 'true' amazon-ebs: ==> amazon-ebs: Stopping the source instance... ==> amazon-ebs: Waiting for the instance to stop... ==> amazon-ebs: Creating the AMI: ubuntu-trusty-hvm amazon-ebs: AMI: ami-abcdef ==> amazon-ebs: Waiting for AMI to become ready... ==> amazon-ebs: Terminating the source AWS instance... ==> amazon-ebs: Cleaning up any extra volumes... ==> amazon-ebs: Deleting temporary security group... ==> amazon-ebs: Deleting temporary keypair... Build 'amazon-ebs' finished. ==> Builds finished. The artifacts of successful builds are: --> amazon-ebs: AMIs were created: ap-northeast-1: ami-abcdef
ConsulのWatch機能を使ってItamaeを実行する
Capistranoを使った方法は手軽である反面、
ここでは説明を簡略化するため、
まず、
$ wget https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip $ unzip 0.5.2_linux_amd64.zip
eventを受け取ったときに実行されるスクリプトを書きます。細かい仕様などについてはドキュメントを参照してください。以下のスクリプトをitamae-apply-handler
として保存します。
#!/usr/bin/env ruby
require 'pathname'
require 'json'
require 'base64'
require 'tmpdir'
# 同じeventを2度以上処理しないように最後のeventのindexを保存しておく
index = ENV['CONSUL_INDEX']
index_file = Pathname.new('/tmp/itamae-apply-handler-last-index')
if index_file.exist? && index_file.read == index
puts "This is not a new event"
exit
end
index_file.write(index)
input = JSON.parse($stdin.read).last
payload = JSON.parse(Base64.decode64(input['Payload']))
Dir.mktmpdir do |tmpdir|
Dir.chdir(tmpdir) do
# RecipeURLで指定されたgzipped tarballをダウンロードし実行する
system("wget", "-O", "recipe.tar.gz", payload['RecipeURL']) || raise
system("tar", "xf", "recipe.tar.gz") || raise
system("/opt/itamae/embedded/bin/itamae", "local", "bootstrap.rb") || raise
end
end
上記のスクリプトでやっていることは非常にシンプルでeventで指定されたURLからレシピをダウンロードし、itamae local
を実行しています。
このスクリプトを実行可能にします。
$ chmod +x itamae-apply-handler
スクリプト内でItamaeを実行しているので、
$ curl -s https://packagecloud.io/install/repositories/ryotarai/itamae/script.deb.sh | sudo bash $ sudo apt-get install itamae
最後にevent名とhandlerのひも付ける設定ファイルを書きます。以下をconsul.
として保存します。
{
"watches": [{
"type": "event",
"name": "itamae-apply",
"handler": "/path/to/itamae-apply-handler"
}]
}
そして、
$ ./consul agent -data-dir=/tmp/consul -server -bootstrap -config-file=consul.json (中略) 2015/09/28 08:25:15 [INFO] consul: New leader elected: vagrant-ubuntu-trusty-64 2015/09/28 08:25:15 [INFO] raft: Disabling EnableSingleNode (bootstrap) 2015/09/28 08:25:15 [INFO] consul: member 'vagrant-ubuntu-trusty-64' joined, marking health alive 2015/09/28 08:25:16 [INFO] agent: Synced service 'consul'
この状態でeventを発行すると、
$ ./consul event -name itamae-apply '{"RecipeURL": "https://gist.github.com/ryotarai/b5e6a356145faeac55da/raw/recipes.tar.gz"}'
consul monitor
コマンドでログが見られます。
$ ./consul monitor -log-level=debug 2015/09/28 09:16:05 [DEBUG] consul: user event: itamae-apply 2015/09/28 09:16:05 [DEBUG] agent: new event: itamae-apply (b99e3de8-a0f7-a74a-e8b9-4b2d48b97ef2) 2015/09/28 09:16:05 [DEBUG] http: Request /v1/event/list?index=9906610952174680195&name=itamae-apply (5.003298219s) 2015/09/28 09:16:06 [DEBUG] agent: watch handler '/home/vagrant/itamae-apply-handler' output: --2015-09-28 09:16:05-- https://gist.github.com/ryotarai/b5e6a356145faeac55da/raw/recipes.tar.gz Resolving gist.github.com (gist.github.com)... 192.30.252.143 Connecting to gist.github.com (gist.github.com)|192.30.252.143|:443... connected. HTTP request sent, awaiting response... 301 Moved Permanently Location: https://gist.githubusercontent.com/ryotarai/b5e6a356145faeac55da/raw/recipes.tar.gz [following] --2015-09-28 09:16:06-- https://gist.githubusercontent.com/ryotarai/b5e6a356145faeac55da/raw/recipes.tar.gz Resolving gist.githubusercontent.com (gist.githubusercontent.com)... 103.245.222.133 Connecting to gist.githubusercontent.com (gist.githubusercontent.com)|103.245.222.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 167 [application/octet-stream] Saving to: ‘recipe.tar.gz’ 0K 100% 32.2M=0s 2015-09-28 09:16:06 (32.2 MB/s) - ‘recipe.tar.gz’ saved [167/167] INFO : Starting Itamae... INFO : Recipe: /tmp/d20150928-2975-1a7tza3/bootstrap.rb INFO : execute[echo Hello Itamae] executed will change from 'false' to 'true'
このように非常に簡単にスケーラブルなItamae実行環境が用意できます。この例はあくまで大枠を解説したものなので、
- Abort機能
途中で中止できるほうが心の平穏が保たれそうです。
- 同時実行数の制限
全台で同時に実行されると困る場合や、
リスクが大きい場合、 同時に実行できる数を制限すると良いかもしれません。 consul lock
で同時に実行できる数を制限することもできます。- ログの集約
いちいちサーバにログインする必要があるのでログを集約する必要があります。
- eventの発行元の検証
誰でもeventを発行出来てしまうので、
例えばHMACをPayloadに付加すると良いかもしれません。 - レシピをCIなどでアップロードする
Gitなどで管理しているレシピをどこかにアップロードする必要があるので、
Jenkinsなどでアップロードする必要があります。 上記の例ではHTTPのURLを指定してダウンロードしていましたが、
AWSであればS3からダウンロードするのもよいでしょう。
といったところでしょうか。規模が大きい場合このような方法も試してみてはいかがでしょうか。
まとめ
今回紹介した方法以外にもItamaeを使う手段はいろいろあります。Itamaeは非常にシンプルなツールなので環境に合わせてカスタマイズして使っていただけるかと思います。
これまで全5回、