Kubernetes Application Update
303-app-updateの内容
Kubernetes Application Update
今回では、Kubernetesクラスタにデプロイされたアプリケーションを使用して更新する方法について説明しデプロイします。 また、アプリケーションのCanary Deploymentについても見ていきます。
Deploymentは、Podを管理するためのレプリカセットを作成します。 レプリカセット内のレプリカの数は、アプリケーションの要求に合わせて拡大縮小できます。 Deploymentを使用してdeployされたアプリケーションを更新するには、 Deploymentの構成を更新する必要があります。
この変更により、新しいレプリカセットが作成されます。 これは、以前のレプリカセットが縮小されている間にスケールアップされます。 これにより、アプリケーションのダウンタイムが発生しません。
kubectl rolling-update
コマンドが ありますが、レプリカセットにのみ適用されます。
このコマンドからの更新は、クライアント側で行われました。
更新がサーバー側にあるので、Deploymentを使用してrolling-updateを行うことを強くお勧めします。
我々のユースケースでは、アプリケーションは最初に画像を使用します arungupta/app-upgrade:v1
。
次に、イメージを使用するようにDeploymentが更新されます arungupta/app-upgrade:v2
。
v1イメージは "Hello World!"を出力します。
v2イメージは「Howdy World!」を印刷します。
これらのイメージのソースコードはimagesディレクトリにあります。
前提条件
この章の演習を行うには、Kubernetesクラスタ構成を展開する必要があります。 EKSベースのKubernetesクラスタを作成するには、AWS CLIを使用します。 EKSを使用せずにKubernetesクラスタを作成する場合は、代わりにkopsを使用できます。 この章の設定ファイルはすべてapp-updateディレクトリにあります。 この章のコマンドを実行する前に、そのディレクトリに移動してください。 Cloud9で作業している場合は、次のコマンドを実行します。
cd ~/environment/aws-workshop-for-kubernetes/03-path-application-development/303-app-update/
rolling-update
新しいリビジョンへのアップデート
アプリケーションを更新するには、既存のすべてのポッドを、別のバージョンのイメージを使用する新しいポッドに置き換える必要があります。
.spec.strategy
デプロイメント設定で、古いポッドを新しいポッドに置き換えるための戦略を定義することができます。
このキーには次の2つの値があります。
- Recreate
- RollingUpdate (デフォルト)
この2つのデプロイ戦略を見てみましょう。
strategy を再作成する
既存のPodはすべて、新しいものが作成される前に強制終了されます。 設定ファイルは以下のようになります
apiVersion: apps/v1 kind: Deployment metadata: name: app-recreate spec: replicas: 5 selector: matchLabels: name: app-recreate strategy: type: Recreate template: metadata: labels: name: app-recreate spec: containers: - name: app-recreate image: arungupta/app-upgrade:v1 ports: - containerPort: 8080
- deploymentを作成
$ kubectl create -f templates/app-recreate.yaml --record deployment "app-recreate" created
--recordこのdeploymentを開始するコマンドが確実に記録されます。 これは、アプリケーションがいくつかの更新を経て、バージョンとコマンドを関連付ける必要がある場合に便利です。
- deploymentsの履歴を取得
$ kubectl rollout history deployment/app-recreate deployments "app-recreate" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-recreate.yaml --record=true
- サービスを公開する
$ kubectl expose deployment/app-recreate --port=80 --target-port=8080 --name=app-recreate --type=LoadBalancer service "app-recreate" exposed
- サービスの詳細を取得する
$ kubectl describe svc/app-recreate Name: app-recreate Namespace: default Labels: name=app-recreate Annotations: <none> Selector: name=app-recreate Type: LoadBalancer IP: 100.65.43.233 LoadBalancer Ingress: af2dc1f99bda211e791f402037f18a54-1616925381.eu-central-1.elb.amazonaws.com Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 30158/TCP Endpoints: 100.96.1.14:80,100.96.2.13:80,100.96.3.13:80 + 2 more... Session Affinity: None External Traffic Policy: Cluster Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CreatingLoadBalancer 24s service-controller Creating load balancer Normal CreatedLoadBalancer 23s service-controller Created load balancer
- serviceにアクセス
$ curl http://af2dc1f99bda211e791f402037f18a54-1616925381.eu-central-1.elb.amazonaws.com Hello World!
- 別の端末では、Podの状態を確認
$ kubectl get -w pods app-v1-recreate-486400321-4rwzb 1/1 Running 0 9m app-v1-recreate-486400321-fqh5l 1/1 Running 0 9m app-v1-recreate-486400321-jm02h 1/1 Running 0 9m app-v1-recreate-486400321-rl79n 1/1 Running 0 9m app-v1-recreate-486400321-z89nm 1/1 Running 0 9m
- deploymentのイメージを更新します。
$ kubectl set image deployment/app-recreate app-recreate=arungupta/app-upgrade:v2 deployment "app-recreate" image updated
- Podのステータスが更新されます。すべてのPodが最初に終了し、新しいPodが作成されたことを示します。
$ kubectl get -w pods NAME READY STATUS RESTARTS AGE app-v1-recreate-486400321-4rwzb 1/1 Running 0 9m app-v1-recreate-486400321-fqh5l 1/1 Running 0 9m app-v1-recreate-486400321-jm02h 1/1 Running 0 9m app-v1-recreate-486400321-rl79n 1/1 Running 0 9m app-v1-recreate-486400321-z89nm 1/1 Running 0 9m app-v1-recreate-486400321-rl79n 1/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 1/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 1/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 1/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 1/1 Terminating 0 10m app-v1-recreate-486400321-rl79n 0/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 0/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 0/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 0/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 0/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 0/1 Terminating 0 10m app-v1-recreate-486400321-fqh5l 0/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 0/1 Terminating 0 10m app-v1-recreate-486400321-z89nm 0/1 Terminating 0 10m app-v1-recreate-486400321-rl79n 0/1 Terminating 0 10m app-v1-recreate-486400321-rl79n 0/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 0/1 Terminating 0 10m app-v1-recreate-486400321-jm02h 0/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 0/1 Terminating 0 10m app-v1-recreate-486400321-4rwzb 0/1 Terminating 0 10m app-v1-recreate-2362379170-fp3j2 0/1 Pending 0 0s app-v1-recreate-2362379170-xxqqw 0/1 Pending 0 0s app-v1-recreate-2362379170-hkpt7 0/1 Pending 0 0s app-v1-recreate-2362379170-jzh5d 0/1 Pending 0 0s app-v1-recreate-2362379170-k26sf 0/1 Pending 0 0s app-v1-recreate-2362379170-xxqqw 0/1 Pending 0 0s app-v1-recreate-2362379170-fp3j2 0/1 Pending 0 0s app-v1-recreate-2362379170-hkpt7 0/1 Pending 0 0s app-v1-recreate-2362379170-jzh5d 0/1 Pending 0 0s app-v1-recreate-2362379170-k26sf 0/1 Pending 0 0s app-v1-recreate-2362379170-xxqqw 0/1 ContainerCreating 0 0s app-v1-recreate-2362379170-fp3j2 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-hkpt7 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-jzh5d 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-k26sf 0/1 ContainerCreating 0 1s app-v1-recreate-2362379170-fp3j2 1/1 Running 0 3s app-v1-recreate-2362379170-k26sf 1/1 Running 0 3s app-v1-recreate-2362379170-xxqqw 1/1 Running 0 3s app-v1-recreate-2362379170-hkpt7 1/1 Running 0 4s app-v1-recreate-2362379170-jzh5d 1/1 Running 0 4s
出力は、すべてのPodが最初に終了した後、新しいPodが作成されたことを示します。
- deploymentsの履歴を手に入れる
$ kubectl rollout history deployment/app-recreate deployments "app-recreate" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-recreate.yaml --record=true 2 kubectl set image deployment/app-recreate app-recreate=arungupta/app-upgrade:v2
- 再度アプリケーションにアクセスする
$ curl http://af2dc1f99bda211e791f402037f18a54-1616925381.eu-central-1.elb.amazonaws.com Howdy World!
出力にv2は、使用されているイメージのバージョンが表示されるようになりました。
Rolling update戦略
Podはローリングアップデートの方法で更新されます。 Rolling updateの実行方法を定義するには、次の2つのオプションのプロパティを使用できます。
.spec.strategy.rollingUpdate.maxSurge
必要な数のポッドに作成できるポッドの最大数を指定します。値には、絶対数またはパーセンテージを使用できます。デフォルト値は25%です。.spec.strategy.rollingUpdate.maxUnavailable
更新処理中に使用できないポッドの最大数を指定します。
設定ファイルは以下のようになります
apiVersion: apps/v1 kind: Deployment metadata: name: app-rolling spec: replicas: 5 selector: matchLabels: name: app-rolling strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 1 template: metadata: labels: name: app-rolling spec: containers: - name: app-rolling image: arungupta/app-upgrade:v1 ports: - containerPort: 8080
この場合、最大数のポッド上に1つ以上のポッドを作成することができ、更新プロセス中には1つのポッドしか利用できなくなります。
- deploymentを作成
$ kubectl create -f templates/app-rolling.yaml --record deployment "app-rolling" created
再度、--recordこの展開を開始するコマンドが確実に記録されます。 これは、アプリケーションがいくつかの更新を経て、バージョンとコマンドを関連付ける必要がある場合に便利です。
- デプロイの履歴を取得する
$ kubectl rollout history deployment/app-rolling deployments "app-rolling" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-rolling.yaml --record=true
- サービスを公開する
$ kubectl expose deployment/app-rolling --port=80 --target-port=8080 --name=app-rolling --type=LoadBalancer service "app-rolling" exposed
- サービスの詳細を取得する
$ kubectl describe svc/app-rolling Name: app-rolling Namespace: default Labels: name=app-rolling Annotations: <none> Selector: name=app-rolling Type: LoadBalancer IP: 100.71.164.130 LoadBalancer Ingress: abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 31521/TCP Endpoints: 100.96.1.16:80,100.96.2.15:80,100.96.3.15:80 + 2 more... Session Affinity: None External Traffic Policy: Cluster Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CreatingLoadBalancer 1m service-controller Creating load balancer Normal CreatedLoadBalancer 1m service-controller Created load balancer
- サービスへアクセス
$ curl http://abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Hello World!
出力はv1、イメージのバージョンが使用されていることを示します。
- 別の端末では、Podの状態を確認します。
$ kubectl get -w pods NAME READY STATUS RESTARTS AGE app-rolling-1683885671-d7vpf 1/1 Running 0 2m app-rolling-1683885671-dt31h 1/1 Running 0 2m app-rolling-1683885671-k8xn9 1/1 Running 0 2m app-rolling-1683885671-sdjk3 1/1 Running 0 2m app-rolling-1683885671-x1npp 1/1 Running 0 2m
- deploymentのイメージを更新します。
$ kubectl set image deployment/app-rolling app-rolling=arungupta/app-upgrade:v2 deployment "app-rolling" image updated
- Podのステータスが更新されます。
$ kubectl get -w pods NAME READY STATUS RESTARTS AGE app-rolling-1683885671-d7vpf 1/1 Running 0 2m app-rolling-1683885671-dt31h 1/1 Running 0 2m app-rolling-1683885671-k8xn9 1/1 Running 0 2m app-rolling-1683885671-sdjk3 1/1 Running 0 2m app-rolling-1683885671-x1npp 1/1 Running 0 2m app-rolling-4154020364-ddn16 0/1 Pending 0 0s app-rolling-4154020364-ddn16 0/1 Pending 0 1s app-rolling-4154020364-ddn16 0/1 ContainerCreating 0 1s app-rolling-1683885671-sdjk3 1/1 Terminating 0 5m app-rolling-4154020364-j0nnk 0/1 Pending 0 1s app-rolling-4154020364-j0nnk 0/1 Pending 0 1s app-rolling-4154020364-j0nnk 0/1 ContainerCreating 0 1s app-rolling-1683885671-sdjk3 0/1 Terminating 0 5m app-rolling-4154020364-ddn16 1/1 Running 0 2s app-rolling-1683885671-dt31h 1/1 Terminating 0 5m app-rolling-4154020364-j0nnk 1/1 Running 0 3s app-rolling-4154020364-wlvfz 0/1 Pending 0 1s app-rolling-4154020364-wlvfz 0/1 Pending 0 1s app-rolling-1683885671-x1npp 1/1 Terminating 0 5m app-rolling-4154020364-wlvfz 0/1 ContainerCreating 0 1s app-rolling-4154020364-qr1lz 0/1 Pending 0 1s app-rolling-4154020364-qr1lz 0/1 Pending 0 1s app-rolling-1683885671-dt31h 0/1 Terminating 0 5m app-rolling-4154020364-qr1lz 0/1 ContainerCreating 0 1s app-rolling-1683885671-x1npp 0/1 Terminating 0 5m app-rolling-4154020364-wlvfz 1/1 Running 0 2s app-rolling-1683885671-d7vpf 1/1 Terminating 0 5m app-rolling-4154020364-vlb4b 0/1 Pending 0 2s app-rolling-4154020364-vlb4b 0/1 Pending 0 2s app-rolling-4154020364-vlb4b 0/1 ContainerCreating 0 2s app-rolling-1683885671-d7vpf 0/1 Terminating 0 5m app-rolling-1683885671-x1npp 0/1 Terminating 0 5m app-rolling-1683885671-x1npp 0/1 Terminating 0 5m app-rolling-4154020364-qr1lz 1/1 Running 0 3s app-rolling-1683885671-k8xn9 1/1 Terminating 0 5m app-rolling-1683885671-k8xn9 0/1 Terminating 0 5m app-rolling-4154020364-vlb4b 1/1 Running 0 2s
出力は、新しいPodが作成された後、古いPodが作成された後、新しいPodが作成されたことを示します。
- デプロイの履歴を取得する
$ kubectl rollout history deployment/app-rolling deployments "app-rolling" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-rolling.yaml --record=true 2 kubectl set image deployment/app-rolling app-rolling=arungupta/app-upgrade:v2
- アプリケーションに再度アクセスする
$ curl http://abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Howdy World!
出力にv2は、使用されているイメージのバージョンが表示されるようになりました。
以前のリビジョンへのロールバック
上記で説明したように、Deploymentをどのように展開したかの詳細は、
kubectl rollout history
コマンドを使用して取得できます。
ロールバックするには、Deploymentの完全な履歴を取得できます。
$ kubectl rollout history deployment/app-rolling deployments "app-rolling" REVISION CHANGE-CAUSE 1 kubectl create --filename=templates/app-rolling.yaml --record=true 2 kubectl set image deployment/app-rolling app-rolling=arungupta/app-upgrade:v2
次のコマンドを使用して以前のバージョンにロールバックします。
$ kubectl rollout undo deployment/app-rolling --to-revision=1 deployment "app-rolling" rolled back
サービスに再度アクセスしてください
$ curl http://abe27b4c7bdaa11e791f402037f18a54-647142678.eu-central-1.elb.amazonaws.com Hello World!
出力はv1、イメージのバージョンが現在使用されていることを示します。
リソースの削除
kubectl delete deployment/app-recreate svc/app-recreate deployment/app-rolling svc/app-rolling
Canary deployment
Canaryデプロイメントを使用すると、少数のユーザーに変更を徐々に反映させることで、すべてのユーザーに展開する前に、新しいバージョンのアプリケーションを本番環境に展開することができます。 Kubernetesでこれを達成するにはいくつかの方法があります。
- Service、DeploymentおよびLabelの使用
- 入力コントローラの使用
- DNSコントローラの使用
- IstioまたはLinkerdの使用
今回はService、DeploymentおよびLabelの方法を見ていきます
Deployment, ServiceとLabels
異なるバージョンのイメージを使用した2つのデプロイメントが使用されます。 どちらの配置も同じポッドラベルを持ちますが、少なくとも1つのラベルが異なります。 一般的なポッドラベルは、サービスのセレクタとして表示されます。 レプリカの数を調整するために、異なるポッドラベルが使用されます。 新しいバージョンのDeploymentの1つのレプリカが古いバージョンとともにリリースされます。 しばらくの間エラーが検出されない場合、新しいバージョンのレプリカの数がスケールアップされ、古いバージョンのレプリカの数が縮小されます。 最終的に、古いバージョンは削除されます。
Deploymentとサービス定義
v1展開のバージョンを見てみましょう
apiVersion: apps/v1 kind: Deployment metadata: name: app-v1 spec: replicas: 2 selector: matchLabels: name: app version: v1 template: metadata: labels: name: app version: v1 spec: containers: - name: app image: arungupta/app-upgrade:v1 ports: - containerPort: 8080
それは arungupta/app-upgrade:v1
イメージを使用します。
それは2つのラベル name: app
と version: v1
v2展開のバージョンを見てみましょう
apiVersion: apps/v1 kind: Deployment metadata: name: app-v2 spec: replicas: 2 selector: matchLabels: name: app version: v2 template: metadata: labels: name: app version: v2 spec: containers: - name: app image: arungupta/app-upgrade:v2 ports: - containerPort: 8080
それは別のイメージ arungupta/app-upgrade:v2
を使用します。
これには、Deploymentのバージョン v1
と一致する1つのラベル name: app
があります。
これは、他のラベル v2
と似ていますが、異なる値 version: v2
を使用しています。
このラベルを使用するv1と、Deploymentの v1
バージョンをオーバーライドすることなく、このDeploymentを独自に拡張できます。
最後に、これらのデプロイメントを使用するサービス定義を見てみましょう。
apiVersion: v1 kind: Service metadata: name: app-service spec: selector: name: app ports: - name: app port: 80 type: LoadBalancer
サービスは、アプリケーションの両方のバージョンに共通のラベルを使用します。これにより、両方のデプロイメントのポッドをサービスの一部にすることができます。
確認しましょう。
Canary Deploymentを作成
- Deploymentのv1バージョンをデプロイする
$ kubectl apply -f templates/app-v1.yaml deployment "app-v1" created
- Deploymentのv2バージョンをデプロイする
$ kubectl apply -f templates/app-v2.yaml deployment "app-v2" created
3. サービスをデプロイする
$ kubectl apply -f templates/app-service.yaml service "app-service" created
- このサービスのPod listを確認してください
$ kubectl get pods -l name=app NAME READY STATUS RESTARTS AGE app-v1-3101668686-4mhcj 1/1 Running 0 2m app-v1-3101668686-ncbfv 1/1 Running 0 2m app-v2-2627414310-89j1v 1/1 Running 0 2m app-v2-2627414310-bgg1t 1/1 Running 0 2m
templates/app-service.yaml
のサービス定義で指定されているポッドのみを選択するように、クエリーのname=app
ラベルを明示的に指定していることに注意してください。
v1バージョンからは2つのポッド、 v2バージョンからは2つのポッドがあります。
このサービスにアクセスすると、v1バージョンから50%、2vバージョンから50%の応答が得られます。
Canary Deploymentをスケール
v1バージョンとv2バージョンから含まれるポッドの数は、2つのデプロイメントを使用して個別に拡張できます。
- v2 deployment のレプリカ数を増やす
$ kubectl scale deploy/app-v2 --replicas=4 deployment "app-v2" scaled
- サービスの一部であるポッドを確認してください
$ kubectl get pods -l name=app NAME READY STATUS RESTARTS AGE app-v1-3101668686-4mhcj 1/1 Running 0 6m app-v1-3101668686-ncbfv 1/1 Running 0 6m app-v2-2627414310-89j1v 1/1 Running 0 6m app-v2-2627414310-8jpzd 1/1 Running 0 7s app-v2-2627414310-b17v8 1/1 Running 0 7s app-v2-2627414310-bgg1t 1/1 Running 0 6m
現在、4つのポッドはアプリケーションのバージョンv2
から来ており、2つのポッドはアプリケーションのバージョンv1
から来ていることがわかります。
したがって、ユーザーからのトラフィックの3分の2が新しいアプリケーションから提供されるようになります。
- v1バージョンのレプリカ数を0に減らす
$ kubectl scale deploy/app-v1 --replicas=0 deployment "app-v1" scaled
- サービスの一部であるPodを確認してください
$ kubectl get pods -l name=app NAME READY STATUS RESTARTS AGE app-v2-2627414310-89j1v 1/1 Running 0 8m app-v2-2627414310-8jpzd 1/1 Running 0 1m app-v2-2627414310-b17v8 1/1 Running 0 1m app-v2-2627414310-bgg1t 1/1 Running 0 8m
現在、すべてのポッドがDeploymentのv2
バージョンを提供しています。
Canary Deploymentを削除する
上記で作成したすべてのリソースを削除するには、このコマンドを実行します。
$ kubectl delete svc/app-service deployment/app-v1 deployment/app-v2
Ingress Controller (まだ未実装)
デプロイメントとサービスを使用してトラフィックの適切なパーセンテージを達成するには、必要な数のポッドをスピンアップする必要があります。 たとえば、バージョンにv1ポッドのレプリカが4つある場合などです。 次に、バージョンに5%のトラフィックを向けるためにv2、1ポッドのv2バージョンのレプリカには16個のv1バージョンのレプリカがさらに必要になります。 これはリソースの最適な使用ではありません。 この問題を解決するには、Kubernetes Ingressによる重み付けトラフィックの切り替えが使用できます。
Zalandoによると Kubernetes Ingress Controller for AWS はKubernetesのIngressコントローラ
$ kubectl apply -f templates/ingress-controller.yaml deployment "app-ingress-controller" created