概要
ECS上のコンテナをダウンタイム0で更新(デプロイ)する方法をまとめます。
環境
- ALB
- ECS container agent 1.13.0
- Docker 1.11.2
Amazon ECS Container Agent Versions - Amazon EC2 Container Service
ポイント
minimumHealthyPercent
とmaximumPercent
を適切に設定する- connection drainingを適切な長さにする
この2つを意識していればOKです。
minimumHealthyPercent
とmaximumPercent
を適切に設定する
desiredCount: 4、min: 0%、max: 100%の場合
この場合最低0つ(0%)まで縮小し、最高でも4つ(100%)までしか増えない状態で更新するということになります。
つまりダウンタイムが発生するので今回のrolling updateとは趣旨が異なります。
desiredCount: 4、min: 50%、max: 100%の場合
この場合最低2つ(50%)まで縮小し、最高でも4つ(100%)までしか増えない状態で更新するということになります。図にすると以下です。
全て同時に更新されるわけではなく、順々に更新されていきます。デプロイスピードは遅くなりますが、リソースの無駄が少ないです。
desiredCount: 4、min: 100%、max: 200%の場合
この場合最低でも4つ(100%)は維持し、最高8つ(200%)まで増える状態で更新するということになります。図にすると以下です。
リソースに余裕があるので一度に新しいコンテンが立ち上がり、古いコンテナと交換されます。デプロイスピードは早いですが、当然リソースをあらかじめ用意しておかないといけないので無駄があります。
connection drainingを適切な長さにする
AWSのELB、ALBにはconnection drainingという既存のリクエストの処理が完了するまでは接続を維持する。新しいリクエストは受け付けないという仕組みがあります。
これはgraceful restartにはとてもいいのですが、中々終わってくれなくてしばしば上限値(デフォルト300秒。これを過ぎたら強制的に接続を切る)まで続きます。
一般にクライアント側でもリクエストに10秒程度のタイムアウトを設けていますし、正直そこまで長くなくて良いと思うのでデプロイ速度を気にするのであればもっと小さくても大丈夫です。
rolling update
では実際にrolling updateを試してみます。以下のツールを使用します。
次のコマンドを実行するとデプロイができます。
$ ./ecs-deploy -c クラスタ名 -n サービス名 -i イメージ(docker.repo.com/doorman:latestという書き方)
新しいサービスに更新されてコンテナが更新されるまでをチェックしてくれます。デフォルトだと90秒以内に完了しないとエラーを吐くので(そのままコンテナは更新されますが)、リソースが少ない場合は-t
でタイムアウトの上限を上げたほうがいいです。
コンテナの内1つでも新しいものに更新されればこのチェックは通るので、タイムアウトはコンテナ×1台の更新時間とする必要はありません。
動作確認
以下の条件で試したところ、4分半ほどかかりました。
- インスタンス2台
- コンテナ2つ(1台に1つ)
- desiredCount: 2
- minimumHealthyPercent: 50%
- maximumPercent: 100%