Docker Swarmでのローリングアップデートの確認メモ

Swarmでもローリングアップデートは可能です。公式のドキュメントは[こちら](https://docs.docker.com/engine/swarm/swarm-tutorial/rolling-update/)です。Swarmにおけるローリングアップデートの動作を確認したいと思います。とくに気にしている点は以下の6つです。

- composeファイルを使用した場合の方法
- 旧バージョンに戻したいときはどうするか
- アップデート後、旧バージョンが残るか
- update-delayの動作
- 新旧バージョンが混在しているときのルーティング
- replicas:1の時のローリングアップデート

確認結果を先に書くと以下の通りでした。

**確認結果サマリ**

|観点|検証結果|詳細|
|-|-|-|
|composeファイルを使用した場合の方法|composeファイル内のイメージ指定を書き換えて`docker stack deploy`すれば良い。|[ここ](#普通にやってみる)|
|旧バージョンに戻したいときはどうするか|イメージ指定を再修正しcomposeファイルを再デプロイする。またはdocker service rollbackコマンドで戻す。どちらの場合も結果は同じになる。後者の場合はcomposeファイルと実機の状態に差分が出るためあまりオススメしない。|[ここ](#旧バージョンへの戻し方)|
|アップデート後、旧バージョンが残るか|タスクの履歴としては残るがコンテナとしては削除される。タスク履歴はデフォルトでは5つまで残る。|[ここ](#スタックを再デプロイ)|
|update-delayの動作|前のタスクが更新完了(Running)してから次のタスクを更新するまでの待ち時間。|[ここ](#delay)|
|新旧バージョンが混在しているときのルーティング|新旧関係なくラウンドロビンで振り分けられる。|[ここ](#新旧バージョンが混在しているときのルーティング)|
|replicas:1のときのローリングアップデート|stop-firstの場合は切り替わり時に断が発生する。start-firstの場合は切り替わり中の振り分けが新旧混在する|[ここ](#replicas1のときのローリングアップデート)|

# 検証準備

## クラスタ構成

AWSのEC2にdockerをインストールしています。dockerのバージョンは20.10.7です。EC2は全部で5台あります。マネージャ3台、ワーカー2台です。マネージャはdrainしてあるのでコンテナはスケジュールされません。クラスタを構成するノード間はポート8000の通信をSGのインバウンドで許可しています。デプロイなどの操作は基本的にマネージャで行います。

## コンテナイメージの準備

検証用のコンテナとしてcurlするとバージョンを表示するNginxのコンテナイメージを用意します。以下Dockerfileでビルドしたものです。RUNの`<バージョン>`部分を変えて`v1`と`v2`の2つのイメージをビルドします。イメージ名は`ryotamori/swarm-rollingup-nginx:<バージョン>`といった具合です。ビルドしたらdocker hubにpushしておきます。

``` dockerfile
FROM nginx:1.21
RUN echo <バージョン> > /usr/share/nginx/html/index.html
```

## テスト用composeファイルの準備

以下のシンプルなcomposeファイルを準備します。ノード間はポート8000を許可してあるのでポート8000で公開します。イメージのタグ、deployの設定、レプリカ数は検証の中で変えていきます。

``` yaml
version: "3.9"

services:
  rollingupdate:
    image: ryotamori/swarm-rollingup-nginx:v1
    deploy:
      replicas: 1
    ports:
      - 8000:80
```

上記composeファイルを以下のコマンドでデプロイします。

``` sh
$ docker stack deploy -c ./rolling-update.yaml test
```

マネージャノードで以下のようにcurlするとデプロイしたタスクにアクセスできます。

``` sh
$ curl 127.0.0.1:8000
v1
```

# 検証

## 普通にやってみる

ベースのcomposeでスタックをデプロイしている状態でイメージタグをv2に変えてデプロイしなおします。

``` sh
$ docker stack deploy -c ./rolling-update.yaml test
Updating service test_rollingupdate (id: puu48mpsds8wfveg32l9wsz93)
```

タスクを確認すると以下のように新バージョンのイメージに更新されています。

``` sh
$ docker stack ps test
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
zrpjiw85r1z1   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 2 seconds ago
ni4gahckagdu    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 4 seconds ago
```

マネージャでcurlしv2であることを確認します。

``` sh
$ curl 127.0.0.1:8000
v2
```

## 旧バージョンへの戻し方

`スタックを再デプロイ`、`service rollback`の2つの方法があります。

### スタックを再デプロイ

前のバージョンに戻したい場合はタグをv1にまた書き換えてデプロイし直せばいいです。

``` sh
$ docker stack deploy -c ./rolling-update.yaml test
Updating service test_rollingupdate (id: puu48mpsds8wfveg32l9wsz93)
```

タスクを確認します。

``` sh
$ docker stack ps test
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
tt7qhn9qcb61   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Ready           Ready 3 seconds ago
zrpjiw85r1z1    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running 3 seconds ago
ni4gahckagdu    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 3 minutes ago
```

上記のとおり、旧バージョンのタグを指定してデプロイし直してもタスク(tt7qhn9qcb61)は新しく作成されます。以前作成したv1のタスク(ni4gahckagdu)をリランさせるわけではありません。ちなみに過去のタスク履歴はデフォルトでは5つまで保存され、swarmの設定`task-history-limit`を指定することで履歴をいくつまで残すか調整可能なようです。詳しくは[こちら](https://docs.docker.com/engine/reference/commandline/swarm_update/)を確認ください。

### service rollback

[docker service rollback](https://docs.docker.com/engine/reference/commandline/service_rollback/)コマンドを使って戻すこともできます。スタックでデプロイしたservice名は`test_rollingupdate`なので以下のようにコマンドを実行します。

``` sh
$ docker service rollback test_rollingupdate
test_rollingupdate
rollback: manually requested rollback
overall progress: rolling back update: 1 out of 1 tasks
1/1: running   [>                                                  ]
verify: Service converged
```

タスクを確認します。

``` sh
$ docker stack ps test
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE             ERROR     PORTS
m8jbjkxyjcyo   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 48 seconds ago
up17gw36atzq    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 49 seconds ago
wsqqzfqrbldn    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 13 minutes ago
s5oggq0q3z7k    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 15 minutes ago
```

この場合でも[スタックを再デプロイ](#スタックを再デプロイ)の時と同じように新しくタスク(m8jbjkxyjcyo)が作成されます。ただ、このコマンドで戻した場合はcomposeの内容と実機の状態に差異ができてしまうためあまりオススメはできないやり方かなと思います。

## オプションの動作確認

composeで使えるアップデート関連のオプションは[こちら](https://docs.docker.com/compose/compose-file/compose-file-v3/#update_config)にある。

### delay

更新までの待機時間。ここで待機時間はアップデート開始(deployを実行)から10秒待つのか、次のタスクを更新するときの待ち時間なのか気になったので確認します。結論としては後者の理解で正しかったです。以下のように確認しました。

composeは以下のように書き換え、v1からデプロイします。

``` yaml
    deploy:
      replicas: 4
      update_config:
        parallelism: 1
        delay: 20s
        order: stop-first
```

この状態からスタート

``` sh
$ docker stack ps test
ID             NAME                   IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
r3nsf50a8vu3   test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 14 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 14 seconds ago
fp0xvn255jsh   test_rollingupdate.3   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 14 seconds ago
bhhu5yubm0ah   test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 14 seconds ago
```

composeのイメージタグをv2に修正してdeployする。deployする前に別ターミナルを開いておき以下コマンドで動きを観察します。

``` sh
$ for i in `seq 1000`;do date;docker stack ps test;sleep 1;done
```

すると以下のようになりました。

アップデートの開始コマンドは14時34分24秒ごろに実行しました。まず`test_rollingupdate.1`のアップデートがdeployしてすぐに開始されます。このため、`delay`はdeployしてからの待ち時間ではなくタスクごとの切り替えの待ち時間であることがわかるります。

``` 
2021年 7月 7日 水曜日 14時34分23秒 JST
ID             NAME                   IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
r3nsf50a8vu3   test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 38 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 38 seconds ago
fp0xvn255jsh   test_rollingupdate.3   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 38 seconds ago
bhhu5yubm0ah   test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 38 seconds ago
2021年 7月 7日 水曜日 14時34分25秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                    ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Ready           Ready less than a second ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running less than a second ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 40 seconds ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 40 seconds ago
bhhu5yubm0ah   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 40 seconds ago
2021年 7月 7日 水曜日 14時34分27秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Ready           Ready 2 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running 2 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 42 seconds ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 42 seconds ago
bhhu5yubm0ah   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 42 seconds ago
2021年 7月 7日 水曜日 14時34分29秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                    ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running less than a second ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 1 second ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 44 seconds ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 44 seconds ago
bhhu5yubm0ah   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 44 seconds ago
2021年 7月 7日 水曜日 14時34分31秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 2 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 3 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 46 seconds ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 46 seconds ago
bhhu5yubm0ah   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 46 seconds ago
```

14時34分25秒からアップデートが開始している。まず新しいタスクを作成し状態がReadyになる。そして旧バージョンタスクの終了が実行される。  14時34分29秒に新しいタスクの状態がReadyからRunningになったことがわかる。

それから`delay`に設定した20秒後付近の状態が以下の通り。

```
2021年 7月 7日 水曜日 14時34分48秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 19 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 20 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
bhhu5yubm0ah   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
2021年 7月 7日 水曜日 14時34分50秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 21 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 22 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
kekw7do91x4b   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Ready           Ready 1 second ago
bhhu5yubm0ah    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running 1 second ago
2021年 7月 7日 水曜日 14時34分52秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 23 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 24 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
kekw7do91x4b   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Ready           Ready 3 seconds ago
bhhu5yubm0ah    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running 3 seconds ago
2021年 7月 7日 水曜日 14時34分55秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 25 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 26 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
kekw7do91x4b   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 1 second ago
bhhu5yubm0ah    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 2 seconds ago
2021年 7月 7日 水曜日 14時34分57秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 27 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 28 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
kekw7do91x4b   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 3 seconds ago
bhhu5yubm0ah    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 4 seconds ago
```

1つ目のタスクがRunningになった20秒後(delayで設定した秒数後)の14時34分50秒から2つ目の更新が開始している。そこから1つ目と同じ様に5秒ほどたった14時34分55秒に2つ目のタスクもReadyとなったいる。

そこからさらに20秒後付近の状態が以下の通り。

```

2021年 7月 7日 水曜日 14時35分11秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 42 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 43 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
fp0xvn255jsh   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
kekw7do91x4b   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 18 seconds ago
bhhu5yubm0ah    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 19 seconds ago
2021年 7月 7日 水曜日 14時35分14秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                     ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 44 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 45 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
t5jkp52cugkk   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Ready           Assigned less than a second ago
fp0xvn255jsh    \_ test_rollingupdate.3   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running about a minute ago
kekw7do91x4b   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 20 seconds ago
bhhu5yubm0ah    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 21 seconds ago
2021年 7月 7日 水曜日 14時35分16秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                ERROR     PORTS
4g33i3q5l7ts   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 47 seconds ago
r3nsf50a8vu3    \_ test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 48 seconds ago
p6tzrv4i8mqv   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running about a minute ago
t5jkp52cugkk   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Ready           Ready 2 seconds ago
fp0xvn255jsh    \_ test_rollingupdate.3   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running 2 seconds ago
kekw7do91x4b   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 22 seconds ago
bhhu5yubm0ah    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Shutdown 23 seconds ago
```

14時35分14秒から3つ目のタスクの更新が始まっている。以下は1つ目、2つ目の動きと同じなため割愛します。

### order

`stop-first`と`start-first`があります。stop-firstは古いバージョンのタスクを停止してから新バージョンのタスクに切り替えます。start-firstは新しいバージョンのタスクを起動(Running)してから古いバージョンのタスクを消します。デフォルトは`stop-first`です。

`stop-first`の動作は[delay](#delay)で確認しました。新バージョンがReadyになり、旧バージョンをShutdownし、最後に新バージョンがRunningしてました。

`start-first`の動きもみておきます。composeは以下のように書き換え、v1からデプロイします。

``` yaml
    deploy:
      replicas: 4
      update_config:
        parallelism: 1
        delay: 20s
        order: start-first
```

結果以下の通りです。アップデートの開始コマンドは16時25分41秒ごろに実行しました。

```
2021年 7月 7日 水曜日 16時25分41秒 JST
ID             NAME                   IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
ew3lx627z3bp   test_rollingupdate.1   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 31 seconds ago
ob7zmh24jk3w   test_rollingupdate.2   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 31 seconds ago
rxzmr8uga009   test_rollingupdate.3   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 31 seconds ago
qhea8s62vw4x   test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 31 seconds ago
2021年 7月 7日 水曜日 16時25分43秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE                    ERROR     PORTS
ew3lx627z3bp   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 33 seconds ago
ob7zmh24jk3w   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 33 seconds ago
rxzmr8uga009   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 33 seconds ago
ukgow7auo1nb   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running less than a second ago
qhea8s62vw4x    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running less than a second ago
2021年 7月 7日 水曜日 16時25分45秒 JST
ID             NAME                       IMAGE                                NODE                                       DESIRED STATE   CURRENT STATE            ERROR     PORTS
ew3lx627z3bp   test_rollingupdate.1       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 36 seconds ago
ob7zmh24jk3w   test_rollingupdate.2       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 36 seconds ago
rxzmr8uga009   test_rollingupdate.3       ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 36 seconds ago
ukgow7auo1nb   test_rollingupdate.4       ryotamori/swarm-rollingup-nginx:v2   ip-10-0-1-189.us-east-2.compute.internal   Running         Running 2 seconds ago
qhea8s62vw4x    \_ test_rollingupdate.4   ryotamori/swarm-rollingup-nginx:v1   ip-10-0-1-189.us-east-2.compute.internal   Shutdown        Running 2 seconds ago
```

`test_rollingupdate.4`の新バージョンのタスクがすぐにRunningとなり、同時に旧バージョンの削除が実行されているのがわかります。切り替え時間はこっちの方が早そうですが、コンテナの起動処理を考えると`stop-first`の方が安全そうです。他のタスクの更新についてはdelay秒後に更新されるだけなので割愛します。

## 新旧バージョンが混在しているときのルーティング

たとえば[delay](#delay)の検証をした時はv1のタスクとv2のタスクが混在しています。この混在している状態でアクセスしたときにどのように振り分けられるか確認します。結果を先に書くと新旧関係なくラウンドロビンで振り分けられます。

composeファイルは[delay](#delay)の時と同じものを使用し、v1をデプロイした状態から開始します。その後、イメージタグをv2に書き換えて再デプロイし、ローリングアップデートを開始します。

マネージャで以下のようにcurlを連続で実行し、どのバージョンのタスクに接続するか確認します。

``` sh
$ for i in `seq 1000`;do date; curl 127.0.0.1:8000;sleep 1;done
```

デプロイは07:38:45ごろに実行しました。結果以下のようになりました。長いので途中割愛します。

```
2021年  7月  7日 水曜日 07:38:44 UTC
v1
2021年  7月  7日 水曜日 07:38:45 UTC
v1
2021年  7月  7日 水曜日 07:38:46 UTC
v1
2021年  7月  7日 水曜日 07:38:47 UTC
v1
2021年  7月  7日 水曜日 07:38:48 UTC
v1
2021年  7月  7日 水曜日 07:38:49 UTC
v1
2021年  7月  7日 水曜日 07:38:50 UTC
v1
2021年  7月  7日 水曜日 07:38:51 UTC
v1
2021年  7月  7日 水曜日 07:38:52 UTC
v1
2021年  7月  7日 水曜日 07:38:53 UTC
v1
2021年  7月  7日 水曜日 07:38:54 UTC
v2
2021年  7月  7日 水曜日 07:38:55 UTC
v1
2021年  7月  7日 水曜日 07:38:56 UTC
v1
2021年  7月  7日 水曜日 07:38:57 UTC
v1
2021年  7月  7日 水曜日 07:38:58 UTC
v2
2021年  7月  7日 水曜日 07:38:59 UTC
v1
2021年  7月  7日 水曜日 07:39:00 UTC
v1
2021年  7月  7日 水曜日 07:39:01 UTC
v1
...
```

デプロイした10秒後くらいの07:38:54にはv2の出力があります。その後、07:38:58にもv2が出力されています。以降、タスク数が増えるにしたがってv2の出現頻度が上がることを確認しました。新旧関係なくラウンドロビンで振り分けられています。

## replicas:1のときのローリングアップデート

少し気になったのでこれも検証しておきます。replica:1の場合、orderをstop-firstにした時とstart-firstにした時でそれぞれリクエストの失敗があるか確認します。

composeファイルは以下のような内容です。orderは検証中で修正します。

``` yaml
    deploy:
      replicas: 1
      update_config:
        order: stop-first
```

### stop-firstの場合

v1を先にデプロイしておきv2に修正したcomposeをデプロイします。

マネージャでは以下コマンドで失敗するか監視します。

``` sh
$ for i in `seq 1000`;do curl 127.0.0.1:8000;sleep 1;done
```

結果以下の通りでした。

```
v1
v1
v1
v1
v1
curl: (7) Failed to connect to 127.0.0.1 port 8000: Connection refused
curl: (7) Failed to connect to 127.0.0.1 port 8000: Connection refused
curl: (7) Failed to connect to 127.0.0.1 port 8000: Connection refused
v2
v2
v2
v2
```

更新中に3秒ほどcurlに失敗していることが確認できます。stop-firstの場合、サービス断が発生するようです。

### start-firstの場合

orderをstart-firstにして同じように確認します。

結果以下の通りでした。

```
v1
v1
v1
v1
v2
v1
v2
v2
v2
v2
```

サービス断は発生しないものの切り替わり中、新旧にリクエストが分散していることが確認できます。