Kubernetes のデプロイメントについて自習したメモで、Kubernetes デプロイメントについての自習メモ(その1)の続きです。
スケーリング
手動でスケール
初期状態で、レプリカ・セット数 3 で動作していたとします。
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-web-deployment-765656d945 3 3 3 9m
下記のコマンドで --replicas=10
として ポッド数を増加(スケール)します。
$ kubectl scale deployment nginx-web-deployment --replicas=10
deployment "nginx-web-deployment" scaled
コマンド投入直後の状態です。 ポッドが10個に増え、そのうち、準備完了したものが 6ポッドあることが読み取れます。
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-web-deployment-765656d945 10 10 6 9m
スケールが完了した状態です。
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-web-deployment-765656d945 10 10 10 10m
CPU稼働率によるスケール
ポッドのCPU使用率の閾値を超えると、レプリカ・セットの数を増加させる事ができます。 ポッドのCPU使用率とは、ノードのCPU使用率ではなくポッド毎に集計した値ということになります。
$ kubectl autoscale deployment nginx-web-deployment --min=10 --max=15 --cpu-percent=80
deployment "nginx-web-deployment" autoscaled
参考資料
ロールアウトの一時停止と再開
これはアプリケーションのコンテナを一時的に停止させるという意味ではなく、ロールアウトを一時的に停止しておいて、複数のリクエストを適用後に、デプロイメントを再開することで、無駄なロールオーバーなどを発生させずに、リリースを実施する機能です。
最初のバージョンのアプリをリリース
$ kubectl create -f nginx-web1.yml
deployment "nginx-web-deployment" created
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-web-deployment 3 3 3 3 3s
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-frjhc 1/1 Running 0 9s
nginx-web-deployment-765656d945-jr9t2 1/1 Running 0 9s
nginx-web-deployment-765656d945-wx5sc 1/1 Running 0 9s
ロールアウトの一時停止(ポーズ)
$ kubectl rollout pause deployment/nginx-web-deployment
deployment "nginx-web-deployment" paused
アプリのコンテナ・イメージを Web:v2 へ更新
$ kubectl apply -f nginx-web2.yml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment "nginx-web-deployment" configured
上記コマンド実行直後の状態ですが、レプリカセットのハッシュ 765656d945 は、最初にデプロイした時から変わっていません。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-frjhc 1/1 Running 0 58s
nginx-web-deployment-765656d945-jr9t2 1/1 Running 0 58s
nginx-web-deployment-765656d945-wx5sc 1/1 Running 0 58s
さらに、アプリのコンテナ・イメージを Web:v3 へ更新します。
$ kubectl apply -f nginx-web3.yml
deployment "nginx-web-deployment" configured
結果を確認したすると、ハッシュ値から Web:v1 のままです。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-765656d945-frjhc 1/1 Running 0 1m
nginx-web-deployment-765656d945-jr9t2 1/1 Running 0 1m
nginx-web-deployment-765656d945-wx5sc 1/1 Running 0 1m
ロールアウトの再開(レジューム)
次のコマンドを投入して、一時停止状態を解除します。
$ kubectl rollout resume deployment/nginx-web-deployment
deployment "nginx-web-deployment" resumed
再開直後から、ロールアウトが始まります。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-758c4bbc7f-4htz6 1/1 Running 0 4s
nginx-web-deployment-758c4bbc7f-6hgl7 1/1 Running 0 4s
nginx-web-deployment-758c4bbc7f-rf9b7 0/1 ContainerCreating 0 1s
nginx-web-deployment-765656d945-frjhc 1/1 Terminating 0 1m
nginx-web-deployment-765656d945-jr9t2 0/1 Terminating 0 1m
nginx-web-deployment-765656d945-wx5sc 1/1 Terminating 0 1m
次はロールアウトが完了した状態です。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-web-deployment-758c4bbc7f-4htz6 1/1 Running 0 17s
nginx-web-deployment-758c4bbc7f-6hgl7 1/1 Running 0 17s
nginx-web-deployment-758c4bbc7f-rf9b7 1/1 Running 0 14s
このハッシュは、Web:v2なのか それとも、Web:v3なのか を確認してします。 次のkubectl describe deploy
の結果のImageのフィールドから Web:v3であることが判ります。つまり、Web:v2の無駄なロールアウトが回避され、Web:v3へ切替わったことが理解できます。
$ kubectl describe deploy
Name: nginx-web-deployment
Namespace: default
CreationTimestamp: Sat, 16 Dec 2017 05:08:19 +0000
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=2
kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"extensions/v1beta1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx-web-deployment","namespace":"default"},"spec":{"repli...
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: registry.ng.bluemix.net/takara/web:v3
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-web-deployment-758c4bbc7f (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 6m deployment-controller Scaled up replica set nginx-web-deployment-765656d945 to 3
Normal ScalingReplicaSet 5m deployment-controller Scaled up replica set nginx-web-deployment-758c4bbc7f to 1
Normal ScalingReplicaSet 5m deployment-controller Scaled down replica set nginx-web-deployment-765656d945 to 2
Normal ScalingReplicaSet 5m deployment-controller Scaled up replica set nginx-web-deployment-758c4bbc7f to 2
Normal ScalingReplicaSet 5m deployment-controller Scaled down replica set nginx-web-deployment-765656d945 to 1
Normal ScalingReplicaSet 5m deployment-controller Scaled up replica set nginx-web-deployment-758c4bbc7f to 3
Normal ScalingReplicaSet 5m deployment-controller Scaled down replica set nginx-web-deployment-765656d945 to 0
デプロイメントの状態
デプロイメントはライフサイクル中に、その段階に応じた状態が変化します。 この状態について、理解を進めていきます。
「デプロイメント進行中」状態
次のいずれかによって、「デプロイメント進行中」として、扱われます。
- デプロイメントが新しくレプリカ・セットを作成
- デプロイメントが、最新のレプリカ・セットでスケール・アップ中
- デプロイメントが、古いレプリカ・セットをスケール・ダウン中
- 新しくポッドが、準備完了になるケース
kubectl rollout status
を使用してデプロイメントの進捗状況を監視できます。
「デプロイメント完了」状態
下記の特性を持つ状態は「デプロイメント完了」とされます。デプロイメントが完了したかどうかは、'kubectl rollout status'を使用して確認できます。 ロールアウトが正常に完了すると、'kubectl rollout status'はゼロの終了コードを返します。
- 要求された更新がすべてのレプリカで完了
- すべてのレプリカが準備完了
- 更新前の古いレプリカがすべて終了
「デプロイメント失敗」状態
デプロイメントが完了せずに最新のレプリカセットをデプロイしようとすると、ロールアウトが停止することがあります。 これは、次の要因のいくつかによって発生します。
- 割り当てが不十分
- Readiness プローブの失敗
- イメージ取得エラー
- 不十分な権限
- リミット範囲
- アプリケーションランタイムの設定ミス
この問題を検出する方法の1つは、デプロイメントにデッドライン・パラメータ spec:(spec.progressDeadlineSeconds)
を指定することです。 spec.progressDeadlineSeconds
は、デプロイメント・コントローラが待機する秒数を示します。
次のkubectlコマンドは、10分後にDeploymentの進行状況がコントローラに報告されないようにします。
$ kubectl patch deployment/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
deployment "nginx-deployment" patched
デッドラインを超えると、デプロイメント・コントローラーは 下記の DeploymentCondition をデプロイメントの status.condition に追加します。
- Type = Progressing
- Status = False
- Reason = ProgressDeadlineExceeded
注:Kubernetesは、Reason=ProgressDeadlineExceeded のステータスを報告する以外に、停止したデプロイメントに対しては何もしません。 上位レベルのオーケストレータは、デプロイメントを以前のバージョンにロールバックするなど、それを利用してそれに応じて行動することができます。
注:デプロイメントを一時停止すると、Kubernetesは指定されたデットラインに対する進捗状況をチェックしません。 デッドラインをトリガーすることなく、ロールアウトの途中でデプロイメントを安全に一時停止して再開することができます。
設定したタイムアウト時間が短すぎるか、何らかの原因で一時的エラーのために、デプロイメントにエラーが発生することがあります。 たとえば、クォータが不足しているケースでは、kubectl describe deployment
のConditionsのセクションで原因に気づくでしょう:
$ kubectl describe deployment nginx-deployment
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
kubectl get deployment nginx-deployment -o yaml
を実行すると、展開ステータスは次のようになります。
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: Replica set "nginx-deployment-4262182780" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
- lastTransitionTime: 2016-10-04T12:25:42Z
lastUpdateTime: 2016-10-04T12:25:42Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
reason: FailedCreate
status: "True"
type: ReplicaFailure
observedGeneration: 3
replicas: 2
unavailableReplicas: 2
最終的に、展開のデッドラインを過ぎると、進行状況のステータスと理由を更新します。
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
割り当てが不十分であるという問題に対処するには、デプロイメントをスケールダウンする、実行中の他のコントローラをスケールダウンする、またはネームスペースのクォータを増やすなどがあります。 クォータ条件を満たし、デプロイメント・コントローラが、デプロイメントのロールアウトを完了すると、でデプロイメントのステータスが正常な状態(Status = True および Reason = NewReplicaSetAvailable
)に更新されます。
Type=Available
with Status=True
は、デプロイメントに最低限の可用性があることを意味します。 最低限の可用性は、デプロイメント・ストラテジーで指定されたパラメータによって決まります。 Type=Progressing
with Status=True
は、デプロイメントが進行中であること、または進行状況が正常に完了し、必要な最小限の新しい複製が利用可能であることを意味します。
kubectl rollout status
を使用して、デプロイメントが失敗したかどうかを確認できます。
もし、デプロイメントがデットラインを超えたら、kubectl rollout status
は、ゼロ以外の終了コードを戻します。
$ kubectl rollout status deploy/nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
$ echo $?
1
クリーンナップ
デプロイメントの .spec.revisionHistoryLimit
フィールドを設定して、このデプロイメント用の古いレプリカセットをいくつ保持するかを指定できます。 残りはバックグラウンドでガベージコレクションされます。 デフォルトでは、すべてのリビジョン履歴が保持されます。 将来のバージョンでは、デフォルトで2に切り替わります。
注:このフィールドを明示的に0に設定すると、デプロイメントのすべての履歴がクリーンアップされ、デプロイメントはロールバックできなくなります。
デプロイメントのスペック記述
ポッドテンプレート
.spec.template
は .spec
の唯一の必須フィールドで、ポッドのテンプレートです。 これは、入れ子になっていて apiVersion
や kind
を持たない点を除いて、Podとまったく同じスキーマを持っています。 Podの必須フィールドに加えて、デプロイメントのポッドテンプレートには、適切なラベルを指定する必要があります。ラベルは、他のコントローラと重ならないようにしてください。
1 apiVersion: extensions/v1beta1
2 kind: Deployment
3 metadata:
4 name: nginx-web-deployment
5 spec:
6 replicas: 3
7 selector:
8 matchLabels:
9 app: nginx
10 template: <--- 必須フィールドで、podのテンプレート
11 metadata:
12 labels:
13 app: nginx
14 spec:
15 containers: <--- podの必須フィールドで、コンテナのイメージを指定
16 - name: nginx
17 image: registry.ng.bluemix.net/takara/web:v1
18 ports:
19 - containerPort: 80
レプリカ
.spec.replicas
は、必要なポッドの数を指定するオプションのフィールドです。デフォルトは1です。
5 spec:
6 replicas: 3
セレクター
.spec.selector
は、このデプロイメントによってターゲットとされるポッドのラベルセレクタを指定するオプションのフィールドです。.spec.selector
(A)は .spec.template.metadata.labels
(B)と一致する必要があります。そうしないと、APIによって拒否されます。
5 spec:
6 replicas: 3
7 selector:
8 matchLabels:
9 app: nginx <--- (A)
10 template:
11 metadata:
12 labels:
13 app: nginx <--- (B)
APIバージョンの apps/v1beta2
では、.spec.selector`および
.metadata.labelsは、設定されていない場合、
.spec.template.metadata.labelsにデフォルトではなくなりました。したがって、明示的に設定する必要があります。また、
.spec.selectorは、
apps/v1beta2`のデプロイメントの作成後に不変であることにも注意してください。
デプロイメントは、テンプレート・ポッドが '.spec.template'と異なる場合、またはそのようなポッドの総数が.spec.replicas
を超える場合、ラベルがセレクタと一致するポッドを終了させることができます。ポッドの数が希望の数よりも少ない場合は、 '.spec.template'を使用して新しいポッドを表示します。
注:このセレクタとラベルが一致する他のポッドは、直接作成するか、別のデプロイメントを作成するか、ReplicaSetやReplicationControllerなどの別のコントローラを作成して作成しないでください。 そうした場合、最初の配置は、他のポッドを作成したと考えます。 Kubernetesはこれをやめることを止めません。
重複しているセレクタを持つコントローラが複数ある場合、コントローラは互いに戦い、正しく動作しません。
ストラテジ
.spec.strategy
は古いポッドを新しいポッドに置き換えるための戦略を指定します。 .spec.strategy.type
は、「Recreate」または「RollingUpdate」です。 "RollingUpdate"がデフォルト値です。 下記は、$ kubectl edit deployment
で編集している画面で、26行目からのフィールドです。
1 apiVersion: extensions/v1beta1
2 kind: Deployment
3 metadata:
<中略>
21 spec:
22 replicas: 3
23 selector:
24 matchLabels:
25 app: nginx
26 strategy:
27 rollingUpdate:
28 maxSurge: 1
29 maxUnavailable: 1
30 type: RollingUpdate
31 template:
<以下省略>
.spec.strategy.type == Recreate
のときに、既存のポッドはすべて削除されます。
.spec.strategy.type == RollingUpdate
のときにPodをローリングアップデートで更新します。 maxUnavailable
と maxSurge
を指定してローリングアップデートプロセスを制御することができます。
.spec.strategy.rollingUpdate.maxUnavailable
は、更新処理中に利用できないポッドの最大数を指定するオプションのフィールドです。 値は絶対数(たとえば5)または希望のポッドのパーセンテージ(たとえば10%)にすることができます。 絶対数は、切り捨てによる割合から計算されます。 .spec.strategy.rollingUpdate.maxSurge
が0の場合、値は0にできません。デフォルト値は25%です。
たとえば、この値を30%に設定すると、ローリングアップデートが開始されると直ちに古いReplicaSetを目的のPodの70%に縮小することができます。 新しいPodが準備されると、古いReplicaSetをさらに縮小し、新しいReplicaSetを拡大して、更新中に常に利用可能なPodの総数が希望のPodの70%以上になるようにします。
.spec.strategy.rollingUpdate.maxSurge
は、必要な数のポッド上に作成できるポッドの最大数を指定するオプションのフィールドです。 値は絶対数(たとえば5)または希望のポッドのパーセンテージ(たとえば10%)にすることができます。 MaxUnavailable
が0の場合は、値を0にすることはできません。絶対値は、切り上げによってパーセントから計算されます。 デフォルト値は25%です。
たとえば、この値を30%に設定すると、ローリングアップデートが開始されるとすぐに新しいレプリカセットを拡大して、古いポッドと新しいポッドの合計数が希望のポッドの130%を超えないようにすることができます。 古いPodが一度削除されると、新しいReplicaSetをさらに拡大して、更新中にいつでも実行されるPodの総数が、希望のPodの最大130%になるようにすることができます。
Progress Deadline Seconds
.spec.progressDeadlineSeconds
はオプションのフィールドで、Deploymentが進行していないことをシステムが報告する前に、展開が進むのを待つ秒数を指定します。これは、 Type=Progressing
、 Status=False
となる。リソースのステータスではReason=ProgressDeadlineExceededです。デプロイメントコントローラはデプロイメントを再試行し続けます。将来、自動ロールバックが実装されると、デプロイメントコントローラは、そのような状態を観察するとすぐにデプロイメントをロールバックします。
指定されている場合、このフィールドは .spec.minReadySeconds
より大きい必要があります。
Min Ready Seconds
.spec.minReadySeconds
は、新しく作成されたPodがコンテナがクラッシュせずに準備ができて、利用可能とみなされる最小秒数を指定するオプションのフィールドです。このデフォルトは0です(ポッドは準備ができ次第利用可能と見なされます)。
ポッドがいつ準備完了と見なされるかについては、「コンテナプローブ」を参照してください。
Rollback To
.spec.rollbackTo
はAPIバージョン extensions/v1beta1
と apps/v1beta1
では廃止され、APIバージョンapps/v1beta2
ではサポートされなくなりました。代わりにkubectl rollout undo
を使用する必要があります。
Revision History Limit
.spec.revisionHistoryLimit
は、ロールバックを許可するために保持する古いReplicaSetsの数を指定するオプションのフィールドです。その理想的な価値は、新しい展開の頻度と安定性に依存します。このフィールドが設定されていない場合、すべての古いReplicaSetsはデフォルトで保持され、 etcd 'のリソースを消費し、
kubectl get rs`の出力を混雑させます。
Paused
.spec.paused
は、Deploymentの一時停止と再開のためのオプションのブール値フィールドです。中断されていないDeploymentと一時停止されていないDeploymentとの唯一の違いは、一時停止されたDeploymentのPodTemplateSpecへの変更が、一時停止されている限り、新しいロールアウトをトリガーしないことです。デプロイメントは、作成時にデフォルトで一時停止されません。
まとめ
デプロイメントを勉強することで、k8sの素晴らしい部分の一部が解った様に思います。 頻繁にアプリをデプロイする必要に迫られ、課題を抱えている所に、ソリューションとして実装できる様になりたいですね。 どうも、k8sの能力を活かせるスケーラブルなデータベースが必須なんだと思いますね。