Edited at

Kubernetes デプロイメント についての自習メモ (その1)

More than 1 year has passed since last update.

Kubernetesのデプロイメントについて自習したメモで、YAML先頭部分で、良く見かける kind: Deployment について自習ノートです。

apiVersion: apps/v1beta2 # for versions before 1.8.0 use apps/v1beta1

kind: Deployment


デプロイメントとは

デプロイメントは、ポッドとレプリカ・セット(次世代レプリケーションコントローラ)の宣言的な更新を提供します。 デプロイメント・オブジェクトの目的の状態を記述するだけで、デプロイメント・コントローラは、実際の状態を目的の状態へ、制御下の速度で、変更します。 デプロイメントを定義して新しいリソースを作成したり、既存のリソースを新しいものに置き換えることができます。

典型的な使用例は次のとおりです。


  • デプロイメントを作成し、レプリカセットとポッドが起動します。

  • デプロイメントの状態をチェックして、成功か否かを確認できます。

  • 実行中のデプロイメントを更新して、ポッドを再作成できます。(たとえば、新しいイメージを使用するなど)

  • 更新後のデプロイメントが安定しないケースには、以前のレビジョンにロールバックできます。

  • デプロイメントの一時停止と再開


デプロイメントの作成

デプロイメント・コントローラーは、次のYAMLを読み込んで、nginx の ポッドを3個、レプリカ・セットを作成します。


nginx-deployment.yaml

 1: apiVersion: apps/v1beta2 # for versions before 1.8.0 use apps/v1beta1

2: kind: Deployment
3: metadata:
4: name: nginx-deployment
5: labels:
6: app: nginx
7: spec:
8: replicas: 3 <--- レプリカ・セット 3個を指定
9: selector:
10: matchLabels:
11: app: nginx
12: template:
13: metadata:
14: labels:
15: app: nginx
16: spec:
17: containers:
18: - name: nginx
19: image: nginx:1.7.9 <--- コンテナのイメージを指定
20: ports:
21: - containerPort: 80


主要な項目解説


  • 一行目にAPIのバージョン指定 (注1)

  • コントローラの種別指定は、2行目 kind: Deployment

  • このデプロイメントの名前は、3行目のmetadata:の下 name:の nginx-deployment

  • デプロイメントのポッド数は、8行目replicas:で示される3つのレプリカのポッドを作成

  • 管理対象のポッドは、9行目からのapp: nginxに一致するポッド

  • ポッド・テンプレートであるメタ情報と仕様が、12行目から記述、メタ情報(metadata)には管理対象として識別するラベル、仕様(spec)には、レジストリに登録されたコンテナ・イメージの名前とタグ、外部とのポート番号の指定

(注1) IBM Cloud k8s では ver 1.8.2.1501 を利用に際しても apps/v1beta1 で提供されています。apiVersion マイナー文字列の扱いは、共通では無い様です。


デプロイメント作成の実行例

次の様にGitHubに保存された上記のYAMLファイルを指定することもできます。

$ kubectl create -f https://raw.githubusercontent.com/takara9/k8s_study/master/nginx_deploy.yaml

動作を確認してするには、get deployment のオプションで実行します。

$ kubectl get deployment

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 12s


  • NAME クラスター内のデプロイメントの名前をリストします。

  • DESIRED アプリケーションのレプリカの必要な数を表示します。これは、デプロイメントの作成時に定義します。 これが望ましい状態です。

  • CURRENT 現在実行中のレプリカの数を表示します。

  • UP-TO-DATE 希望の状態になるように更新されたレプリカの数を表示します。

  • AVAILABLE アプリケーションに使用可能なレプリカの数を表示します。

  • AGE アプリケーションが実行されている時間が表示されます。

デプロイメントの実行(ロールアウト)を確認するには、kubectl rollout status を実行します。

$ kubectl rollout status deployment nginx-deployment

deployment "nginx-deployment" successfully rolled out


デプロイメントの階層構造

デプロイメントの構成要素をkubectlコマンドで確認していきます。 NAMEフィールドに注目して追ってみてください。 デプロイメントの名前の次に、レプリカセットのID、そして次に、ポッドのIDが繋がっていることがわかります。 最下層にDockerコンテナが動作している事がわかります。


デプロイメント

$ kubectl get deployment

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 6m


レプリカセット

$ kubectl get rs

NAME DESIRED CURRENT READY AGE
nginx-deployment-569477d6d8 3 3 3 6m


ポッド

$ kubectl get pod

NAME READY STATUS RESTARTS AGE
nginx-deployment-569477d6d8-4fcgg 1/1 Running 0 6m
nginx-deployment-569477d6d8-vk69d 1/1 Running 0 6m
nginx-deployment-569477d6d8-vnz8b 1/1 Running 0 6m


コンテナ(ボッド内)

Containeters を見れば、dockerコンテナを利用している事がわかります。

$ kubectl describe pod

Name: nginx-deployment-569477d6d8-4fcgg
Namespace: default
Node: 10.132.253.17/10.132.253.17
Start Time: Thu, 14 Dec 2017 04:52:57 +0000
Labels: app=nginx
pod-template-hash=1250338284
Status: Running
IP: 172.30.170.222
Controllers: ReplicaSet/nginx-deployment-569477d6d8
Containers:
nginx:
Container ID: docker://2709b784b9fd160b658c1c7f5ec5ff79d3fb6aa739cd1922f658b77662aa2d0b
Image: nginx:1.7.9
Image ID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
Port: 80/TCP
State: Running
Started: Thu, 14 Dec 2017 04:52:59 +0000
Ready: True
Restart Count: 0


ポッド・テンプレートのラベル

--show-labelskubectl get podsに付与する事で、付与されているラベルを確認できます。

$ kubectl get pods --show-labels

NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-569477d6d8-4fcgg 1/1 Running 0 32m app=nginx,pod-template-hash=1250338284
nginx-deployment-569477d6d8-vk69d 1/1 Running 0 32m app=nginx,pod-template-hash=1250338284
nginx-deployment-569477d6d8-vnz8b 1/1 Running 0 32m app=nginx,pod-template-hash=1250338284


参考情報

The Kubernetes API

Labels and Selectors

Pod Templates


デプロイメントの更新

「k8sは、どの様にアプリの更新するのか?」と言った動作を理解する目的で、コンテナのnginx 1.7.9のイメージを`nginx 1.9.2'に更新して動作を確認します。


初期状態

初期の状態はnginx 1.7.9のコンテナで、レプリカ・セットのハッシュ 569477d6d8 でサービスが提供されています。

$ kubectl get pods --show-labels

NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-569477d6d8-4fcgg 1/1 Running 0 32m app=nginx,pod-template-hash=1250338284
nginx-deployment-569477d6d8-vk69d 1/1 Running 0 32m app=nginx,pod-template-hash=1250338284
nginx-deployment-569477d6d8-vnz8b 1/1 Running 0 32m app=nginx,pod-template-hash=1250338284


nginx 1.7.9からnginx 1.9.2への更新

コンテナ・イメージを更新する方法は 以下の三通りあります。


1.YAMLファイルを更新後に適用する

一番目の方法は、デプロイした時のYAMLを編集して、kubectl apply -f nginx-deployment.yml を実行します。

vimで編集して、1.7.9 を1.9.1にします。

16:     spec:

17: containers:
18: - name: nginx
19: image: nginx:1.7.9 -> 1.9.1 へ変更

kubectlで更新したYAMLファイルを適用します。

$ kubectl apply -f nginx-deployment.yml


2.実行中デプロイメントのYAMLを編集

二番目の方法は、kubectl edit...とする事で、稼働中のデプロイメントの定義をエディタで編集できます。エディタを保存終了すると、ただちにロールアウトが開始されます。

$ kubectl edit deployment nginx-deployment

deployment "nginx-deployment" edited

下記のはデフォルトのエディタvim で編集中の画面例です。

 31   template:

32 metadata:
33 creationTimestamp: null
34 labels:
35 app: nginx
36 spec:
37 containers:
38 - image: nginx:1.9.1
39 imagePullPolicy: IfNotPresent
40 name: nginx
41 ports:
42 - containerPort: 80
43 protocol: TCP


3.コマンドラインで目的のコンテナを指定

三番目の方法は、コマンドラインから、目的のバージョンに変更します。

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

deployment "nginx-deployment" image updated


実行結果の確認

上記のいずれの方法でも、次のコマンドで全体の動作について確認できます。

$ kubectl rollout status deployment/nginx-deployment

Waiting for rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out

ロールアウトが完了した後に、ポッドのレベルで確認すると、レプリカ・セット、ポッドのハッシュ値が全て変更されており、デプロイメントの中身が全て入れ替わった事が判ります。

$ kubectl get pods --show-labels

NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-6bd4859cdb-2kpnl 1/1 Running 0 27s app=nginx,pod-template-hash=2680415786
nginx-deployment-6bd4859cdb-mdx4q 1/1 Running 0 32s app=nginx,pod-template-hash=2680415786
nginx-deployment-6bd4859cdb-mg5f5 1/1 Running 0 45s app=nginx,pod-template-hash=2680415786


ロールアウト中の動作

現行でサービスしているサービスの新バージョンをリリースする際のk8sの動きを確認してみます。

具体的には、以下の様にイメージのweb:v1からweb:v2へバージョンをアップします。


nginx-web1.yml

    14      spec:

15 containers:
16 - name: nginx
17 image: registry.ng.bluemix.net/takara/web:v1


nginx-web2.yml

    14      spec:

15 containers:
16 - name: nginx
17 image: registry.ng.bluemix.net/takara/web:v2


初期状態

3個のポッドを持つweb:v1のデプロイメントが稼働しています。 この状態からweb:v2へロールオーバーします。

$ kubectl get deploy

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-web-deployment 3 3 3 3 10m

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-7fkk7 1/1 Running 0 10m
nginx-web-deployment-765656d945-fjt7w 1/1 Running 0 10m
nginx-web-deployment-765656d945-g6zbd 1/1 Running 0 10m


Web:v2へ更新の開始

web:v2のイメージを記述したnginx-web2.ymlを適用して、ロールオーバーを開始します。

$ kubectl apply -f nginx-web2.yml

deployment "nginx-web-deployment" configured


Web:v1からWeb:v2へ切替り進行中

web:v1のレプリカ・セットは 765656d945 で、二つが稼働を続けています。

web:v2のレプリカ・セットが b6fd9b64b として作られています。

$ kubectl get pods

NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-7fkk7 1/1 Terminating 0 11m
nginx-web-deployment-765656d945-fjt7w 1/1 Running 0 11m
nginx-web-deployment-765656d945-g6zbd 1/1 Running 0 11m
nginx-web-deployment-b6fd9b64b-kf2hp 0/1 ContainerCreating 0 3s
nginx-web-deployment-b6fd9b64b-x7ckc 0/1 ContainerCreating 0 3s

web:v2のレプリカ・セットの2ポッドが稼働した処で、アプリのバージョンアップは完了です。そして、web:v1が全数終了となります。

$ kubectl get pods

NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-7fkk7 0/1 Terminating 0 11m
nginx-web-deployment-765656d945-fjt7w 0/1 Terminating 0 11m
nginx-web-deployment-765656d945-g6zbd 0/1 Terminating 0 11m
nginx-web-deployment-b6fd9b64b-kf2hp 1/1 Running 0 5s
nginx-web-deployment-b6fd9b64b-wp995 0/1 ContainerCreating 0 2s
nginx-web-deployment-b6fd9b64b-x7ckc 1/1 Running 0 5s

web:v2の3個目が起動しました。

$ kubectl get pods

NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-7fkk7 0/1 Terminating 0 11m
nginx-web-deployment-765656d945-fjt7w 0/1 Terminating 0 11m
nginx-web-deployment-765656d945-g6zbd 0/1 Terminating 0 11m
nginx-web-deployment-b6fd9b64b-kf2hp 1/1 Running 0 9s
nginx-web-deployment-b6fd9b64b-wp995 1/1 Running 0 6s
nginx-web-deployment-b6fd9b64b-x7ckc 1/1 Running 0 9s

web:v1のクリーンナップ進行中

$ kubectl get pods

NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-fjt7w 0/1 Terminating 0 11m
nginx-web-deployment-b6fd9b64b-kf2hp 1/1 Running 0 15s
nginx-web-deployment-b6fd9b64b-wp995 1/1 Running 0 12s
nginx-web-deployment-b6fd9b64b-x7ckc 1/1 Running 0 15s

切り替えのプロセスは完了です。

$ kubectl get pods

NAME READY STATUS RESTARTS AGE
nginx-web-deployment-b6fd9b64b-kf2hp 1/1 Running 0 18s
nginx-web-deployment-b6fd9b64b-wp995 1/1 Running 0 15s
nginx-web-deployment-b6fd9b64b-x7ckc 1/1 Running 0 18s

参考資料

Perform Rolling Update Using a Replication Controller


ストラテジー

前述の過渡期状態での web:v1 のポッドの減少とweb:v2のポッドの増加は、RollingUpdateStrategy で定められた値にもとずいて制御されています。

$ kubectl describe deploy

Name: nginx-web-deployment
Namespace: default
CreationTimestamp: Thu, 14 Dec 2017 11:00:49 +0000
Labels: app=nginx
Selector: app=nginx
Replicas: 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-web-deployment-b6fd9b64b (3/3 replicas created)
<以下省略>

移行中のポッドの数の制御は、RollingUpdateStrategy に指定してあり、1 max unavailableによって、レプリカのポッドの内で停止状態のポッドは1個に制限されています。そして、最大1個のサージ1 max surgeが指定されており、上記の例では判りませんが、ポッドの同時稼働数の超過数は、最大1個に制限されています。

上記のデプロイメントを詳しく見ると、最初に新しいポッドを作成した後、古いポッドをいくつか削除して新しいポッドを作成したことがわかります。十分な数の新しいポッドが登場するまで古いポッドを止めることはありません。十分な数の古いポッドが止められるまで、新しいポッドは作成されません。利用可能なポッドの数が2以上で、ポッドの総数が最大で4であることを確認します。

以下は、kubectl describe deployのEventsパートを理解に必要な部分だけに編集したものです。このイベントの記録では、最初に新しいポッド1個を開始しています。ここでWeb:v1の3個の稼働中ポッドと、最初に起動したWeb:v2ポッドの合わせて4個が稼働しており、サージ数の最大1個を守っている事が判ります。


つづき

Events:

From Reason Message
----- ------ -------
{deployment-controller } ScalingReplicaSet Scaled up replica set nginx-web-deployment-b6fd9b64b to 1
{deployment-controller } ScalingReplicaSet Scaled down replica set nginx-web-deployment-765656d945 to 2
{deployment-controller } ScalingReplicaSet Scaled up replica set nginx-web-deployment-b6fd9b64b to 2
{deployment-controller } ScalingReplicaSet Scaled down replica set nginx-web-deployment-765656d945 to 1
{deployment-controller } ScalingReplicaSet Scaled up replica set nginx-web-deployment-b6fd9b64b to 3
{deployment-controller } ScalingReplicaSet Scaled down replica set nginx-web-deployment-765656d945 to 0


kubectl rolling update とデプロイメントの比較

kubectl rolling updateは、Podと ReplicationControllersで、同様の更新を実行します。 しかし、デプロイメントは、サーバーサイドで宣言的であり、ローリング・アップデートが完了した後でも以前のリビジョンにロールバックするなどの優れた機能がありますので、デプロイメントを利用するのが良いと思います。


ロールオーバー

ロールオーバーとは、サービス提供中のバージョンを次のバージョンへの切り替えるロールアウト推進中に、さらに被せる様に、その次のリリース要求する、複数の更新を要求するケースを指しています。 スマートフォンのアプリでは同時接続のクライアント数が多いため、アプリサーバー数が100台くらい存在するケースがあります。 そうすると、新バージョンへのリリースで、稼働中のセッションを維持しながら移行を想定すると、それなりの時間を要します。新バージョンのリリースを進めている最中に、問題修正版のリリースが必要となり、実行に移した場合に、Kubernetesは、素晴らしい働きをしてくれます。 その動作を実際に実験した結果で見て行きます。

実験では、Web:v1、Web:v2、Web:v3 のバージョンがあります。 Web:v1を本番提供中に、Web:v2へロールアウトを進めている最中に、Web:v3をロールオーバーします。

内部の動作では、Web:v2のレプリカ・セットをポッドを増やし、Web:v1のレプリカ・セットのポッドを減らす作業の進行中に、Web:v3のレプリカ・セットを増やす動作を要求するものとなります。 この場合、デプロイメント・コントローラーは、Web:v2の移行を待たずに、Web:v1を終了させてWeb:v3へ移行を進め始めます。 既に起動を開始した Web:v2のポッドを終了させて行きます。 それでは、実際の動作を確認します。


初期状態 Web:v1

初期の状態では、デプロイメントのレプリカセットの全てのポッドがWeb:v1の状態です。 ここで、Web:v1のレプリカセットのハッシュ値 765656d945 として識別する事ができます。

NAME                                    READY     STATUS    RESTARTS   AGE

nginx-web-deployment-765656d945-9g8ks 1/1 Running 0 14s
nginx-web-deployment-765656d945-b44mt 1/1 Running 0 14s
nginx-web-deployment-765656d945-j9bft 1/1 Running 0 14s
nginx-web-deployment-765656d945-jvccm 1/1 Running 0 14s
nginx-web-deployment-765656d945-p69qx 1/1 Running 0 14s
nginx-web-deployment-765656d945-p6v6d 1/1 Running 0 14s
nginx-web-deployment-765656d945-p8l7l 1/1 Running 0 14s
nginx-web-deployment-765656d945-qm4s7 1/1 Running 0 14s
nginx-web-deployment-765656d945-s2ljf 1/1 Running 0 14s
nginx-web-deployment-765656d945-t742l 1/1 Running 0 14s


ロールアウト中 Web:v1 -> Web:v2

以下は、Web:v2のロールアウトを要求した直後の状態です。 Web:v2のハッシュ値 b6fd9b64b のポッドが増加して、Web:v1のハッシュ値 765656d945のポッドが減っているのが見て判ります。何もなければ、全数がWeb:v2へ切り替わるはずです。

NAME                                    READY     STATUS        RESTARTS   AGE

nginx-web-deployment-765656d945-9g8ks 1/1 Terminating 0 19s
nginx-web-deployment-765656d945-b44mt 1/1 Running 0 19s
nginx-web-deployment-765656d945-j9bft 0/1 Terminating 0 19s
nginx-web-deployment-765656d945-jvccm 1/1 Running 0 19s
nginx-web-deployment-765656d945-p69qx 1/1 Terminating 0 19s
nginx-web-deployment-765656d945-p6v6d 1/1 Running 0 19s
nginx-web-deployment-765656d945-p8l7l 1/1 Terminating 0 19s
nginx-web-deployment-765656d945-qm4s7 0/1 Terminating 0 19s
nginx-web-deployment-765656d945-s2ljf 1/1 Running 0 19s
nginx-web-deployment-765656d945-t742l 1/1 Running 0 19s
nginx-web-deployment-b6fd9b64b-7qqg7 0/1 Pending 0 0s
nginx-web-deployment-b6fd9b64b-pgj4s 0/1 Pending 0 0s
nginx-web-deployment-b6fd9b64b-rccl5 1/1 Running 0 3s
nginx-web-deployment-b6fd9b64b-rmfwk 1/1 Running 0 3s
nginx-web-deployment-b6fd9b64b-tz2tv 1/1 Running 0 5s
nginx-web-deployment-b6fd9b64b-wht4l 1/1 Running 0 5s


ロールオーバー要求 (Web:v3のロールアウトを投入)

ここでv2に問題が発見され、一瞬のうちに対策版コンテナのv3のビルドが仕上がって、Web:v3のロールアウトを要求した。というちょっと有り得ないかもしれない様なストーリが展開したとして、Web:v3 のレプリカ・セット(758c4bbc7f)のロールオーバーの開始直後の状況が以下になります。

Web:v1、Web:v2、Web:v3の三世代が同時に存在しています。Running中のポッドが9個で、停止数が1個、RunningとContainerCreatingのポッドの総数は11個で、サージ数は1個となっており、RollingUpdateStrategyの規定数を維持しながら、ロールオーバーが進んでいます。Web:v2 b6fd9b64b も既に終了が始まっています。

NAME                                    READY     STATUS              RESTARTS   AGE

nginx-web-deployment-758c4bbc7f-m9vqs 0/1 ContainerCreating 0 0s
nginx-web-deployment-758c4bbc7f-zg6qh 0/1 ContainerCreating 0 0s
nginx-web-deployment-765656d945-9g8ks 1/1 Terminating 0 23s
nginx-web-deployment-765656d945-b44mt 1/1 Running 0 23s
nginx-web-deployment-765656d945-j9bft 0/1 Terminating 0 23s
nginx-web-deployment-765656d945-jvccm 1/1 Running 0 23s
nginx-web-deployment-765656d945-p69qx 1/1 Terminating 0 23s
nginx-web-deployment-765656d945-p6v6d 1/1 Running 0 23s
nginx-web-deployment-765656d945-p8l7l 1/1 Terminating 0 23s
nginx-web-deployment-765656d945-qm4s7 0/1 Terminating 0 23s
nginx-web-deployment-765656d945-s2ljf 1/1 Running 0 23s
nginx-web-deployment-765656d945-t742l 1/1 Running 0 23s
nginx-web-deployment-b6fd9b64b-7qqg7 0/1 Terminating 0 4s
nginx-web-deployment-b6fd9b64b-pgj4s 0/1 Terminating 0 4s
nginx-web-deployment-b6fd9b64b-rccl5 1/1 Running 0 7s
nginx-web-deployment-b6fd9b64b-rmfwk 1/1 Running 0 7s
nginx-web-deployment-b6fd9b64b-tz2tv 1/1 Running 0 9s
nginx-web-deployment-b6fd9b64b-wht4l 1/1 Running 0 9s


ロールオーバー中 Web:v3

Web:v2は全て終了して、クリーンナップが進んでいます。 一番多く稼働しているボッドは、Web:v3のものとなっています。

NAME                                    READY     STATUS              RESTARTS   AGE

nginx-web-deployment-758c4bbc7f-8zps4 1/1 Running 0 10s
nginx-web-deployment-758c4bbc7f-d4ln5 1/1 Running 0 21s
nginx-web-deployment-758c4bbc7f-m9vqs 1/1 Running 0 23s
nginx-web-deployment-758c4bbc7f-nspbm 1/1 Running 0 9s
nginx-web-deployment-758c4bbc7f-rc2v6 1/1 Running 0 8s
nginx-web-deployment-758c4bbc7f-rzwv5 1/1 Running 0 21s
nginx-web-deployment-758c4bbc7f-sff26 0/1 ContainerCreating 0 6s
nginx-web-deployment-758c4bbc7f-snb6w 1/1 Running 0 17s
nginx-web-deployment-758c4bbc7f-vw5nb 1/1 Running 0 11s
nginx-web-deployment-758c4bbc7f-zg6qh 1/1 Running 0 23s
nginx-web-deployment-765656d945-s2ljf 0/1 Terminating 0 46s
nginx-web-deployment-b6fd9b64b-rccl5 0/1 Terminating 0 30s
nginx-web-deployment-b6fd9b64b-tz2tv 0/1 Terminating 0 32s
nginx-web-deployment-b6fd9b64b-wht4l 1/1 Terminating 0 32s


ロールオーバー完了 Web:v3

Web:v3のロールアウトが完了した状態です。

NAME                                    READY     STATUS    RESTARTS   AGE

nginx-web-deployment-758c4bbc7f-8zps4 1/1 Running 0 21s
nginx-web-deployment-758c4bbc7f-d4ln5 1/1 Running 0 32s
nginx-web-deployment-758c4bbc7f-m9vqs 1/1 Running 0 34s
nginx-web-deployment-758c4bbc7f-nspbm 1/1 Running 0 20s
nginx-web-deployment-758c4bbc7f-rc2v6 1/1 Running 0 19s
nginx-web-deployment-758c4bbc7f-rzwv5 1/1 Running 0 32s
nginx-web-deployment-758c4bbc7f-sff26 1/1 Running 0 17s
nginx-web-deployment-758c4bbc7f-snb6w 1/1 Running 0 28s
nginx-web-deployment-758c4bbc7f-vw5nb 1/1 Running 0 22s
nginx-web-deployment-758c4bbc7f-zg6qh 1/1 Running 0 34s

レプリカ・セットを表示すると、クリーンナップされたもの含めて、全体を把握する事ができます。

$ kubectl get rs

NAME DESIRED CURRENT READY AGE
nginx-web-deployment-758c4bbc7f 10 10 10 1h
nginx-web-deployment-765656d945 0 0 0 1h
nginx-web-deployment-b6fd9b64b 0 0 0 1h

この機能はk8sの有用性を最も顕著に示すものと思います。大規模なシステムでアプリのリリースで苦労した経験を持った者であれば、この機能の素晴らしさが理解できると思います。 しかし、ロードバランサーとの関係やコンテナ内のアプリ設計に注意を払う必要がありますので、後述したいと思います。


ローリング・アップデートの調整機能

RollingUpdate Deploymentsは、複数のバージョンのアプリケーションを同時に実行することをサポートします。 あなたまたはオートスケーラがロールアウト中(進行中または一時停止中)にあるRollingUpdate Deploymentの規模を調整すると、Deployment Controllerは既存のアクティブなReplicaSets(ReplicaSets with Pods)の追加のバランスを取ってリスクを軽減します。

たとえば、replicas = 10、maxSurge = 3、および maxUnavailable = 2 を使用してデプロイメントを実行しているとします。


nginx-web6.yml

  1 apiVersion: extensions/v1beta1

2 kind: Deployment
3 metadata:
4 name: nginx-web-deployment
5 spec:
6 replicas: 10
7 selector:
8 matchLabels:
9 app: nginx
10 strategy:
11 rollingUpdate: <--- ここからの条件に注意
12 maxSurge: 3
13 maxUnavailable: 2
14 type: RollingUpdate
15 template:
16 metadata:
17 labels:
18 app: nginx
19 spec:
20 containers:
21 - name: nginx
22 image: registry.ng.bluemix.net/takara/web:v1
23 ports:
24 - containerPort: 80

下記 kubectl create -f nginx-web6.yml を実行して、アプリが稼働している状態です。

NAME                              DESIRED   CURRENT   READY     AGE

nginx-web-deployment-6798cb747c 10 10 10 19s

ここで、Web:v2を適用します。

$ kubectl create -f nginx-web7.yml 

deployment "nginx-web-deployment" created

maxUnavailable = 2 の条件により、 6798cb747c のレプリカ・セットは、2個減らす事ができます。 maxSurge = 3 の条件により、全体で13個までのポッドが許されているので、67bcffb8b6 の要求数(DESIRED) を 5 にします。

NAME                              DESIRED   CURRENT   READY     AGE

nginx-web-deployment-6798cb747c 8 8 8 22s
nginx-web-deployment-67bcffb8b6 5 5 0 0s

次に、67bcffb8b6 のレプリカ・セットの数を増やし、maxUnavailable = 2 の条件をキープしながらローリング・アップデートを推進していきます。

NAME                              DESIRED   CURRENT   READY     AGE

nginx-web-deployment-6798cb747c 5 5 5 25s
nginx-web-deployment-67bcffb8b6 8 8 3 3s

6798cb747cの DESIREDを1づつ減らし、対応して 67bcffb8b6 のDESIREDを増やし、最終的にREADYが10となったら、ローリング・アップデートを完了します。

NAME                              DESIRED   CURRENT   READY     AGE

nginx-web-deployment-6798cb747c 0 0 0 42s
nginx-web-deployment-67bcffb8b6 10 10 10 20s


ロールバック

何らかの理由があって、デプロイしたアプリを前のバージョンに戻す(ロールバック)ケースの動作です。


一つ前のバージョンに戻す

前述からの続きで、以下は、Web:v3にロールアウトが完了した状態です。 これから、一つ前のWeb:v2にロールバックしてみます。

$ kubectl get rs

NAME DESIRED CURRENT READY AGE
nginx-web-deployment-758c4bbc7f 10 10 10 1h
nginx-web-deployment-765656d945 0 0 0 1h
nginx-web-deployment-b6fd9b64b 0 0 0 1h

前のバージョン Web:v2にロールバックを開始するコマンド kubectl rollout undo deploymentを投入します。

$ kubectl rollout undo deployment nginx-web-deployment

deployment "nginx-web-deployment" rolled back

ロールバックコマンド投入直後の状態です。 Web:v3(758c4bbc7f)のポッドは減らされて、Web:v2(b6fd9b64b)のポッドが増えているのが解ります。

$ kubectl get rs

NAME DESIRED CURRENT READY AGE
nginx-web-deployment-758c4bbc7f 7 7 7 1h
nginx-web-deployment-765656d945 0 0 0 1h
nginx-web-deployment-b6fd9b64b 4 4 2 1h

少し時間が経過すると、すべてのポッドがWeb:v2(b6fd9b64b)にロールバックされました。

$ kubectl get rs

NAME DESIRED CURRENT READY AGE
nginx-web-deployment-758c4bbc7f 0 0 0 1h
nginx-web-deployment-765656d945 0 0 0 1h
nginx-web-deployment-b6fd9b64b 10 10 10 1h

こんなに簡単にリリースしたアプリをロールバックできるk8sのデプロイメント・コントローラに感動してしまいました。


リリース失敗のロールバック

リリースを緊急で戻したいケースがあります。 例えば、コンテナが安定せず、リスタートを繰り返す、コンテナイメージの名前のタイプミスや、レジストリへの登録ミスなどにより、ロールアウトが成功しないケースです。 この様な問題に対して、デプロイメント・コントローラの振る舞いと対処方法について確かめていきます。

次のコマンドで、Web:v4 のリリースをロールアウトします。 しかし、Web:v4 のコンテナ・イメージは、レジストリに別の名前で登録されており、コンテナをプルできないという状態に陥ります。

$ kubectl apply -f nginx-web4.yml

deployment "nginx-web-deployment" configured

次のコマンドで、ロールアウトの状態を確認します。 2個の失敗、完了待ちとのメッセージです。

$ kubectl rollout status deployment nginx-web-deployment

Waiting for rollout to finish: 2 out of 10 new replicas have been updated...

コマンドをコントロール Cで止めて、次のコマンドで、レプリカ・セットの状態を確認します。 そうすると、Web:v4(7598f5987b)のレプリカ・セットが、2個起動しており、READYになっていない状態である事が判ります。 そして、Web:v2(b6fd9b64b)は、1個減らされています。 このポッド数は、RollingUpdateStrategyのデフォルトの値によって制御されています。

$ kubectl get rs

NAME DESIRED CURRENT READY AGE
nginx-web-deployment-758c4bbc7f 0 0 0 9h
nginx-web-deployment-7598f5987b 2 2 0 3m
nginx-web-deployment-765656d945 0 0 0 9h
nginx-web-deployment-b6fd9b64b 9 9 9 9h

次にポッドの状態を確認します。 Web:v4のレプリカ・セット 7598f5987b のポッドが起動せず、ImagePullBackOffの状態、すなわち、レジストリからイメージをプル(ダウンロード)に失敗して、Back off つまり 中断している状態である事が判ります。

$ kubectl get pods

NAME READY STATUS RESTARTS AGE
nginx-web-deployment-7598f5987b-pk87t 0/1 ImagePullBackOff 0 4m
nginx-web-deployment-7598f5987b-z5t8h 0/1 ImagePullBackOff 0 4m
nginx-web-deployment-b6fd9b64b-4s2v9 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-ffmdk 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-h544r 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-hf44d 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-kp8x5 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-rzmst 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-s9swt 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-wxjf7 1/1 Running 0 7h
nginx-web-deployment-b6fd9b64b-x696f 1/1 Running 0 7h

ここで、ロールバックを実行します。

$ kubectl rollout undo deployment nginx-web-deployment

deployment "nginx-web-deployment" rolled back

レプリカセットを確認すると、Web:v2 へロールバックされた事が読み取れます。

$ kubectl get rs

NAME DESIRED CURRENT READY AGE
nginx-web-deployment-758c4bbc7f 0 0 0 9h
nginx-web-deployment-7598f5987b 0 0 0 5m
nginx-web-deployment-765656d945 0 0 0 9h
nginx-web-deployment-b6fd9b64b 10 10 10 9h

デプロイメント・コントローラには、起動できないデプロイメントが、誤ってリリースされても、サービスの全滅を防止する機能があり、コマンド一つでロールバックする事がきます。


クラッシュ・ループのケース

コンテナ・イメージのプル(ダウンロード)で失敗するケースを見ましたが、コンテナが起動直後にクラッシュするケースを以下に示します。 フェール・セーフの機能が働いている事が解りますね。

$ kubectl apply -f nginx-web5.yml 

deployment "nginx-web-deployment" configured

$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-web-deployment-69c86977bf 2 2 0 5s
nginx-web-deployment-758c4bbc7f 0 0 0 11h
nginx-web-deployment-7598f5987b 0 0 0 1h
nginx-web-deployment-765656d945 0 0 0 11h
nginx-web-deployment-b6fd9b64b 9 9 9 11h

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-69c86977bf-fsklh 0/1 CrashLoopBackOff 1 15s
nginx-web-deployment-69c86977bf-xhjdr 0/1 CrashLoopBackOff 1 15s
nginx-web-deployment-b6fd9b64b-4s2v9 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-ffmdk 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-h544r 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-hf44d 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-kp8x5 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-rzmst 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-s9swt 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-wxjf7 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-x696f 1/1 Running 0 9h

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-69c86977bf-fsklh 0/1 CrashLoopBackOff 6 8m
nginx-web-deployment-69c86977bf-xhjdr 0/1 CrashLoopBackOff 6 8m
nginx-web-deployment-b6fd9b64b-4s2v9 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-ffmdk 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-h544r 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-hf44d 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-kp8x5 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-rzmst 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-s9swt 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-wxjf7 1/1 Running 0 9h
nginx-web-deployment-b6fd9b64b-x696f 1/1 Running 0 9h

この状態から、ロールバックすることで、失敗したリリースを取り消す事ができます。


レビジョンを指定してのロールバック

kubectl apply -f nginx-web2.yml --recordの様にコマンドのフラグとして--recordを追加することで、過去にリリースしたレビジョン(改定)の履歴を記録してくれます。 このレビジョンを指定してロールバックもできます。

$ kubectl rollout history deployment nginx-web-deployment

deployments "nginx-web-deployment"
REVISION CHANGE-CAUSE
1 kubectl create -f nginx-web1.yml --record
2 kubectl apply -f nginx-web2.yml --record
4 kubectl apply -f nginx-web4.yml --record
5 kubectl apply -f nginx-web3.yml --record

例として、2番目のレビジョンに戻すには、--to-revision=2を付与します。

$ kubectl rollout undo deployment nginx-web-deployment --to-revision=2

その2へ続きます。


参考資料