consulとstretcherによるデプロイの検証

2016年3月18日

概要


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

デプロイ

Posted by GENDOSU