Deployment
Deployment
Deploymentは複数のReplicaSetを管理することで、ローリングアップデートやロールバックなどを実現可能にするリソースです。
仕組みとしては単純で、
- 新しいReplicaSetを作成
- 新しいReplicaSet上のレプリカ数(Pod数)を徐々に増やす
- 古いReplicaSet上のレプリカ数(Pod数)を徐々に減らす
- (2、3をくり返す)
- 古いReplicaSetはレプリカ数0で保持する
というフローを取ります。
切り替えの際には
- 新しいReplicaSet上でコンテナが起動するか・ヘルスチェックが通っているかの確認をしながら
- ReplicaSetを移行していく際のPod数の細かい指定が可能
となっており、Kubernetesでは最も推奨されているコンテナの起動方法となっています。たとえ1コンテナだけだったとしても、Deploymentを利用して起動するのが望ましいです。
Deploymentの作成
簡単なDeploymentのサンプルを動作させてみます。まず設定ファイルですが、下記のようなファイルから、sample-deploymentを作成します。先ほど作成したReplicaSetの設定にならってDeploymentを作成します。
リスト27:サンプルのDeploymentを作成するdeployment_sample.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-deployment
spec:
replicas: 3
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx:1.12
ports:
- containerPort: 80
設定ファイルを元にDeploymentを作成します。「--record」を付けておくことで、アップデートを行った際の履歴を保持しておくことが可能です。
リスト28:Deploymentを作成
$ kubectl apply -f ./deployment_sample.yml --record
deployment "sample-deployment" created
履歴自体は各ReplicaSetsのmetadata.annotations.kubernetes.io/change-causeに保持されているため、下記のように確認することが可能です。また現在のReplicaSetのRevisionの番号も、同様にmetadata.annotations.deployment.kubernetes.io/revisionで確認できます。
リスト29:Deploymentの履歴を確認
$ kubectl get rs -o yaml | head
apiVersion: v1
items:
- apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
annotations:
deployment.kubernetes.io/desired-replicas: "3"
deployment.kubernetes.io/max-replicas: "4"
deployment.kubernetes.io/revision: "1"
kubernetes.io/change-cause: kubectl apply -f ./deployment_sample.yml --record
ちなみに、「kubectl run」でほぼ同等のDeploymentを生成することも可能です。デフォルトのlabelにrun: sample-deploymentが付与される点だけ違いますが、衝突の危険性も少ないため、イメージの確認など簡単な用途では、こちらを利用することも可能です。
リスト30:runコマンドでも同等の作業が行える
$ kubectl run sample-deployment --image nginx:1.12 --replicas 3 --port 80
deployment "sample-deployment" created
Deploymentを確認してみると、ほとんどReplicaSetと同じような情報が表示されます。命名規則からもDeploymentがReplicaSetを生成し、ReplicaSetがPodを作成していることが分かりやすいかと思います。
リスト31:Deploymentの結果を確認
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
sample-deployment 3 3 3 3 24s
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
sample-deployment-5cddb77dd4 3 3 3 26s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sample-deployment-5cddb77dd4-npsp8 1/1 Running 0 38s
sample-deployment-5cddb77dd4-q2qjc 1/1 Running 0 38s
sample-deployment-5cddb77dd4-zwdpq 1/1 Running 0 38s
試しにDeploymentで利用しているコンテナイメージを、nginx:1.12からnginx:1.13にアップデートしてみたいと思います。イメージの更新には「kubectl set image」コマンドを利用します。
リスト32:コンテナのアップデート
$ kubectl set image deployment sample-deployment nginx-container=nginx:1.13
deployment "sample-deployment" image updated
更新後はReplicaSetが新たに作られており、そこに紐づく形でPodが再作成されます。この時、内部的にはローリングアップデートが行われているため、基本的にはサービスへの影響はありません。
リスト33:アップデート後の状態を確認
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
sample-deployment 3 3 3 3 5m
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
sample-deployment-5cddb77dd4 0 0 0 5m
sample-deployment-7575f567ff 3 3 3 1m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sample-deployment-7575f567ff-9cjg9 1/1 Running 0 1m
sample-deployment-7575f567ff-pgc5g 1/1 Running 0 1m
sample-deployment-7575f567ff-tgwpl 1/1 Running 0 1m
今回紹介したDeployment、ReplicaSet、Podの関係は、下の図のようになります。また更新を行った際には、新規でReplicaSetが増えることになります。
Deploymentのアップデート(ReplcaSetが作成される)の条件
Deploymentでは、変更があるとReplicaSetが生成されると説明しました。この「変更」にはレプリカ数の変更などは含まれておらず、「生成されるPodの内容の変更」が必要です。より正確に言うと、spec.templateに変更があるとReplicaSetを新規で作成し、ローリングアップデートが行われます。実際にReplicaSetの定義を見てみると、spec.template以下の構造体のハッシュ値を計算し、それを利用したラベル付けで管理を行っています。また、こういった仕組みで実現されているため、再度手作業でImageなどを戻してハッシュ値が同じになった場合には、ReplicaSetを新規で作成するのではなく、既存のReplicaSetを利用するようになっています。
リスト34:Deploymentで利用されるハッシュ値
$ kubectl get rs sample-deployment-5cddb77dd4 -o yaml
…(省略)…
spec:
replicas: 3
selector:
matchLabels:
app: sample-app
pod-template-hash: "1788633880"
…(省略)…
今回の例では、Imageをnginx:1.12からnginx:1.13に変更したため、Pod Template Hashが再計算され、ReplicaSetが新しく作られることになりました。
変更のロールバック
Deoploymentにはロールバック機能があります。ロールバック機能の実体は、現在使用しているReplicaSetの切り替えと同義です。ReplicaSetは基本的には履歴としてレプリカ数を0にして形だけは残っているため、レプリカ数を増やすことで再度利用することが可能な状態になっています。
変更履歴を確認するには、「kubectl rollout history」コマンドを利用します。CHANGE-CAUSEの部分についてはDeployment作成時に--recordオプションを渡したため記載されていますが、--recordオプションがない場合には空になります。
リスト35:Deploymentの変更履歴の確認
$ kubectl rollout history deployment sample-deployment
deployments "sample-deployment"
REVISION CHANGE-CAUSE
1 kubectl create --filename=deployment_sample.yml --record=true
2 kubectl set image deployment sample-deployment nginx-container=nginx:1.13
ロールバックする際には、引数でリビジョンを指定することも可能ですし、未指定の場合には一つ前のリビジョンに戻ります。
リスト36:ロールバックするリビジョンの指定
# 1つ前にロールバックする場合(デフォルトの--to-revision 0が指定される)
$ kubectl rollout undo deployment sample-deployment
deployment "sample-deployment" rolled back
# リビジョンを指定してロールバックする場合
$ kubectl rollout undo deployment sample-deployment --to-revision 1
deployment "sample-deployment" rolled back
ロールバックした際には、古いReplicaSetのほうでPodが起動される形になります。
リスト37:ロールバック後の状態を確認
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
sample-deployment-5cddb77dd4 3 3 3 5m
sample-deployment-7575f567ff 0 0 0 1m
しかしながら、実際にはこのロールバック機能を使っている利用者は少ないのではないかと思います。というのも、CI/CDのパイプラインを整備した際には、kubectl rolloutコマンドでロールバックするよりも、古いYAMLファイルを再度kubectl applyして適用したほうが相性が良いからです。この時spec.templateを同じものに戻した場合にはPod Template Hashも同じになるため、kubectl rolloutと同じように元々あったReplicaSetのほうでPodを起動します。
Deploymentのスケーリング
ReplicaSetsと同様の方法で「kubectl scale」または「kubectl apply -f」を使ってスケールさせることが可能です。
より高度なアップデート方法
今回はローリングアップデートに焦点を当てましたが、実はアップデートの種類にはrecreateという方式もあります。また、アップデートの挙動に関しては様々なパラメータが存在するため、詳細は次回以降に紹介したいと思います。
- この記事のキーワード