KubernetesのWorkloadsリソース(その1)
Deployment
Deploymentは複数のReplicaSetを管理することで、ローリングアップデートやロールバックなどを実現可能にするリソースです。
仕組みとしては単純で、
- 新しいReplicaSetを作成
- 新しいReplicaSet上のレプリカ数(Pod数)を徐々に増やす
- 古いReplicaSet上のレプリカ数(Pod数)を徐々に減らす
- (2、3をくり返す)
- 古いReplicaSetはレプリカ数0で保持する
というフローを取ります。
切り替えの際には
- 新しいReplicaSet上でコンテナが起動するか・ヘルスチェックが通っているかの確認をしながら
- ReplicaSetを移行していく際のPod数の細かい指定が可能
となっており、Kubernetesでは最も推奨されているコンテナの起動方法となっています。たとえ1コンテナだけだったとしても、Deploymentを利用して起動するのが望ましいです。
Deploymentの作成
簡単なDeploymentのサンプルを動作させてみます。まず設定ファイルですが、下記のようなファイルから、sample-deploymentを作成します。先ほど作成したReplicaSetの設定にならってDeploymentを作成します。
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」を付けておくことで、アップデートを行った際の履歴を保持しておくことが可能です。
$ 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で確認できます。
$ 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が付与される点だけ違いますが、衝突の危険性も少ないため、イメージの確認など簡単な用途では、こちらを利用することも可能です。
$ kubectl run sample-deployment --image nginx:1.12 --replicas 3 --port 80 deployment "sample-deployment" created
Deploymentを確認してみると、ほとんどReplicaSetと同じような情報が表示されます。命名規則からもDeploymentがReplicaSetを生成し、ReplicaSetがPodを作成していることが分かりやすいかと思います。
$ 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」コマンドを利用します。
$ kubectl set image deployment sample-deployment nginx-container=nginx:1.13 deployment "sample-deployment" image updated
更新後はReplicaSetが新たに作られており、そこに紐づく形でPodが再作成されます。この時、内部的にはローリングアップデートが行われているため、基本的にはサービスへの影響はありません。
$ 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を利用するようになっています。
$ 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オプションがない場合には空になります。
$ 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
ロールバックする際には、引数でリビジョンを指定することも可能ですし、未指定の場合には一つ前のリビジョンに戻ります。
# 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が起動される形になります。
$ 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という方式もあります。また、アップデートの挙動に関しては様々なパラメータが存在するため、詳細は次回以降に紹介したいと思います。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- KubernetesのWorkloadsリソース(その2)
- KubernetesのDiscovery&LBリソース(その2)
- Oracle Cloud Hangout Cafe Season7 #1「Kubnernetes 超入門」(2023年6月7日開催)
- KubernetesのConfig&Storageリソース(その1)
- Kubernetes上のコンテナをIngressでインターネットに公開するまで
- ドメインを考慮した柔軟なPodの配置を実現する「Balancer」
- KubernetesのDiscovery&LBリソース(その1)
- Kubernetesの基礎
- Oracle Cloud Hangout Cafe Season5 #3「Kubernetes のセキュリティ」(2022年3月9日開催)
- KubernetesのマニフェストをMagnumで実行する