consulとstretcherによるデプロイの検証
概要
consulのevent発行=>event watchの機能をフルに使ったデプロイになります。
event watchで起動されるデプロイツールがstretcherになります。
前提条件
オートスケーリングをする
ソースgzとかしてS3においておく
各サーバがS3からソースをダウンロードして展開する(stretcher)
オートスケーリングの仕組みは別途あるものとする
検証
consulの基本的な設定
webの場合
#/etc/consul.d/web.conf
{ "service": { "name": "nginx", "service": "nginx", "tags": [ "nginx", "unicorn" ], "port": 80, "check": { "script": "curl http://127.0.0.1:80/ > /dev/null 2>&1", "interval": "10s", "timeout": "5s" } } }
/etc/consul.d/event.conf
{ "watches": [ { "type": "event", "name": "deploy", "handler": "/usr/local/bin/stretcher" }, ] }
インスタンスの作成時
サーバの起動スクリプトに以下を仕込んでおく
/usr/local/bin/stretcher s3://example/manifest.yml
アプリのリリース時
s3にリリースするソースファイルをアップしておく
s3のmanifest.ymlを更新しておく
consul event発行
consul event -name deploy s3://example/manifest.yml
クラスタリスタートさせる場合
/etc/consul.d/web.confに定義出来る
- name
- service
- tags
の設定で頑張る事でなんとかなりそう。
具体例
/etc/consul.d/web.conf(クラスタ1のグループのサーバ)
{ "service": { "name": "nginx", "tags": [ "clustor1" ], "port": 80, "check": { "script": "curl http://127.0.0.1:80/ > /dev/null 2>&1", "interval": "10s", "timeout": "5s" } } }
/etc/consul.d/web.conf(クラスタ2のグループのサーバ)
{ "service": { "name": "nginx", "tags": [ "clustor2" ], "port": 80, "check": { "script": "curl http://127.0.0.1:80/ > /dev/null 2>&1", "interval": "10s", "timeout": "5s" } } }
クラスタ1のリスタートイベント発行
consul event -name deploy -service nginx -tag clustor1 s3://example/manifest.yml
クラスタ2のリスタートイベント発行
consul event -name deploy -service nginx -tag clustor2 s3://example/manifest.yml
1台だけ新しいソースにして動作確認する
これはサーバイメージの更新の時もありうるので
オートスケールの最低台数を+1する想定だけど
新しいmanifest-prerelease.ymlとかを作成して
/usr/local/bin/stretcher s3://example/manifest-prerelease.yml
として手で叩くでも良い。
それか、例えば、nginx.jsonに以下のような設定を入れ
サーバ1
"name": "nginx" "tags": ["clustor1", "production", "prerelease"]
サーバ2
"name": "nginx" "tags": ["clustor2", "production"]
サーバ3
"name": "nginx" "tags": ["staging"]
サーバ4
"name": "nginx" "tags": ["develop"]
consul reloadしてから
consul event -name deploy -tag prerelease
とすると、サーバ1だけにイベントが飛びます。
consul event -name deploy -tag production
とすると、サーバ1とサーバ2にイベントが飛びます。
consul event -name deploy -tag staging
とすると、サーバ3だけにイベントが飛びます。
/etc/consul.d/nginx.jsonを、直接いじりたい場合(例えば、一台だけprerelease機にしたい場合)に
直接入ってファイルをいじって、consul reloadすれば、設定が更新されます。
その後に
consul event -name deploy -service nginx tag prerelease s3://example/manifest-prerelease.yml
とすれば、1台だけリリース可能。
全台デプロイ完了の検知
全台デプロイを検知する仕組みとして
consulの持つKey/Valueの仕組みを利用すると実現可能。
手順
deployイベント発行時にデプロイスクリプトであらかじめ
curl -X DELETE http://localhost:8500/v1/kv/deploy curl -X DELETE http://localhost:8500/v1/kv/deployFailure
をしておく。
渡すmanifestファイルを以下のように
commands: pre: - echo 'staring deploy' - echo `hostname` - curl -X PUT -d 'deploy' http://localhost:8500/v1/kv/deploy/{`hostname`} post: - echo 'deploy done' - 'supervisorctl restart nginx' - curl -X DELETE http://localhost:8500/v1/kv/deploy/{`hostname`} success: - echo 'deploy success' failure: - echo 'deploy failed!!' - cat >> /root/failure.log - curl -X PUT -d 'failure' http://localhost:8500/v1/kv/deployFailure/{`hostname`}
としておく。
としておく。
デプロイ時のスクリプトなどで
consul event〜〜
発行後
curl http://localhost:8500/v1/kv/deploy/?keys
を監視。
keysがなくなれば全台デプロイ作業完了
最後に
curl http://localhost:8500/v1/kv/deployFailure/?keys
を取得し
エラーがないことをチェックしてデプロイフローの完了となる。
感想
という事で、イベントを送る先をtagsで良い感じに制御出来ればconsulとstretcherによるデプロイは良さそうな気がします。
全台デプロイ完了の検知は、consulのイベントとかステータスとかだけでやりたかった。けど、なかなか上手くいかない。
引き続き良い方法があれば調べたい。
manifest.ymlはデプロイスクリプト(capistrano?)で自動で更新されるようにしたいため、ここにhook処理が羅列されるのは嬉しくない。
ソースを固めてs3に上げてmanifest.ymlを作るという部分はまだ考慮しきれていない。
各サーバでserviceにcheckという設定(このページではconsulの基本的な設定のweb.json)を付けると、指定したチェックが通るまではserviceとしては追加されないので
ロードバランサにぶら下げるときにも
consulのヘルスチェックを見てゴニョゴニョ出来たらいいのかと思ったりしました。
補足
イベント発行のAPI
curl -X PUT -d 's3://example/manifest.yml' http://localhost:8500/v1/event/fire/deploy