Kubernetes: Deployment の仕組み

  • 38
    いいね
  • 0
    コメント

この記事は Kubernetes 1.5.2 で確認した情報を元に記載しています。

Deployment

Deploymentはローリングアップデートやロールバックといったデプロイ管理の仕組みを提供するものです。

Deployment の仕組み

下記の図のようにDeploymentReplicaSetを生成・管理し、ReplicaSetPodを生成・管理します。

ReplicaSet(ReplicationControllerの後継)はPodTemplateと呼ばれるPodのテンプレートをもとに、Podを指定された数(レプリカ数)に調整・管理を行う仕組みです。Podがレプリカ数より足りない場合はPodを追加し、多い場合はをPodを削除します。この仕組みによってノードの障害やアプリケーションのクラッシュでPodが足りなくなった際も自動的にPodが追加され、セルフヒーリングが実現されています。

Deploymentはコンテナイメージのバージョンアップなどアップデートがあった場合、新しい仕様のReplicaSetを作成し、新旧の全体Pod数を調整しながら新しい仕様のPodに置き換えていきます。これによりローリングアップデートが実現されます。ただし、レプリカ数のみ変更の場合は新しいReplicaSetは作成せず、現在のReplicaSetのレプリカ数を変更します。新旧のPodともに共通するラベルを持っておりローリングアップデート中はServiceを通して新旧のバージョンが混ざってサービス提供される形になります。

リソース 役割
Deployment ReplicaSetを生成、管理しローリングアップデートやロールバックといったデプロイ管理を行います。
ReplicaSet 同じ仕様のPodのレプリカ数を管理します。ReplicationControllerの後継に当たるものです。
Pod アプリケーションを動かすための最小単位。1つ以上のコンテナと共有されたボリュームで構成されます。

ローリングアップデートが終わった後もアップデート前のReplicaSetは一定数保持されます。これによりロールバックが可能になっています。

Deployment の定義

以下はDeploymentの定義例になります。下記の内容をdeployment-example.yamlという名前で保存したとします。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  # Deploymentの名前。Namespace内ではユニークである必要があります
  name: deployment-example
spec:
  # レプリカ数の指定
  replicas: 2
  # Podのテンプレート(PodTemplate)
  template:
    metadata:
      labels:
        # ラベル指定は必須
        app: deployment-example
    spec:
      containers:
      - name: nginx
        image: nginx:1.10
        ports:
        - containerPort: 80

.spec.templatePodTemplateと呼ばれるPodのテンプレートになります。このPodTemplateをもとにReplicaSetがレプリカ数分のPodを生成・管理します。またDeploymentが配下のReplicaSetReplicaSetが管理するPodを管理するためにラベルが必要となり、.spec.template.metadata.labelsで指定する必要があります。

Deployment のデプロイ

定義したDeploymentをデプロイをしてみます。ここでは操作履歴を残すために--recordオプションを指定してkubectlのコマンドをアノテーションに保存するように指定しています。

$ kubectl create -f deployment-example.yaml --record
deployment "deployment-example" created

デプロイできたか確認してみます。

$ kubectl get deployments
NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment-example   2         2         2            2           22m

--selectorオプションで設定したラベルを指定して関連リソースを見てます。

$ kubectl get deployments,replicasets,pods --selector app=deployment-example
NAME                        DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/deployment-example   2         2         2            2           30s

NAME                               DESIRED   CURRENT   READY     AGE
rs/deployment-example-2748039730   2         2         2         30s

NAME                                     READY     STATUS    RESTARTS   AGE
po/deployment-example-2748039730-k5c5j   1/1       Running   0          30s
po/deployment-example-2748039730-p85gg   1/1       Running   0          30s

Deployment の変更

次にDeploymentの情報を変更してみます。ここでは nginx のバージョンを変更してみます。先程のdeployment-example.yamlを編集し、nginx のバージョンを 1.11 にしてみます。

# 省略...
    spec:
      containers:
      - name: nginx
        image: nginx:1.11 # 1.10から1.11に変更
        ports:
        - containerPort: 80

変更を反映させます。

$ kubectl apply -f deployment-example.yaml --record
deployment "deployment-example" configured

変更されたか見てみます。ローリングアップデートで新旧のPodの数を調整しながらアップデートされていきます。

$ kubectl get deployments,replicasets,pods --selector app=deployment-example
NAME                        DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/deployment-example   2         2         2            2           7m

NAME                               DESIRED   CURRENT   READY     AGE
rs/deployment-example-2748039730   0         0         0         7m     # 古いバージョンのReplicaSet。レプリカ数が0に
rs/deployment-example-2829304371   2         2         2         27s    # 新しいバージョンのReplicaset。レプリカ数が2に

NAME                                     READY     STATUS    RESTARTS   AGE
po/deployment-example-2829304371-33x2x   1/1       Running   0          27s # Podは再生成される
po/deployment-example-2829304371-szbxm   1/1       Running   0          27s

アップデート中は下記の図のような状態になっています。アップデートが終わっても古いバージョンのReplicaSetは履歴管理のために残ります。

Podのコンテナのバージョンが新しくなっていることを確認してみます。

$ kubectl describe pods --selector=app=deployment-example
...
Controllers:    ReplicaSet/deployment-example-2829304371
Containers:
  nginx:
    Container ID:       docker://a7adf603e653826d4092d8b1340f985584767080c47a5d23895c438ed5d4d813
    Image:              nginx:1.11 # コンテナのバージョンが新しくなっていれば成功
    Image ID:           docker://sha256:01f818af747d88b4ebca7cdabd0c581e406e0e790be72678d257735fad84a15f
    Port:               80/TCP
...

ロールバック

Deploymentの特徴にロールバックがあります。デプロイの履歴を見てみます。

$  kubectl rollout history deployment deployment-example
deployments "deployment-example"
REVISION        CHANGE-CAUSE
1               kubectl create -f deployment-example.yaml --record
2               kubectl apply -f deployment-example.yaml --record

リビジョンの詳細は下記のコマンドで確認できます。

$ kubectl rollout history deployment deployment-example --revision=2
deployments "deployment-example" with revision #2
  Labels:       app=deployment-example
        pod-template-hash=2829304371
  Annotations:  kubernetes.io/change-cause=kubectl apply -f deployment-example.yaml --record
  Containers:
   nginx:
    Image:      nginx:1.11
    Port:       80/TCP
    Volume Mounts:      <none>
    Environment Variables:      <none>
  No volumes.

リビジョンを指定してロールバックしてみます。--to-revisionオプションを指定しない場合は直前のリビジョンになります。

$ kubectl rollout undo deployment deployment-example --to-revision=1
deployment "deployment-example" rolled back

nginx コンテナのバージョンが 1.11 から 1.10 にロールバックされていることを確認します。ロールバックまで少し時間がかかる場合があります。

$ kubectl describe pods --selector=app=deployment-example
...
Containers:
  nginx:
    Container ID:       docker://fae4d04753243119bf5840fefd820353766eddfd9dd75a628ea1e56673cf3828
    Image:              nginx:1.10  # 1.10に戻っている
    Image ID:           docker://sha256:c2d83d8cde8d6b13e774170f85d87829736e6614a8be33479bb7f8bd7f12dd06
    Port:               80/TCP

デプロイの履歴を見てみます。リビジョン1の行がなくなり、リビジョン3(最新)になっていることがわかります。

$ kubectl rollout history deployment deployment-example
deployments "deployment-example"
REVISION        CHANGE-CAUSE
2               kubectl apply -f deployment-example.yaml --record
3               kubectl create -f deployment-example.yaml --record # 1から3(最新)に変更された

なおデプロイの履歴は内部的には過去のReplicaSetで管理されており、ロールバックは過去のReplicaSetの切り替えることで行われています。リビジョンやコマンドの履歴といった情報はReplicaSetのアノテーションとして保存されています。

補足: Deployment のラベル

Deploymentではspec.template.metadata.labels設定したラベルが自動的にDeploymentのセレクタ(.spec.selector.matchLabels)に設定されるようになっています。

$ kubectl get deployment deployment-example -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
...
spec:
  replicas: 2
  selector:
    # 自動的に設定される
    matchLabels:
      app: deployment-example
  ...
  template:
    metadata:
      creationTimestamp: null
      labels:
        # マニフェストで設定した値
        app: deployment-example
...

Deploymentspec.template.metadata.labelsの値はReplicaSetのラベルとセレクタの一部とPodのラベルに使われています。またReplicaSetごとに配下のPodを識別するためにpod-template-hashというPodTemplateから生成したハッシュ値を持っています。

$ kubectl get replicaset -l app=deployment-example -o yaml
...
- apiVersion: extensions/v1beta1
  kind: ReplicaSet
  spec:
    replicas: 2
    selector:
      # このセレクタでPodを選択する
      matchLabels:
        # deploymentで指定したラベル
        app: deployment-example
        # Podを識別するためのPodTemplateから作られたハッシュ値
        pod-template-hash: "2748039730"
    template:
      metadata:
        creationTimestamp: null
        labels:
          # セレクタと同じ値
          app: deployment-example
          pod-template-hash: "2748039730"

PodReplicaSetが持つセレクタと同じラベルが設定されています。

$ kubectl get pods -l app=deployment-example -o yaml
...
- apiVersion: v1
  kind: Pod
  metadata:
   ...
    labels:
      app: deployment-example
      pod-template-hash: "2748039730"

下記の図ではDeploymentspec.template.metadata.labelsapp=myappだった場合のラベルの付け方を説明しています。新旧のPodともに共通のapp=myappというラベルがあるためローリングアップデート中もServiceを通して断続なくサービス提供でき、新旧で異なるpod-template-hashというラベルがあるため個別にも管理できる仕組みになっています。

まとめ

  • Deploymentはローリングアップデートやロールバックといったデプロイ管理の仕組みを提供します
  • 同じ仕様のPodを管理するReplicaSetとアプリケーションを動作させる最小単位のPodで構成されています
  • 履歴が管理されておりロールバックが可能です

参考