SE(しがないエンジニア)のブログ

IT技術ネタ(クラウド・セキュリティ周り)が中心です!他雑記(お馬さん 他いろいろ)もあり。

Kubernetes(AKS)をやさしく学ぶ旅 その8

アプリケーションのデプロイの観点から

Kubernetes には流行りの CI / CD を実現する上で重要なデプロイの機能を備えています。今までにキーワードとしては出ていないですがデプロイを管理する「Deployment」が便利です。

アプリケーションのバージョンアップの考え方として、「より安全(テスト済)に、より迅速に。」が重要です。そんな中でデプロイする手法として代表的なものは以下のようなものです。

ローリングアップデート

アプリケーションのバージョンアップの際にまとめて一気に変更せず、稼働状態を保ちながら少しずつ順繰り更新する方法です。ちなみに、更新中は新旧のアプリケーションが混在するため、ローリングアップデートに対応した仕組みになっている必要があります。

ブルー/グリーンデプロイメント

バージョンが異なる新旧2つのアプリケーションを同時に動作させておき、ネットワークの設定を変更して対応する方法です。ブルー(旧)とグリーン(新)を切り替えることからそう呼ばれます。

ブルーを本番としてグリーン側で機能追加したものでテストし確認できた上で切り替えます。万が一、アプリケーションに障害があってもブルーに切り戻せることがメリットです。

その他キーワードとして一部利用者のみに新機能を開放して問題ないことを確認した上で残りを大規模展開することを「カナリアリリース」といいます。

Deployment とは?

その5 でスケジューリングの話をチラッとしましたが、Pod をどの Node に配置するかはこのスケジューリングで実現します。クラスター上の Pod はラベルによって管理されており、バージョンアップの際にそのアクセスする Pod を変える、という制御を管理するのが Deployment になります。

ちなみに、Pod や ReplicaSet は履歴の概念がないのでリリース後に変更のないアプリケーションを管理するのに適しています。Deployment の場合は履歴の概念があります。すなわち、、

➡ Pod のロールアウトやロールバックができる

➡ ロールアウトの方式を指定したり条件や速度を決められる

アプリケーションの世界では一般的に「作成したらそれで終わり!」というものが基本は少ないため、Deployment の積極利用が勧められます。

ここからハンズオン

Deployment 用のマニフェストファイルを準備し進める形となります。

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.15/#deployment-v1-apps

xxx > kubectl apply -f Deployment/nginx-deployment.yaml
deployment.apps/nginx-deployment created
xxx > kubectl get deploy
NAME               READY     UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3       3            3           21s

Deployment の作成と共に自動的に ReplicaSet と Pod もできあがるようです。

xxx > kubectl get replicaset,pod
NAME                                                DESIRED   CURRENT   READY     AGE
replicaset.extensions/nginx-deployment-789d949f8b   3         3         3         3m21s

NAME                                    READY     STATUS    RESTARTS   AGE
pod/nginx-deployment-789d949f8b-cq9mv   1/1       Running   0          3m21s
pod/nginx-deployment-789d949f8b-hq4pg   1/1       Running   0          3m21s
pod/nginx-deployment-789d949f8b-xbpf7   1/1       Running   0          3m21s

Deployment 名を元に ReplicaSet と Pod の名称がつけられていることが分かります。

xxx > kubectl describe deploy nginx-deployment
(略)
OldReplicaSets:  
NewReplicaSet:   nginx-deployment-789d949f8b (3/3 replicas created)
(略)

この詳細を確認するコマンド実行結果を見ると上記2つで履歴をとっていることが分かります。次に一度 apply したファイルの中身 [spec] - [template] - [spec] - [containers] - [image] の行を変更します。

xxx > kubectl apply -f Deployment/nginx-deployment.yaml
deployment.apps/nginx-deployment configured
xxx > kubectl describe deploy nginx-deployment
(略)
OldReplicaSets:  nginx-deployment-789d949f8b (1/1 replicas created)
NewReplicaSet:   nginx-deployment-69fdb6677 (3/3 replicas created)
(略)

再度 apply した上で確認すると、変化の途中を捉えたものですが、「789~~」が「69f~~」になっています。

xxx > kubectl get replicaset --output=wide
NAME                          DESIRED   CURRENT   READY     AGE       CONTAINERS   IMAGES       SELECTOR
nginx-deployment-69fdb6677    3         3         3         7m26s     nginx        nginx:1.15   app=nginx-pod,pod-template-hash=69fdb6677
nginx-deployment-789d949f8b   0         0         0         21m       nginx        nginx:1.14   app=nginx-pod,pod-template-hash=789d949f8b

Deployment の場合は内部で ReplicaSet の履歴を持っており、Label 確認コマンドを実行すると「pod-template-hash」というのを持っていることが分かります。ここでお馴染みの delete を発行します。

xxx > kubectl delete -f Deployment/nginx-deployment.yaml
deployment.apps "nginx-deployment" deleted
xxx > kubectl get pod,replicaset,deploy
No resources found.

Deployment の削除と共に紐付いている ReplicaSet や Pod も削除されることが上記で分かります。

Deployment のしくみ

Kubernetes では大分類として2つのアップデート方式があります。

1つ目は「Recreate」方式で旧 Pod を全停止した上で新 Pod をその名の通り再作成する方法です。何となく勘の良い方はおわかりだと思うのですが、これではダウンタイムが発生します。すなわち、ダウンタイムが許される開発環境などで使用します。

2つ目は前述もしている「RollingUpdate」です。こちらは「Recreate」と違い順繰りに変更していくため、新旧が混在するもののダウンタイムはありません。当方法はマニフェストファイル上では [strategy] - [type] で設定できます。明示的に指定しない場合は「RollingUpdate」になるようです。

再度ハンズオンに入る前に「ロールアウト」という言葉を覚えておきます。この用語はアプリケーションをクラスター内にデプロイしサービスを動作させることを指します。

xxx > kubectl apply -f Deployment/rollout-depoyment.yaml
deployment.apps/rollout-deployment created
service/rollout created
xxx > kubectl rollout status deploy rollout-deployment
deployment "rollout-deployment" successfully rolled out
xxx > kubectl get pod
NAME                                 READY     STATUS    RESTARTS   AGE
rollout-deployment-fc7c7cbdc-78d29   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-7wwhj   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-8k5sh   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-cwzc9   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-k8mkw   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-knjdj   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-v2hx4   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-w5n4f   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-xbdfn   1/1       Running   0          66s
rollout-deployment-fc7c7cbdc-zjwd6   1/1       Running   0          66s
xxx > kubectl get service
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      10.0.0.1                  443/TCP        3d1h
rollout      LoadBalancer   10.0.160.142   40.115.182.229   80:32053/TCP   101s

Deployment だけでなく Service のリソースも作成されています。また、「kubectl rollout ~~」でDeployment の結果を確認できます。Pod は 10個 できており、外部からのアクセスIPは「40.115.182.229」といった状態です。アクセスしてみると?

f:id:btsn:20191025003919p:plain

アクセスできました。

xxx > kubectl describe deploy rollout-deployment
Name:                   rollout-deployment
(略)
Annotations:            deployment.kubernetes.io/revision=1
(略)
Selector:               app=photo-view
Replicas:               10 desired | 10 updated | 10 total | 10 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
~~~~~
Pod Template:
  Labels:  app=photo-view
  Containers:
   photoview-container:
    Image:        sampleacrregistry999.azurecr.io/photo-view:v1.0
    Port:         80/TCP
(略)
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  
NewReplicaSet:   rollout-deployment-fc7c7cbdc (10/10 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  11m   deployment-controller  Scaled up replica set rollout-deployment-fc7c7cbdc to 10

Deployment の概要が表示され「Annotations」行には「revision=1」があります。履歴管理のためのものでローリングアップに際して増分します。「Selector」行以降でローリングアップデート状況を確認できます。「Pod Template」行以降で Pod の仕様等を確認できます。

続いて その4 で ACR に登録した v2.0 を利用して挙動確認します。準備としてマニフェストファイルの一部を v1.0 から v2.0 に変更します。

xxx > kubectl apply -f Deployment/rollout-depoyment.yaml
deployment.apps/rollout-deployment configured
service/rollout unchanged
xxx > kubectl get deploy
NAME                 READY     UP-TO-DATE   AVAILABLE   AGE
rollout-deployment   10/10     10           10          28m
xxx > kubectl describe deploy rollout-deployment
Name:                   rollout-deployment
(略)
Annotations:            deployment.kubernetes.io/revision=2
(略)
Pod Template:
  Labels:  app=photo-view
  Containers:
   photoview-container:
    Image:        sampleacrregistry999.azurecr.io/photo-view:v2.0
(略)
OldReplicaSets:  
NewReplicaSet:   rollout-deployment-7bfc98cff8 (10/10 replicas created)
(略)

見比べてみると、「Annotations」行には「revision=2」となり「Image」行は「v2.0」となっております。また、Old と New の ReplicaSet も勿論変更されております。内部的な動作としては新しい ReplicaSet を作成してそちらの Pod を増やす、古い方の Pod を減らす、そして0になるまで続けるといった塩梅です。外見としては把握しにくいですが整合を取りつつ内部ではロールアウトしています。

では、次にロールバックを見てみます。マニフェストを当初の v1.0 に戻します。

xxx > kubectl apply -f Deployment/rollout-depoyment.yaml
deployment.apps/rollout-deployment configured
service/rollout unchanged
xxx > kubectl describe deploy rollout-deployment
Name:                   rollout-deployment
(略)
Annotations:            deployment.kubernetes.io/revision=3
(略)
Pod Template:
  Labels:  app=photo-view
  Containers:
   photoview-container:
    Image:        sampleacrregistry999.azurecr.io/photo-view:v1.0
(略)
OldReplicaSets:  
NewReplicaSet:   rollout-deployment-fc7c7cbdc (10/10 replicas created)
(略)

 「Annotations」行には「revision=3」となり「Image」行は「v1.0」となっております。その上で Old と New 行なのですが、「revision=1」の際の英数文字の羅列に戻っております。revision こそ進んでいるものの内部の履歴を参照しロールバックをしていることが分かります。

また、ロールアウトは条件として Pod のテンプレートを変更したときのみ行われます。一通りの動きが分かったので削除します。(コマンドは割愛します)

ローリングアップデートの制御に関して

describe のコマンド結果にも表示されていましたが、使用できない Pod の制御として「maxUnavailable」の指定、クラスターで Pod を作成できる最大数として「maxSurge」を指定できます。共にデフォルト値は 25% です。こちらのマニフェストファイルの変更のハンズオンは割愛します。

 

実際には前述している「ブルー/グリーンデプロイメント」もハンズオンしようと思ったのですがここまでにたっぷりと触れてしまったので その8 はここで打ち切り(笑)にします。

ざっくりとした内容としてはブルー用(旧)のマニフェストファイル v1.0 とグリーン用(新)のマニフェストファイル v2.0 を準備し共にクラスターへデプロイします。apply 方法はいつもと変わりありません。3つずつ Pod がある想定で計6つ Pod が共存する形になります。

これに加え外部からアクセスする際の Service マニフェストを作成する際に v1.0 へ向けるようにするとブルー用(旧)へ向く形となります。v2.0 での確認を一通り終えたところで Service マニフェストを v2.0 へ向けるようにすれば当デプロイメント完了です!

 

解散!