1 - Deployment

DeploymentPodReplicaSetの宣言的なアップデート機能を提供します。

Deploymentにおいて 理想的な状態 を記述すると、Deploymentコントローラーは指定された頻度で現在の状態を理想的な状態に変更します。Deploymentを定義することによって、新しいReplicaSetを作成したり、既存のDeploymentを削除して新しいDeploymentで全てのリソースを適用できます。

備考: Deploymentによって作成されたReplicaSetを管理しないでください。ご自身のユースケースが以下の項目に含まれない場合、メインのKubernetesリポジトリーにIssueを作成することを検討してください。

ユースケース

以下の項目はDeploymentの典型的なユースケースです。

  • ReplicaSetをロールアウトするためにDeploymentの作成を行う: ReplicaSetはバックグラウンドでPodを作成します。Podの作成が完了したかどうかは、ロールアウトのステータスを確認してください。
  • DeploymentのPodTemplateSpecを更新することによりPodの新しい状態を宣言する: 新しいReplicaSetが作成され、Deploymentは指定された頻度で古いReplicaSetから新しいReplicaSetへのPodの移行を管理します。新しいReplicaSetはDeploymentのリビジョンを更新します。
  • Deploymentの現在の状態が不安定な場合、Deploymentのロールバックをする: ロールバックによる各更新作業は、Deploymentのリビジョンを更新します。
  • より多くの負荷をさばけるように、Deploymentをスケールアップする。
  • PodTemplateSpecに対する複数の修正を適用するためにDeploymentを停止(Pause)し、それを再開して新しいロールアウトを開始します。
  • Deploymentのステータス をロールアウトが失敗したサインとして利用する。
  • 今後必要としない古いReplicaSetのクリーンアップ

Deploymentの作成

以下はDeploymentの例です。これはnginxPodのレプリカを3つ持つReplicaSetを作成します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

この例では、

  • .metadata.nameフィールドで指定されたnginx-deploymentという名前のDeploymentが作成されます。

  • このDeploymentは.spec.replicasフィールドで指定された通り、3つのレプリカPodを作成します。

  • .spec.selectorフィールドは、Deploymentが管理するPodのラベルを定義します。ここでは、Podテンプレートにて定義されたラベル(app: nginx)を選択しています。しかし、PodTemplate自体がそのルールを満たす限り、さらに洗練された方法でセレクターを指定することができます。

    備考: .spec.selector.matchLabelsフィールドはキーバリューペアのマップです。 matchLabelsマップにおいて、{key, value}というペアは、keyというフィールドの値が"key"で、その演算子が"In"で、値の配列が"value"のみ含むようなmatchExpressionsの要素と等しくなります。 matchLabelsmatchExpressionsの両方が設定された場合、条件に一致するには両方とも満たす必要があります。
  • templateフィールドは、以下のサブフィールドを持ちます。:

    • Podは.metadata.labelsフィールドによって指定されたapp: nginxというラベルがつけられます。
    • PodTemplate、または.template.specフィールドは、Podがnginxという名前でDocker Hubにあるnginxのバージョン1.14.2が動くコンテナを1つ動かすことを示します。
    • 1つのコンテナを作成し、.spec.template.spec.containers[0].nameフィールドを使ってnginxという名前をつけます。

作成を始める前に、Kubernetesクラスターが稼働していることを確認してください。 上記のDeploymentを作成するためには以下のステップにしたがってください:

  1. 以下のコマンドを実行してDeploymentを作成してください。
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
備考: 実行したコマンドをkubernetes.io/change-causeというアノテーションに記録するために--recordフラグを指定できます。 これは将来的な問題の調査のために有効です。例えば、各Deploymentのリビジョンにおいて実行されたコマンドを見るときに便利です。
  1. Deploymentが作成されたことを確認するために、kubectl get deploymentsを実行してください。

Deploymentがまだ作成中の場合、コマンドの実行結果は以下のとおりです。

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   0/3     0            0           1s

クラスターにてDeploymentを調査するとき、以下のフィールドが出力されます。

  • NAMEは、クラスター内にあるDeploymentの名前一覧です。
  • READYは、ユーザーが使用できるアプリケーションのレプリカの数です。使用可能な数/理想的な数の形式で表示されます。
  • UP-TO-DATEは、理想的な状態を満たすためにアップデートが完了したレプリカの数です。
  • AVAILABLEは、ユーザーが利用可能なレプリカの数です。
  • AGEは、アプリケーションが稼働してからの時間です。

.spec.replicasフィールドの値によると、理想的なレプリカ数は3であることがわかります。

  1. Deploymentのロールアウトステータスを確認するために、kubectl rollout status deployment.v1.apps/nginx-deploymentを実行してください。

コマンドの実行結果は以下のとおりです。

Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
  1. 数秒後、再度kubectl get deploymentsを実行してください。 コマンドの実行結果は以下のとおりです。
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           18s

Deploymentが3つ全てのレプリカを作成して、全てのレプリカが最新(Podが最新のPodテンプレートを含んでいる)になり、利用可能となっていることを確認してください。

  1. Deploymentによって作成されたReplicaSet(rs)を確認するにはkubectl get rsを実行してください。コマンドの実行結果は以下のとおりです:
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-75675f5897   3         3         3       18s

ReplicaSetの出力には次のフィールドが表示されます:

  • NAMEは、名前空間内にあるReplicaSetの名前の一覧です。
  • DESIREDは、アプリケーションの理想的な レプリカ の値です。これはDeploymentを作成したときに定義したもので、これが 理想的な状態 と呼ばれるものです。
  • CURRENTは現在実行されているレプリカの数です。
  • READYは、ユーザーが使用できるアプリケーションのレプリカの数です。
  • AGEは、アプリケーションが稼働してからの時間です。

ReplicaSetの名前は[Deployment名]-[ランダム文字列]という形式になることに注意してください。ランダム文字列はランダムに生成され、pod-template-hashをシードとして使用します。

  1. 各Podにラベルが自動的に付けられるのを確認するにはkubectl get pods --show-labelsを実行してください。 コマンドの実行結果は以下のとおりです:
NAME                                READY     STATUS    RESTARTS   AGE       LABELS
nginx-deployment-75675f5897-7ci7o   1/1       Running   0          18s       app=nginx,pod-template-hash=3123191453
nginx-deployment-75675f5897-kzszj   1/1       Running   0          18s       app=nginx,pod-template-hash=3123191453
nginx-deployment-75675f5897-qqcnn   1/1       Running   0          18s       app=nginx,pod-template-hash=3123191453

作成されたReplicaSetはnginxPodを3つ作成することを保証します。

備考:

Deploymentに対して適切なセレクターとPodテンプレートのラベルを設定する必要があります(このケースではapp: nginx)。

ラベルやセレクターを他のコントローラーと重複させないでください(他のDeploymentやStatefulSetを含む)。Kubernetesはユーザーがラベルを重複させることを阻止しないため、複数のコントローラーでセレクターの重複が発生すると、コントローラー間で衝突し予期せぬふるまいをすることになります。

pod-template-hashラベル

注意: このラベルを変更しないでください。

pod-template-hashラベルはDeploymentコントローラーによってDeploymentが作成し適用した各ReplicaSetに対して追加されます。

このラベルはDeploymentが管理するReplicaSetが重複しないことを保証します。このラベルはReplicaSetのPodTemplateをハッシュ化することにより生成され、生成されたハッシュ値はラベル値としてReplicaSetセレクター、Podテンプレートラベル、ReplicaSetが作成した全てのPodに対して追加されます。

Deploymentの更新

備考: Deploymentのロールアウトは、DeploymentのPodテンプレート(この場合.spec.template)が変更された場合にのみトリガーされます。例えばテンプレートのラベルもしくはコンテナーイメージが更新された場合です。Deploymentのスケールのような更新では、ロールアウトはトリガーされません。

Deploymentを更新するには以下のステップに従ってください。

  1. nginxのPodで、nginx:1.14.2イメージの代わりにnginx:1.16.1を使うように更新します。

    kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
    

    または単に次のコマンドを使用します。

    kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1 --record
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment image updated
    

    また、Deploymentを編集して、.spec.template.spec.containers[0].imagenginx:1.14.2からnginx:1.16.1に変更することができます。

    kubectl edit deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment edited
    
  2. ロールアウトのステータスを確認するには、以下のコマンドを実行してください。

    kubectl rollout status deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
    

    もしくは

    deployment "nginx-deployment" successfully rolled out
    

更新されたDeploymentのさらなる情報を取得するには、以下を確認してください。

  • ロールアウトが成功したあと、kubectl get deploymentsを実行してDeploymentを確認できます。 実行結果は以下のとおりです。

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           36s
    
  • Deploymentが新しいReplicaSetを作成してPodを更新させたり、新しいReplicaSetのレプリカを3にスケールアップさせたり、古いReplicaSetのレプリカを0にスケールダウンさせるのを確認するにはkubectl get rsを実行してください。

    kubectl get rs
    

    実行結果は以下のとおりです。

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       6s
    nginx-deployment-2035384211   0         0         0       36s
    
  • get podsを実行させると、新しいPodのみ確認できます。

    kubectl get pods
    

    実行結果は以下のとおりです。

    NAME                                READY     STATUS    RESTARTS   AGE
    nginx-deployment-1564180365-khku8   1/1       Running   0          14s
    nginx-deployment-1564180365-nacti   1/1       Running   0          14s
    nginx-deployment-1564180365-z9gth   1/1       Running   0          14s
    

    次にPodを更新させたいときは、DeploymentのPodテンプレートを再度更新するだけです。

    Deploymentは、Podが更新されている間に特定の数のPodのみ停止状態になることを保証します。デフォルトでは、目標とするPod数の少なくとも25%が停止状態になることを保証します(25% max unavailable)。

    また、DeploymentはPodが更新されている間に、目標とするPod数を特定の数まで超えてPodを稼働させることを保証します。デフォルトでは、目標とするPod数に対して最大でも125%を超えてPodを稼働させることを保証します(25% max surge)。

    例えば、上記で説明したDeploymentの状態を注意深く見ると、最初に新しいPodが作成され、次に古いPodが削除されるのを確認できます。十分な数の新しいPodが稼働するまでは、Deploymentは古いPodを削除しません。また十分な数の古いPodが削除しない限り新しいPodは作成されません。少なくとも2つのPodが利用可能で、最大でもトータルで4つのPodが利用可能になっていることを保証します。

  • Deploymentの詳細情報を取得します。

    kubectl describe deployments
    

    実行結果は以下のとおりです。

    Name:                   nginx-deployment
    Namespace:              default
    CreationTimestamp:      Thu, 30 Nov 2017 10:56:25 +0000
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision=2
    Selector:               app=nginx
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
       Containers:
        nginx:
          Image:        nginx:1.16.1
          Port:         80/TCP
          Environment:  <none>
          Mounts:       <none>
        Volumes:        <none>
      Conditions:
        Type           Status  Reason
        ----           ------  ------
        Available      True    MinimumReplicasAvailable
        Progressing    True    NewReplicaSetAvailable
      OldReplicaSets:  <none>
      NewReplicaSet:   nginx-deployment-1564180365 (3/3 replicas created)
      Events:
        Type    Reason             Age   From                   Message
        ----    ------             ----  ----                   -------
        Normal  ScalingReplicaSet  2m    deployment-controller  Scaled up replica set nginx-deployment-2035384211 to 3
        Normal  ScalingReplicaSet  24s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 1
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 2
        Normal  ScalingReplicaSet  22s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 2
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 1
        Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 3
        Normal  ScalingReplicaSet  14s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 0
    

    最初にDeploymentを作成した時、ReplicaSet(nginx-deployment-2035384211)を作成してすぐにレプリカ数を3にスケールするのを確認できます。Deploymentを更新すると新しいReplicaSet(nginx-deployment-1564180365)を作成してレプリカ数を1にスケールアップし、古いReplicaSeetを2にスケールダウンさせます。これは常に最低でも2つのPodが利用可能で、かつ最大4つのPodが作成されている状態にするためです。Deploymentは同じローリングアップ戦略に従って新しいReplicaSetのスケールアップと古いReplicaSetのスケールダウンを続けます。最終的に新しいReplicaSetを3にスケールアップさせ、古いReplicaSetを0にスケールダウンさせます。

ロールオーバー (リアルタイムでの複数のPodの更新)

Deploymentコントローラーにより、新しいDeploymentが観測される度にReplicaSetが作成され、理想とするレプリカ数のPodを作成します。Deploymentが更新されると、既存のReplicaSetが管理するPodのラベルが.spec.selectorにマッチするが、テンプレートが.spec.templateにマッチしない場合はスケールダウンされます。最終的に、新しいReplicaSetは.spec.replicasの値にスケールアップされ、古いReplicaSetは0にスケールダウンされます。

Deploymentのロールアウトが進行中にDeploymentを更新すると、Deploymentは更新する毎に新しいReplicaSetを作成してスケールアップさせ、以前にスケールアップしたReplicaSetのロールオーバーを行います。Deploymentは更新前のReplicaSetを古いReplicaSetのリストに追加し、スケールダウンを開始します。

例えば、5つのレプリカを持つnginx:1.14.2のDeploymentを作成し、nginx:1.14.2の3つのレプリカが作成されているときに5つのレプリカを持つnginx:1.16.1に更新します。このケースではDeploymentは作成済みのnginx:1.14.2の3つのPodをすぐに削除し、nginx:1.16.1のPodの作成を開始します。nginx:1.14.2の5つのレプリカを全て作成するのを待つことはありません。

ラベルセレクターの更新

通常、ラベルセレクターを更新することは推奨されません。事前にラベルセレクターの使い方を計画しておきましょう。いかなる場合であっても更新が必要なときは十分に注意を払い、変更時の影響範囲を把握しておきましょう。

備考: apps/v1API バージョンにおいて、Deploymentのラベルセレクターは作成後に不変となります。
  • セレクターの追加は、Deployment Specのテンプレートラベルも新しいラベルで更新する必要があります。そうでない場合はバリデーションエラーが返されます。この変更は重複がない更新となります。これは新しいセレクターは古いセレクターを持つReplicaSetとPodを選択せず、結果として古い全てのReplicaSetがみなし子状態になり、新しいReplicaSetを作成することを意味します。
  • セレクターの更新により、セレクターキー内の既存の値が変更されます。これにより、セレクターの追加と同じふるまいをします。
  • セレクターの削除により、Deploymentのセレクターから存在している値を削除します。これはPodテンプレートのラベルに関する変更を要求しません。既存のReplicaSetはみなし子状態にならず、新しいReplicaSetは作成されませんが、削除されたラベルは既存のPodとReplicaSetでは残り続けます。

Deploymentのロールバック

例えば、クラッシュループ状態などのようにDeploymentが不安定な場合においては、Deploymentをロールバックしたくなることがあります。Deploymentの全てのロールアウト履歴は、いつでもロールバックできるようにデフォルトでシステムに保持されています(リビジョン履歴の上限は設定することで変更可能です)。

備考: Deploymentのリビジョンは、Deploymentのロールアウトがトリガーされた時に作成されます。これはDeploymentのPodテンプレート(.spec.template)が変更されたときのみ新しいリビジョンが作成されることを意味します。Deploymentのスケーリングなど、他の種類の更新においてはDeploymentのリビジョンは作成されません。これは手動もしくはオートスケーリングを同時に行うことができるようにするためです。これは過去のリビジョンにロールバックするとき、DeploymentのPodテンプレートの箇所のみロールバックされることを意味します。
  • nginx:1.16.1の代わりにnginx:1.161というイメージに更新して、Deploymentの更新中にタイプミスをしたと仮定します。

    kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.161 --record=true
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment image updated
    
  • このロールアウトはうまくいきません。ロールアウトのステータスを見るとそれを確認できます。

    kubectl rollout status deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
    
  • ロールアウトのステータスの確認は、Ctrl-Cを押すことで停止できます。ロールアウトがうまく行かないときは、Deploymentのステータスを読んでさらなる情報を得てください。

  • 古いレプリカ数(nginx-deployment-1564180365 and nginx-deployment-2035384211)が2になっていることを確認でき、新しいレプリカ数(nginx-deployment-3066724191)は1になっています。

    kubectl get rs
    

    実行結果は以下のとおりです。

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       25s
    nginx-deployment-2035384211   0         0         0       36s
    nginx-deployment-3066724191   1         1         0       6s
    
  • 作成されたPodを確認していると、新しいReplicaSetによって作成された1つのPodはコンテナイメージのpullに失敗し続けているのがわかります。

    kubectl get pods
    

    実行結果は以下のとおりです。

    NAME                                READY     STATUS             RESTARTS   AGE
    nginx-deployment-1564180365-70iae   1/1       Running            0          25s
    nginx-deployment-1564180365-jbqqo   1/1       Running            0          25s
    nginx-deployment-1564180365-hysrc   1/1       Running            0          25s
    nginx-deployment-3066724191-08mng   0/1       ImagePullBackOff   0          6s
    
    備考: Deploymentコントローラーは、この悪い状態のロールアウトを自動的に停止し、新しいReplicaSetのスケールアップを止めます。これはユーザーが指定したローリングアップデートに関するパラメータ(特にmaxUnavailable)に依存します。デフォルトではKubernetesがこの値を25%に設定します。
  • Deploymentの詳細情報を取得します。

    kubectl describe deployment
    

    実行結果は以下のとおりです。

    Name:           nginx-deployment
    Namespace:      default
    CreationTimestamp:  Tue, 15 Mar 2016 14:48:04 -0700
    Labels:         app=nginx
    Selector:       app=nginx
    Replicas:       3 desired | 1 updated | 4 total | 3 available | 1 unavailable
    StrategyType:       RollingUpdate
    MinReadySeconds:    0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:        nginx:1.161
        Port:         80/TCP
        Host Port:    0/TCP
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    ReplicaSetUpdated
    OldReplicaSets:     nginx-deployment-1564180365 (3/3 replicas created)
    NewReplicaSet:      nginx-deployment-3066724191 (1/1 replicas created)
    Events:
      FirstSeen LastSeen    Count   From                    SubObjectPath   Type        Reason              Message
      --------- --------    -----   ----                    -------------   --------    ------              -------
      1m        1m          1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-2035384211 to 3
      22s       22s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 1
      22s       22s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 2
      22s       22s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 2
      21s       21s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 1
      21s       21s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 3
      13s       13s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 0
      13s       13s         1       {deployment-controller }                Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-3066724191 to 1
    

    これを修正するために、Deploymentを安定した状態の過去のリビジョンに更新する必要があります。

Deploymentのロールアウト履歴の確認

ロールアウトの履歴を確認するには、以下の手順に従って下さい。

  1. 最初に、Deploymentのリビジョンを確認します。

    kubectl rollout history deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    deployments "nginx-deployment"
    REVISION    CHANGE-CAUSE
    1           kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml --record=true
    2           kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1 --record=true
    3           kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.161 --record=true
    

    CHANGE-CAUSEはリビジョンの作成時にDeploymentのkubernetes.io/change-causeアノテーションからリビジョンにコピーされます。以下の方法によりCHANGE-CAUSEメッセージを指定できます。

    • kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.1"の実行によりアノテーションを追加します。
    • リソースの変更時にkubectlコマンドの内容を記録するために--recordフラグを追加します。
    • リソースのマニフェストを手動で編集します。
  2. 各リビジョンの詳細を確認するためには以下のコマンドを実行してください。

    kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
    

    実行結果は以下のとおりです。

    deployments "nginx-deployment" revision 2
      Labels:       app=nginx
              pod-template-hash=1159050644
      Annotations:  kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1 --record=true
      Containers:
       nginx:
        Image:      nginx:1.16.1
        Port:       80/TCP
         QoS Tier:
            cpu:      BestEffort
            memory:   BestEffort
        Environment Variables:      <none>
      No volumes.
    

過去のリビジョンにロールバックする

現在のリビジョンから過去のリビジョン(リビジョン番号2)にロールバックさせるには、以下の手順に従ってください。

  1. 現在のリビジョンから過去のリビジョンにロールバックします。

    kubectl rollout undo deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment rolled back
    

    その他に、--to-revisionを指定することにより特定のリビジョンにロールバックできます。

    kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment rolled back
    

    ロールアウトに関連したコマンドのさらなる情報はkubectl rolloutを参照してください。

    Deploymentが過去の安定したリビジョンにロールバックされました。Deploymentコントローラーによって、リビジョン番号2にロールバックするDeploymentRollbackイベントが作成されたのを確認できます。

  2. ロールバックが成功し、Deploymentが正常に稼働していることを確認するために、以下のコマンドを実行してください。

    kubectl get deployment nginx-deployment
    

    実行結果は以下のとおりです。

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           30m
    
  3. Deploymentの詳細情報を取得します。

    kubectl describe deployment nginx-deployment
    

    実行結果は以下のとおりです。

    Name:                   nginx-deployment
    Namespace:              default
    CreationTimestamp:      Sun, 02 Sep 2018 18:17:55 -0500
    Labels:                 app=nginx
    Annotations:            deployment.kubernetes.io/revision=4
                            kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1 --record=true
    Selector:               app=nginx
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=nginx
      Containers:
       nginx:
        Image:        nginx:1.16.1
        Port:         80/TCP
        Host Port:    0/TCP
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   nginx-deployment-c4747d96c (3/3 replicas created)
    Events:
      Type    Reason              Age   From                   Message
      ----    ------              ----  ----                   -------
      Normal  ScalingReplicaSet   12m   deployment-controller  Scaled up replica set nginx-deployment-75675f5897 to 3
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 1
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 2
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 2
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 1
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-c4747d96c to 3
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled down replica set nginx-deployment-75675f5897 to 0
      Normal  ScalingReplicaSet   11m   deployment-controller  Scaled up replica set nginx-deployment-595696685f to 1
      Normal  DeploymentRollback  15s   deployment-controller  Rolled back deployment "nginx-deployment" to revision 2
      Normal  ScalingReplicaSet   15s   deployment-controller  Scaled down replica set nginx-deployment-595696685f to 0
    

Deploymentのスケーリング

以下のコマンドを実行させてDeploymentをスケールできます。

kubectl scale deployment.v1.apps/nginx-deployment --replicas=10

実行結果は以下のとおりです。

deployment.apps/nginx-deployment scaled

クラスター内で水平Podオートスケーラーが有効になっていると仮定します。ここでDeploymentのオートスケーラーを設定し、稼働しているPodのCPU使用量に基づいて、稼働させたいPodのレプリカ数の最小値と最大値を設定できます。

kubectl autoscale deployment.v1.apps/nginx-deployment --min=10 --max=15 --cpu-percent=80

実行結果は以下のとおりです。

deployment.apps/nginx-deployment scaled

比例スケーリング

Deploymentのローリングアップデートは、同時に複数のバージョンのアプリケーションの稼働をサポートします。ユーザーやオートスケーラーがローリングアップデートをロールアウト中(更新中もしくは一時停止中)のDeploymentに対して行うと、Deploymentコントローラーはリスクを削減するために既存のアクティブなReplicaSetのレプリカのバランシングを行います。これを比例スケーリング と呼びます。

レプリカ数が10、maxSurge=3、maxUnavailable=2であるDeploymentが稼働している例です。

  • Deployment内で10のレプリカが稼働していることを確認します。

    kubectl get deploy
    

    実行結果は以下のとおりです。

    NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment     10        10        10           10          50s
    
  • クラスター内で、解決できない新しいイメージに更新します。

    kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:sometag
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment image updated
    
  • イメージの更新は新しいReplicaSet nginx-deployment-1989198191へのロールアウトを開始させます。しかしロールアウトは、上述したmaxUnavailableの要求によりブロックされます。ここでロールアウトのステータスを確認します。

    kubectl get rs
    

    実行結果は以下のとおりです。

    NAME                          DESIRED   CURRENT   READY     AGE
    nginx-deployment-1989198191   5         5         0         9s
    nginx-deployment-618515232    8         8         8         1m
    
  • 次にDeploymentのスケーリングをするための新しい要求が発生します。オートスケーラーはDeploymentのレプリカ数を15に増やします。Deploymentコントローラーは新しい5つのレプリカをどこに追加するか決める必要がでてきます。比例スケーリングを使用していない場合、5つのレプリカは全て新しいReplicaSetに追加されます。比例スケーリングでは、追加されるレプリカは全てのReplicaSetに分散されます。比例割合が大きいものはレプリカ数の大きいReplicaSetとなり、比例割合が低いときはレプリカ数の小さいReplicaSetとなります。残っているレプリカはもっとも大きいレプリカ数を持つReplicaSetに追加されます。レプリカ数が0のReplicaSetはスケールアップされません。

上記の例では、3つのレプリカが古いReplicaSetに追加され、2つのレプリカが新しいReplicaSetに追加されました。ロールアウトの処理では、新しいレプリカ数のPodが正常になったと仮定すると、最終的に新しいReplicaSetに全てのレプリカを移動させます。これを確認するためには以下のコマンドを実行して下さい。

kubectl get deploy

実行結果は以下のとおりです。

NAME                 DESIRED   CURRENT   UP-TO-DATE  AVAILABLE   AGE
nginx-deployment     15        18        7           8           7m

ロールアウトのステータスでレプリカがどのように各ReplicaSetに追加されるか確認できます。

kubectl get rs

実行結果は以下のとおりです。

NAME                          DESIRED   CURRENT  READY     AGE
nginx-deployment-1989198191   7         7        0         7m
nginx-deployment-618515232    11        11       11        7m

Deployment更新の一時停止と再開

ユーザーは1つ以上の更新処理をトリガーする前に更新の一時停止と再開ができます。これにより、不必要なロールアウトを実行することなく一時停止と再開を行う間に複数の修正を反映できます。

  • 例えば、作成直後のDeploymentを考えます。 Deploymentの詳細情報を確認します。

    kubectl get deploy
    

    実行結果は以下のとおりです。

    NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    nginx     3         3         3            3           1m
    

    ロールアウトのステータスを確認します。

    kubectl get rs
    

    実行結果は以下のとおりです。

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   3         3         3         1m
    
  • 以下のコマンドを実行して更新処理の一時停止を行います。

    kubectl rollout pause deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment paused
    
  • 次にDeploymentのイメージを更新します。

    kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment image updated
    
  • 新しいロールアウトが開始されていないことを確認します。

    kubectl rollout history deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    deployments "nginx"
    REVISION  CHANGE-CAUSE
    1   <none>
    
  • Deploymentの更新に成功したことを確認するためにロールアウトのステータスを確認します。

    kubectl get rs
    

    実行結果は以下のとおりです。

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   3         3         3         2m
    
  • 更新は何度でも実行できます。例えば、Deploymentが使用するリソースを更新します。

    kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment resource requirements updated
    

    一時停止する前の初期状態では更新処理は機能しますが、Deploymentが一時停止されている間は新しい更新処理は反映されません。

  • 最後に、Deploymentの稼働を再開させ、新しいReplicaSetが更新内容を全て反映させているのを確認します。

    kubectl rollout resume deployment.v1.apps/nginx-deployment
    

    実行結果は以下のとおりです。

    deployment.apps/nginx-deployment resumed
    
  • 更新処理が完了するまでロールアウトのステータスを確認します。

    kubectl get rs -w
    

    実行結果は以下のとおりです。

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   2         2         2         2m
    nginx-3926361531   2         2         0         6s
    nginx-3926361531   2         2         1         18s
    nginx-2142116321   1         2         2         2m
    nginx-2142116321   1         2         2         2m
    nginx-3926361531   3         2         1         18s
    nginx-3926361531   3         2         1         18s
    nginx-2142116321   1         1         1         2m
    nginx-3926361531   3         3         1         18s
    nginx-3926361531   3         3         2         19s
    nginx-2142116321   0         1         1         2m
    nginx-2142116321   0         1         1         2m
    nginx-2142116321   0         0         0         2m
    nginx-3926361531   3         3         3         20s
    
  • 最新のロールアウトのステータスを確認します。

    kubectl get rs
    

    実行結果は以下のとおりです。

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   0         0         0         2m
    nginx-3926361531   3         3         3         28s
    
備考: Deploymentの稼働を再開させない限り、一時停止したDeploymentをロールバックすることはできません。

Deploymentのステータス

Deploymentは、そのライフサイクルの間に様々な状態に遷移します。新しいReplicaSetへのロールアウト中は進行中になり、その後は完了し、また失敗にもなります。

Deploymentの更新処理

以下のタスクが実行中のとき、KubernetesはDeploymentの状態を 進行中 にします。

  • Deploymentが新しいReplicaSetを作成します。
  • Deploymentが新しいReplicaSetをスケールアップさせています。
  • Deploymentが古いReplicaSetをスケールダウンさせています。
  • 新しいPodが準備中もしくは利用可能な状態になります(少なくともMinReadySecondsの間は準備中になります)。

kubectl rollout statusを実行すると、Deploymentの進行状態を確認できます。

Deploymentの更新処理の完了

Deploymentが以下の状態になったとき、KubernetesはDeploymentのステータスを 完了 にします。

  • Deploymentの全てのレプリカが、指定された最新のバージョンに更新されます。これは指定した更新処理が完了したことを意味します。
  • Deploymentの全てのレプリカが利用可能になります。
  • Deploymentの古いレプリカが1つも稼働していません。

kubectl rollout statusを実行して、Deploymentの更新が完了したことを確認できます。ロールアウトが正常に完了するとkubectl rollout statusの終了コードが0で返されます。

kubectl rollout status deployment.v1.apps/nginx-deployment

実行結果は以下のとおりです。

Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out

そしてkubectl rolloutの終了ステータスが0となります(成功です):

echo $?
0

Deploymentの更新処理の失敗

新しいReplicaSetのデプロイが完了せず、更新処理が止まる場合があります。これは主に以下の要因によるものです。

  • 不十分なリソースの割り当て
  • ReadinessProbeの失敗
  • コンテナイメージの取得ができない
  • 不十分なパーミッション
  • リソースリミットのレンジ
  • アプリケーションランタイムの設定の不備

このような状況を検知する1つの方法として、Deploymentのリソース定義でデッドラインのパラメータを指定します(.spec.progressDeadlineSeconds)。.spec.progressDeadlineSecondsはDeploymentの更新が停止したことを示す前にDeploymentコントローラーが待つ秒数を示します。

以下のkubectlコマンドでリソース定義にprogressDeadlineSecondsを設定します。これはDeploymentの更新が止まってから10分後に、コントローラーが失敗を通知させるためです。

kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'

実行結果は以下のとおりです。

deployment.apps/nginx-deployment patched

一度デッドラインを超過すると、DeploymentコントローラーはDeploymentの.status.conditionsに以下のDeploymentConditionを追加します。

  • Type=Progressing
  • Status=False
  • Reason=ProgressDeadlineExceeded

ステータスの状態に関するさらなる情報はKubernetes APIの規則を参照してください。

備考: Kubernetesは停止状態のDeploymentに対して、ステータス状態を報告する以外のアクションを実行しません。高レベルのオーケストレーターはこれを利用して、状態に応じて行動できます。例えば、前のバージョンへのDeploymentのロールバックが挙げられます。
備考: Deploymentを停止すると、Kubernetesは指定したデッドラインを超えたかどうかチェックしません。 ロールアウトの途中でもDeploymentを安全に一時停止でき、デッドラインを超えたイベントをトリガーすることなく再開できます。

設定したタイムアウトの秒数が小さかったり、一時的なエラーとして扱える他の種類のエラーが原因となり、Deploymentで一時的なエラーが出る場合があります。例えば、リソースの割り当てが不十分な場合を考えます。Deploymentの詳細情報を確認すると、以下のセクションが表示されます。

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を実行すると、Deploymentのステータスは以下のようになります。

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

最後に、一度Deploymentの更新処理のデッドラインを越えると、KubernetesはDeploymentのステータスと進行中の状態を更新します。

Conditions:
  Type            Status  Reason
  ----            ------  ------
  Available       True    MinimumReplicasAvailable
  Progressing     False   ProgressDeadlineExceeded
  ReplicaFailure  True    FailedCreate

Deploymentか他のリソースコントローラーのスケールダウンを行うか、使用している名前空間内でリソースの割り当てを増やすことで、リソースの割り当て不足の問題に対処できます。割り当て条件を満たすと、DeploymentコントローラーはDeploymentのロールアウトを完了させ、Deploymentのステータスが成功状態になるのを確認できます(Status=TrueReason=NewReplicaSetAvailable)。

Conditions:
  Type          Status  Reason
  ----          ------  ------
  Available     True    MinimumReplicasAvailable
  Progressing   True    NewReplicaSetAvailable

Status=TrueType=Availableは、Deploymentが最小可用性の状態であることを意味します。最小可用性は、Deploymentの更新戦略において指定されているパラメータにより決定されます。Status=TrueType=Progressingは、Deploymentのロールアウトの途中で、更新処理が進行中であるか、更新処理が完了し、必要な最小数のレプリカが利用可能であることを意味します(各TypeのReason項目を確認してください。このケースでは、Reason=NewReplicaSetAvailableはDeploymentの更新が完了したことを意味します)。

kubectl rollout statusを実行してDeploymentが更新に失敗したかどうかを確認できます。kubectl rollout statusはDeploymentが更新処理のデッドラインを超えたときに0以外の終了コードを返します。

kubectl rollout status deployment.v1.apps/nginx-deployment

実行結果は以下のとおりです。

Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline

そしてkubectl rolloutの終了ステータスが1となります(エラーを示しています):

echo $?
1

失敗したDeploymentの操作

更新完了したDeploymentに適用した全てのアクションは、更新失敗したDeploymentに対しても適用されます。スケールアップ、スケールダウンができ、前のリビジョンへのロールバックや、Deploymentのテンプレートに複数の更新を適用させる必要があるときは一時停止もできます。

古いリビジョンのクリーンアップポリシー

Deploymentが管理する古いReplicaSetをいくつ保持するかを指定するために、.spec.revisionHistoryLimitフィールドを設定できます。この値を超えた古いReplicaSetはバックグラウンドでガーベージコレクションの対象となって削除されます。デフォルトではこの値は10です。

備考: このフィールドを明示的に0に設定すると、Deploymentの全ての履歴を削除します。従って、Deploymentはロールバックできません。

カナリアパターンによるデプロイ

Deploymentを使って一部のユーザーやサーバーに対してリリースのロールアウトをしたい場合、リソースの管理に記載されているカナリアパターンに従って、リリース毎に1つずつ、複数のDeploymentを作成できます。

Deployment Specの記述

他の全てのKubernetesの設定と同様に、Deploymentは.apiVersion.kind.metadataフィールドを必要とします。 設定ファイルの利用に関する情報はアプリケーションのデプロイを参照してください。コンテナーの設定に関してはリソースを管理するためのkubectlの使用を参照してください。 Deploymentオブジェクトの名前は、有効なDNSサブドメイン名でなければなりません。 Deploymentは.specセクションも必要とします。

Podテンプレート

.spec.template.spec.selector.specにおける必須のフィールドです。

.spec.templatePodテンプレートです。これは.spec内でネストされていないことと、apiVersionkindを持たないことを除いてはPodと同じスキーマとなります。

Podの必須フィールドに加えて、Deployment内のPodテンプレートでは適切なラベルと再起動ポリシーを設定しなくてはなりません。ラベルは他のコントローラーと重複しないようにしてください。ラベルについては、セレクターを参照してください。

.spec.template.spec.restartPolicyAlwaysに等しいときのみ許可されます。これはテンプレートで指定されていない場合のデフォルト値です。

レプリカ数

.spec.repliasは理想的なPodの数を指定するオプションのフィールドです。デフォルトは1です。

セレクター

.spec.selectorは必須フィールドで、Deploymentによって対象とされるPodのラベルセレクターを指定します。

.spec.selector.spec.template.metadata.labelsと一致している必要があり、一致しない場合はAPIによって拒否されます。

apps/v1バージョンにおいて、.spec.selector.metadata.labelsが指定されていない場合、.spec.template.metadata.labelsの値に初期化されません。そのため.spec.selector.metadata.labelsを明示的に指定する必要があります。またapps/v1のDeploymentにおいて.spec.selectorは作成後に不変になります。

Deploymentのテンプレートが.spec.templateと異なる場合や、.spec.replicasの値を超えてPodが稼働している場合、Deploymentはセレクターに一致するラベルを持つPodを削除します。Podの数が理想状態より少ない場合Deploymentは.spec.templateをもとに新しいPodを作成します。

備考: Deploymentのセレクターに一致するラベルを持つPodを直接作成したり、他のDeploymentやReplicaSetやReplicationControllerによって作成するべきではありません。作成してしまうと、最初のDeploymentがラベルに一致する新しいPodを作成したとみなされます。こうなったとしても、Kubernetesは処理を止めません。

セレクターが重複する複数のコントローラーを持つとき、そのコントローラーは互いに競合状態となり、正しくふるまいません。

更新戦略

.spec.strategyは古いPodから新しいPodに置き換える際の更新戦略を指定します。.spec.strategy.typeは"Recreate"もしくは"RollingUpdate"を指定できます。デフォルトは"RollingUpdate"です。

Deploymentの再作成

.spec.strategy.type==Recreateと指定されているとき、既存の全てのPodは新しいPodが作成される前に削除されます。

備考: これは更新のための作成の前にPodを停止する事を保証するだけです。Deploymentを更新する場合、古いリビジョンのPodは全てすぐに停止されます。削除に成功するまでは、新しいリビジョンのPodは作成されません。手動でPodを削除すると、ライフサイクルがReplicaSetに制御されているのですぐに置き換えが実施されます(たとえ古いPodがまだ停止中のステータスでも)。Podに"高々この程度の"保証を求めるならばStatefulSetの使用を検討してください。

Deploymentのローリングアップデート

.spec.strategy.type==RollingUpdateと指定されているとき、DeploymentはローリングアップデートによりPodを更新します。ローリングアップデートの処理をコントロールするためにmaxUnavailablemaxSurgeを指定できます。

Max Unavailable

.spec.strategy.rollingUpdate.maxUnavailableはオプションのフィールドで、更新処理において利用不可となる最大のPod数を指定します。値は絶対値(例: 5)を指定するか、理想状態のPodのパーセンテージを指定します(例: 10%)。パーセンテージを指定した場合、絶対値は小数切り捨てされて計算されます。.spec.strategy.rollingUpdate.maxSurgeが0に指定されている場合、この値を0にできません。デフォルトでは25%です。

例えば、この値が30%と指定されているとき、ローリングアップデートが開始すると古いReplicaSetはすぐに理想状態の70%にスケールダウンされます。一度新しいPodが稼働できる状態になると、古いReplicaSetはさらにスケールダウンされ、続いて新しいReplicaSetがスケールアップされます。この間、利用可能なPodの総数は理想状態のPodの少なくとも70%以上になるように保証されます。

Max Surge

.spec.strategy.rollingUpdate.maxSurgeはオプションのフィールドで、理想状態のPod数を超えて作成できる最大のPod数を指定します。値は絶対値(例: 5)を指定するか、理想状態のPodのパーセンテージを指定します(例: 10%)。パーセンテージを指定した場合、絶対値は小数切り上げで計算されます。MaxUnavailableが0に指定されている場合、この値を0にできません。デフォルトでは25%です。

例えば、この値が30%と指定されているとき、ローリングアップデートが開始すると新しいReplicaSetはすぐに更新されます。このとき古いPodと新しいPodの総数は理想状態の130%を超えないように更新されます。一度古いPodが削除されると、新しいReplicaSetはさらにスケールアップされます。この間、利用可能なPodの総数は理想状態のPodに対して最大130%になるように保証されます。

Progress Deadline Seconds

.spec.progressDeadlineSecondsはオプションのフィールドで、システムがDeploymentの更新に失敗したと判断するまでに待つ秒数を指定します。更新に失敗したと判断されたとき、リソースのステータスはType=ProgressingStatus=FalseかつReason=ProgressDeadlineExceededとなるのを確認できます。DeploymentコントローラーはDeploymentの更新のリトライし続けます。デフォルト値は600です。今後、自動的なロールバックが実装されたとき、更新失敗状態になるとすぐにDeploymentコントローラーがロールバックを行うようになります。

この値が指定されているとき、.spec.minReadySecondsより大きい値を指定する必要があります。

Min Ready Seconds

.spec.minReadySecondsはオプションのフィールドで、新しく作成されたPodが利用可能となるために、最低どれくらいの秒数コンテナーがクラッシュすることなく稼働し続ければよいかを指定するものです。デフォルトでは0です(Podは作成されるとすぐに利用可能と判断されます)。Podが利用可能と判断された場合についてさらに学ぶためにContainer Probesを参照してください。

リビジョン履歴の保持上限

Deploymentのリビジョン履歴は、Deploymentが管理するReplicaSetに保持されています。

.spec.revisionHistoryLimitはオプションのフィールドで、ロールバック可能な古いReplicaSetの数を指定します。この古いReplicaSetはetcd内のリソースを消費し、kubectl get rsの出力結果を見にくくします。Deploymentの各リビジョンの設定はReplicaSetに保持されます。このため一度古いReplicaSetが削除されると、そのリビジョンのDeploymentにロールバックすることができなくなります。デフォルトでは10もの古いReplicaSetが保持されます。しかし、この値の最適値は新しいDeploymentの更新頻度と安定性に依存します。

さらに詳しく言うと、この値を0にすると、0のレプリカを持つ古い全てのReplicaSetが削除されます。このケースでは、リビジョン履歴が完全に削除されているため新しいDeploymentのロールアウトを元に戻すことができません。

paused

.spec.pausedはオプションのboolean値で、Deploymentの一時停止と再開のための値です。一時停止されているものと、そうでないものとの違いは、一時停止されているDeploymentはPodTemplateSpecのいかなる変更があってもロールアウトがトリガーされないことです。デフォルトではDeploymentは一時停止していない状態で作成されます。

2 - ReplicaSet

ReplicaSetの目的は、どのような時でも安定したレプリカPodのセットを維持することです。これは、理想的なレプリカ数のPodが利用可能であることを保証するものとして使用されます。

ReplicaSetがどのように動くか

ReplicaSetは、ReplicaSetが対象とするPodをどう特定するかを示すためのセレクターや、稼働させたいPodのレプリカ数、Podテンプレート(理想のレプリカ数の条件を満たすために作成される新しいPodのデータを指定するために用意されるもの)といったフィールドとともに定義されます。ReplicaSetは、指定された理想のレプリカ数にするためにPodの作成と削除を行うことにより、その目的を達成します。ReplicaSetが新しいPodを作成するとき、ReplicaSetはそのPodテンプレートを使用します。

ReplicaSetがそのPod群と連携するためのリンクは、Podのmetadata.ownerReferencesというフィールド(現在のオブジェクトが所有されているリソースを指定する)を介して作成されます。ReplicaSetによって所持された全てのPodは、それらのownerReferencesフィールドにReplicaSetを特定する情報を保持します。このリンクを通じて、ReplicaSetは管理しているPodの状態を把握したり、その後の実行計画を立てます。

ReplicaSetは、そのセレクターを使用することにより、所有するための新しいPodを特定します。もしownerReferenceフィールドの値を持たないPodか、ownerReferenceフィールドの値が コントローラーでないPodで、そのPodがReplicaSetのセレクターとマッチした場合に、そのPodは即座にそのReplicaSetによって所有されます。

ReplicaSetを使うとき

ReplicaSetはどんな時でも指定された数のPodのレプリカが稼働することを保証します。しかし、DeploymentはReplicaSetを管理する、より上位レベルの概念で、Deploymentはその他の多くの有益な機能と共に、宣言的なPodのアップデート機能を提供します。それゆえ、我々はユーザーが独自のアップデートオーケストレーションを必要としたり、アップデートを全く必要としないような場合を除いて、ReplicaSetを直接使うよりも代わりにDeploymentを使うことを推奨します。

これは、ユーザーがReplicaSetのオブジェクトを操作する必要が全く無いことを意味します。 代わりにDeploymentを使用して、specセクションにユーザーのアプリケーションを定義してください。

ReplicaSetの使用例

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # modify replicas according to your case
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
    matchExpressions:
      - {key: tier, operator: In, values: [frontend]}
  template:
    metadata:
      labels:
        app: guestbook
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
        - name: GET_HOSTS_FROM
          value: dns
          # If your cluster config does not include a dns service, then to
          # instead access environment variables to find service host
          # info, comment out the 'value: dns' line above, and uncomment the
          # line below.
          # value: env
        ports:
        - containerPort: 80

上記のマニフェストをfrontend.yamlファイルに保存しKubernetesクラスターに適用すると、マニフェストに定義されたReplicaSetとそれが管理するPod群を作成します。

kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml

ユーザーはデプロイされた現在のReplicaSetの情報も取得できます。

kubectl get rs

そして、ユーザーが作成したfrontendリソースについての情報も取得できます。

NAME       DESIRED   CURRENT   READY   AGE
frontend   3         3         3       6s

ユーザーはまたReplicaSetの状態も確認できます。

kubectl describe rs/frontend

その結果は以下のようになります。

Name:		frontend
Namespace:	default
Selector:	tier=frontend
Labels:		app=guestbook
		tier=frontend
Annotations:	kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",...
Replicas:	3 current / 3 desired
Pods Status:	3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  tier=frontend
  Containers:
   php-redis:
    Image:        gcr.io/google_samples/gb-frontend:v3
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  117s  replicaset-controller  Created pod: frontend-wtsmm
  Normal  SuccessfulCreate  116s  replicaset-controller  Created pod: frontend-b2zdv
  Normal  SuccessfulCreate  116s  replicaset-controller  Created pod: frontend-vcmts

そして最後に、ユーザーはReplicaSetによって作成されたPodもチェックできます。

kubectl get pods

表示されるPodに関する情報は以下のようになります。

NAME             READY   STATUS    RESTARTS   AGE
frontend-b2zdv   1/1     Running   0          6m36s
frontend-vcmts   1/1     Running   0          6m36s
frontend-wtsmm   1/1     Running   0          6m36s

ユーザーはまた、それらのPodのownerReferencesfrontendReplicaSetに設定されていることも確認できます。 これを確認するためには、稼働しているPodの中のどれかのyamlファイルを取得します。

kubectl get pods frontend-b2zdv -o yaml

その表示結果は、以下のようになります。そのfrontendReplicaSetの情報がmetadataownerReferencesフィールドにセットされています。

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2020-02-12T07:06:16Z"
  generateName: frontend-
  labels:
    tier: frontend
  name: frontend-b2zdv
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: frontend
    uid: f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf
...

テンプレートなしのPodの所有

ユーザーが問題なくベアPod(Bare Pod: ここではPodテンプレート無しのPodのこと)を作成しているとき、そのベアPodがユーザーのReplicaSetの中のいずれのセレクターともマッチしないことを確認することを強く推奨します。 この理由として、ReplicaSetは、所有対象のPodがReplicaSetのテンプレートによって指定されたPodのみに限定されていないからです(ReplicaSetは前のセクションで説明した方法によって他のPodも所有できます)。

前のセクションで取り上げたfrontendReplicaSetと、下記のマニフェストのPodをみてみます。

apiVersion: v1
kind: Pod
metadata:
  name: pod1
  labels:
    tier: frontend
spec:
  containers:
  - name: hello1
    image: gcr.io/google-samples/hello-app:2.0

---

apiVersion: v1
kind: Pod
metadata:
  name: pod2
  labels:
    tier: frontend
spec:
  containers:
  - name: hello2
    image: gcr.io/google-samples/hello-app:1.0

これらのPodはownerReferencesに何のコントローラー(もしくはオブジェクト)も指定されておらず、そしてfrontendReplicaSetにマッチするセレクターをもっており、これらのPodは即座にfrontendReplicaSetによって所有されます。

このfrontendReplicaSetがデプロイされ、初期のPodレプリカがレプリカ数の要求を満たすためにセットアップされた後で、ユーザーがそのPodを作成することを考えます。

kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml

新しいPodはそのReplicaSetによって所有され、そのReplicaSetのレプリカ数が、設定された理想のレプリカ数を超えた場合すぐにそれらのPodは削除されます。

下記のコマンドでPodを取得できます。

kubectl get pods

その表示結果で、新しいPodがすでに削除済みか、削除中のステータスになっているのを確認できます。

NAME             READY   STATUS        RESTARTS   AGE
frontend-b2zdv   1/1     Running       0          10m
frontend-vcmts   1/1     Running       0          10m
frontend-wtsmm   1/1     Running       0          10m
pod1             0/1     Terminating   0          1s
pod2             0/1     Terminating   0          1s

もしユーザーがそのPodを最初に作成する場合

kubectl apply -f http://k8s.io/examples/pods/pod-rs.yaml

そしてその後にfrontendReplicaSetを作成すると、

kubectl apply -f http://k8s.io/examples/controllers/frontend.yaml

ユーザーはそのReplicaSetが作成したPodを所有し、さらにもともと存在していたPodと今回新たに作成されたPodの数が、理想のレプリカ数になるまでPodを作成するのを確認できます。 ここでまたPodの状態を取得します。

kubectl get pods

取得結果は下記のようになります。

NAME             READY   STATUS    RESTARTS   AGE
frontend-hmmj2   1/1     Running   0          9s
pod1             1/1     Running   0          36s
pod2             1/1     Running   0          36s

この方法で、ReplicaSetはテンプレートで指定されたもの以外のPodを所有することができます。

ReplicaSetのマニフェストを記述する。

他の全てのKubernetes APIオブジェクトのように、ReplicaSetはapiVersionkindmetadataフィールドを必要とします。 ReplicaSetでは、kindフィールドの値はReplicaSetです。 Kubernetes1.9において、ReplicaSetはapps/v1というAPIバージョンが現在のバージョンで、デフォルトで有効です。apps/v1beta2というAPIバージョンは廃止されています。先ほど作成したfrontend.yamlファイルの最初の行を参考にしてください。

ReplicaSetオブジェクトの名前は、有効な DNSサブドメイン名である必要があります。

また、ReplicaSetは.spec セクションも必須です。

Pod テンプレート

.spec.templateはラベルを持つことが必要なPod テンプレート です。先ほど作成したfrontend.yamlの例では、tier: frontendというラベルを1つ持っています。 他のコントローラーがこのPodを所有しようとしないためにも、他のコントローラーのセレクターでラベルを上書きしないように注意してください。

テンプレートの再起動ポリシーのためのフィールドである.spec.template.spec.restartPolicyAlwaysのみ許可されていて、そしてそれがデフォルト値です。

Pod セレクター

.spec.selectorフィールドはラベルセレクターです。 先ほど議論したように、ReplicaSetが所有するPodを指定するためにそのラベルが使用されます。 先ほどのfrontend.yamlの例では、そのセレクターは下記のようになっていました

matchLabels:
  tier: frontend

そのReplicaSetにおいて、.spec.template.metadata.labelsフィールドの値はspec.selectorと一致しなくてはならず、一致しない場合はAPIによって拒否されます。

備考: 2つのReplicaSetが同じ.spec.selectorの値を設定しているが、それぞれ異なる.spec.template.metadata.labels.spec.template.specフィールドの値を持っていたとき、それぞれのReplicaSetはもう一方のReplicaSetによって作成されたPodを無視します。

レプリカ数について

ユーザーは.spec.replicasフィールドの値を設定することにより、いくつのPodを同時に稼働させるか指定できます。そのときReplicaSetはレプリカ数がこの値に達するまでPodを作成、または削除します。

もしユーザーが.spec.replicasを指定しない場合、デフォルト値として1がセットされます。

ReplicaSetを利用する

ReplicaSetとPodの削除

ReplicaSetとそれが所有する全てのPod削除したいときは、kubectl deleteコマンドを使ってください。
ガベージコレクターがデフォルトで自動的に全ての依存するPodを削除します。

REST APIもしくはclient-goライブラリーを使用するとき、ユーザーは-dオプションでpropagationPolicyBackgroundForegroundと指定しなくてはなりません。 例えば下記のように実行します。

kubectl proxy --port=8080
curl -X DELETE  'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"

ReplicaSetのみを削除する

ユーザーはkubectl deleteコマンドで--cascade=falseオプションを付けることにより、所有するPodに影響を与えることなくReplicaSetを削除できます。 REST APIもしくはclient-goライブラリーを使用するとき、ユーザーは-dオプションでpropagationPolicyOrphanと指定しなくてはなりません。

kubectl proxy --port=8080
curl -X DELETE  'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"

一度元のReplicaSetが削除されると、ユーザーは新しいものに置き換えるため新しいReplicaSetを作ることができます。新旧のReplicaSetの.spec.selectorの値が同じである間、新しいReplicaSetは古いReplicaSetで稼働していたPodを取り入れます。 しかし、存在するPodが新しく異なるPodテンプレートとマッチさせようとするとき、この仕組みは機能しません。 ユーザーのコントロール下において新しいspecのPodをアップデートしたい場合は、ローリングアップデートを使用してください。

PodをReplicaSetから分離させる

ユーザーはPodのラベルを変更することにより、ReplicaSetからそのPodを削除できます。この手法はデバッグや、データ修復などのためにサービスからPodを削除したいときに使用できます。 この方法で削除されたPodは自動的に新しいものに置き換えられます。(レプリカ数は変更されないものと仮定します。)

ReplicaSetのスケーリング

ReplicaSetは、ただ.spec.replicasフィールドを更新することによって簡単にスケールアップまたはスケールダウンできます。ReplicaSetコントローラーは、ラベルセレクターにマッチするような指定した数のPodが利用可能であり、操作可能であることを保証します。

HorizontalPodAutoscaler(HPA)のターゲットとしてのReplicaSet

ReplicaSetはまた、Horizontal Pod Autoscalers (HPA)のターゲットにもなることができます。 これはつまりReplicaSetがHPAによってオートスケールされうることを意味します。 ここではHPAが、前の例で作成したReplicaSetをターゲットにする例を示します。

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: frontend-scaler
spec:
  scaleTargetRef:
    kind: ReplicaSet
    name: frontend
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

このマニフェストをhpa-rs.yamlに保存し、Kubernetesクラスターに適用すると、レプリケートされたPodのCPU使用量にもとづいてターゲットのReplicaSetをオートスケールするHPAを作成します。

kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml

同様のことを行うための代替案として、kubectl autoscaleコマンドも使用できます。(こちらの方がより簡単です。)

kubectl autoscale rs frontend --max=10 --min=3 --cpu-percent=50

ReplicaSetの代替案

Deployment (推奨)

DeploymentはReplicaSetを所有することのできるオブジェクトで、宣言的なサーバサイドのローリングアップデートを介してReplicaSetとPodをアップデートできます。 ReplicaSetは単独で使用可能ですが、現在では、ReplicaSetは主にPodの作成、削除とアップデートを司るためのメカニズムとしてDeploymentによって使用されています。ユーザーがDeploymentを使用するとき、Deploymentによって作成されるReplicaSetの管理について心配する必要はありません。DeploymentはReplicaSetを所有し、管理します。 このため、もしユーザーがReplicaSetを必要とするとき、Deploymentの使用を推奨します。

ベアPod(Bare Pods)

ユーザーがPodを直接作成するケースとは異なり、ReplicaSetはNodeの故障やカーネルのアップグレードといった破壊的なNodeのメンテナンスなど、どのような理由に限らず削除または停止されたPodを置き換えます。 このため、我々はもしユーザーのアプリケーションが単一のPodのみ必要とする場合でもReplicaSetを使用することを推奨します。プロセスのスーパーバイザーについても同様に考えると、それは単一Node上での独立したプロセスの代わりに複数のNodeにまたがった複数のPodを監視します。 ReplicaSetは、Node上のいくつかのエージェント(例えば、KubeletやDocker)に対して、ローカルのコンテナ再起動を移譲します。

Job

PodをPodそれ自身で停止させたいような場合(例えば、バッチ用のジョブなど)は、ReplicaSetの代わりにJobを使用してください。

DaemonSet

マシンの監視やロギングなど、マシンレベルの機能を提供したい場合は、ReplicaSetの代わりにDaemonSetを使用してください。 これらのPodはマシン自体のライフタイムに紐づいています: そのPodは他のPodが起動する前に、そのマシン上で稼働される必要があり、マシンが再起動またはシャットダウンされるときには、安全に停止されます。

ReplicationController

ReplicaSetはReplicationControllersの後継となるものです。 この2つは、ReplicationControllerがラベルについてのユーザーガイドに書かれているように、集合ベース(set-based)のセレクター要求をサポートしていないことを除いては、同じ目的を果たし、同じようにふるまいます。
このように、ReplicaSetはReplicationControllerよりも好まれます。

3 - StatefulSet

StatefulSetはステートフルなアプリケーションを管理するためのワークロードAPIです。

StatefulSetはDeploymentとPodのセットのスケーリングを管理し、それらのPodの順序と一意性を保証 します。

Deploymentのように、StatefulSetは指定したコンテナのspecに基づいてPodを管理します。Deploymentとは異なり、StatefulSetは各Podにおいて管理が大変な同一性を維持します。これらのPodは同一のspecから作成されますが、それらは交換可能ではなく、リスケジュール処理をまたいで維持される永続的な識別子を持ちます。

ワークロードに永続性を持たせるためにストレージボリュームを使いたい場合は、解決策の1つとしてStatefulSetが利用できます。StatefulSet内の個々のPodは障害の影響を受けやすいですが、永続化したPodの識別子は既存のボリュームと障害によって置換された新しいPodの紐付けを簡単にします。

StatefulSetの使用

StatefulSetは下記の1つ以上の項目を要求するアプリケーションにおいて最適です。

  • 安定した一意のネットワーク識別子
  • 安定した永続ストレージ
  • 規則的で安全なデプロイとスケーリング
  • 規則的で自動化されたローリングアップデート

上記において安定とは、Podのスケジュール(または再スケジュール)をまたいでも永続的であることと同義です。 もしアプリケーションが安定したネットワーク識別子と規則的なデプロイや削除、スケーリングを全く要求しない場合、ユーザーはステートレスなレプリカのセットを提供するワークロードを使ってアプリケーションをデプロイするべきです。 DeploymentReplicaSetのようなコントローラーはこのようなステートレスな要求に対して最適です。

制限事項

  • 提供されたPodのストレージは、要求されたstorage classにもとづいてPersistentVolume Provisionerによってプロビジョンされるか、管理者によって事前にプロビジョンされなくてはなりません。
  • StatefulSetの削除もしくはスケールダウンをすることにより、StatefulSetに関連したボリュームは削除されません 。 これはデータ安全性のためで、関連するStatefulSetのリソース全てを自動的に削除するよりもたいてい有効です。
  • StatefulSetは現在、Podのネットワークアイデンティティーに責務をもつためにHeadless Serviceを要求します。ユーザーはこのServiceを作成する責任があります。
  • StatefulSetは、StatefulSetが削除されたときにPodの停止を行うことを保証していません。StatefulSetにおいて、規則的で安全なPodの停止を行う場合、削除のために事前にそのStatefulSetの数を0にスケールダウンさせることが可能です。
  • デフォルト設定のPod管理ポリシー (OrderedReady)によってローリングアップデートを行う場合、修復のための手動介入を要求するようなブロークンな状態に遷移させることが可能です。

コンポーネント

下記の例は、StatefulSetのコンポーネントのデモンストレーションとなります。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # .spec.template.metadata.labelsの値と一致する必要があります
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # .spec.selector.matchLabelsの値と一致する必要があります
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi

上記の例では、

  • nginxという名前のHeadlessServiceは、ネットワークドメインをコントロールするために使われます。
  • webという名前のStatefulSetは、specで3つのnginxコンテナのレプリカを持ち、そのコンテナはそれぞれ別のPodで稼働するように設定されています。
  • volumeClaimTemplatesは、PersistentVolumeプロビジョナーによってプロビジョンされたPersistentVolumeを使って安定したストレージを提供します。

StatefulSetの名前は有効な名前である必要があります。

Podセレクター

ユーザーは、StatefulSetの.spec.template.metadata.labelsのラベルと一致させるため、StatefulSetの.spec.selectorフィールドをセットしなくてはなりません。Kubernetes1.8以前では、.spec.selectorフィールドは省略された場合デフォルト値になります。Kubernetes1.8とそれ以降のバージョンでは、ラベルに一致するPodセレクターの指定がない場合はStatefulSetの作成時にバリデーションエラーになります。

Podアイデンティティー

StatefulSetのPodは、順番を示す番号、安定したネットワークアイデンティティー、安定したストレージからなる一意なアイデンティティーを持ちます。 そのアイデンティティーはどのNode上にスケジュール(もしくは再スケジュール)されるかに関わらず、そのPodに紐付きます。

順序インデックス

N個のレプリカをもったStatefulSetにおいて、StatefulSet内の各Podは、0からはじまりN-1までの整数値を順番に割り当てられ、そのStatefulSetにおいては一意となります。

安定したネットワークID

StatefulSet内の各Podは、そのStatefulSet名とPodの順序番号から派生してホストネームが割り当てられます。 作成されたホストネームの形式は$(StatefulSet名)-$(順序番号)となります。先ほどの上記の例では、web-0,web-1,web-2という3つのPodが作成されます。 StatefulSetは、PodのドメインをコントロールするためにHeadless Serviceを使うことができます。 このHeadless Serviceによって管理されたドメインは$(Service名).$(ネームスペース).svc.cluster.local形式となり、"cluster.local"というのはそのクラスターのドメインとなります。 各Podが作成されると、Podは$(Pod名).$(管理するServiceドメイン名)に一致するDNSサブドメインを取得し、管理するServiceはStatefulSetのserviceNameで定義されます。

クラスターでのDNSの設定方法によっては、新たに起動されたPodのDNS名をすぐに検索できない場合があります。 この動作は、クラスター内の他のクライアントが、Podが作成される前にそのPodのホスト名に対するクエリーをすでに送信していた場合に発生する可能性があります。 (DNSでは通常)ネガティブキャッシュは、Podの起動後でも、少なくとも数秒間、以前に失敗したルックアップの結果が記憶され、再利用されることを意味します。

Podが作成された後、速やかにPodを検出する必要がある場合は、いくつかのオプションがあります。

  • DNSルックアップに依存するのではなく、Kubernetes APIに直接(例えばwatchを使って)問い合わせる。
  • Kubernetes DNS プロバイダーのキャッシュ時間を短縮する(これは現在30秒キャッシュされるようになっているCoreDNSのConfigMapを編集することを意味しています。)。

制限事項セクションで言及したように、ユーザーはPodのネットワークアイデンティティーのためにHeadless Serviceを作成する責任があります。

ここで、クラスタードメイン、Service名、StatefulSet名の選択と、それらがStatefulSetのPodのDNS名にどう影響するかの例をあげます。

Cluster Domain Service (ns/name) StatefulSet (ns/name) StatefulSet Domain Pod DNS Pod Hostname
cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1}
cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1}
kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1}
備考: クラスタードメインはその他の設定がされない限り、cluster.localにセットされます。

安定したストレージ

Kubernetesは各VolumeClaimTemplateに対して、1つのPersistentVolumeを作成します。上記のnginxの例において、各Podはmy-storage-classというStorageClassをもち、1Gibのストレージ容量を持った単一のPersistentVolumeを受け取ります。もしStorageClassが指定されていない場合、デフォルトのStorageClassが使用されます。PodがNode上にスケジュール(もしくは再スケジュール)されたとき、そのvolumeMountsはPersistentVolume Claimに関連したPersistentVolumeをマウントします。 注意点として、PodのPersistentVolume Claimと関連したPersistentVolumeは、PodやStatefulSetが削除されたときに削除されません。 削除する場合は手動で行わなければなりません。

Podのネームラベル

StatefulSet コントローラー がPodを作成したとき、Podの名前として、statefulset.kubernetes.io/pod-nameにラベルを追加します。このラベルによってユーザーはServiceにStatefulSet内の指定したPodを割り当てることができます。

デプロイとスケーリングの保証

  • N個のレプリカをもつStatefulSetにおいて、Podがデプロイされるとき、それらのPodは{0..N-1}の番号で順番に作成されます。
  • Podが削除されるとき、それらのPodは{N-1..0}の番号で降順に削除されます。
  • Podに対してスケーリングオプションが適用される前に、そのPodの前の順番の全てのPodがRunningかつReady状態になっていなくてはなりません。
  • Podが停止される前に、そのPodの番号より大きい番号を持つの全てのPodは完全にシャットダウンされていなくてはなりません。

StatefulSetはpod.Spec.TerminationGracePeriodSecondsを0に指定すべきではありません。これは不安全で、やらないことを強く推奨します。さらなる説明としては、StatefulSetのPodの強制削除を参照してください。

上記の例のnginxが作成されたとき、3つのPodはweb-0web-1web-2の順番でデプロイされます。web-1web-0RunningかつReady状態になるまでは決してデプロイされないのと、同様にweb-2web-1がRunningかつReady状態にならないとデプロイされません。もしweb-0web-1がRunningかつReady状態になった後だが、web-2が起動する前に失敗した場合、web-2web-0の再起動が成功し、RunningかつReady状態にならないと再起動されません。

もしユーザーがreplicas=1といったようにStatefulSetにパッチをあてることにより、デプロイされたものをスケールすることになった場合、web-2は最初に停止されます。web-1web-2が完全にシャットダウンされ削除されるまでは、停止されません。もしweb-0が、web-2が完全に停止され削除された後だが、web-1の停止の前に失敗した場合、web-1web-0がRunningかつReady状態になるまでは停止されません。

Podの管理ポリシー

Kubernetes1.7とそれ以降のバージョンでは、StatefulSetは.spec.podManagementPolicyフィールドを介して、Podの一意性とアイデンティティーを保証します。

OrderedReadyなPod管理

OrderedReadyなPod管理はStatefulSetにおいてデフォルトです。これはデプロイとスケーリングの保証に記載されている項目の振る舞いを実装します。

並行なPod管理

ParallelなPod管理は、StatefulSetコントローラーに対して、他のPodが起動や停止される前にそのPodが完全に起動し準備完了になるか停止するのを待つことなく、Podが並行に起動もしくは停止するように指示します。

アップデートストラテジー

Kubernetes1.7とそれ以降のバージョンにおいて、StatefulSetの.spec.updateStrategyフィールドで、コンテナの自動のローリングアップデートの設定やラベル、リソースのリクエストとリミットや、StatefulSet内のPodのアノテーションを指定できます。

OnDelete

OnDeleteというアップデートストラテジーは、レガシーな(Kubernetes1.6以前)振る舞いとなります。StatefulSetの.spec.updateStrategy.typeOnDeleteにセットされていたとき、そのStatefulSetコントローラーはStatefulSet内でPodを自動的に更新しません。StatefulSetの.spec.template項目の修正を反映した新しいPodの作成をコントローラーに支持するためには、ユーザーは手動でPodを削除しなければなりません。

RollingUpdate

RollingUpdateというアップデートストラテジーは、StatefulSet内のPodに対する自動化されたローリングアップデートの機能を実装します。これは.spec.updateStrategyフィールドが未指定の場合のデフォルトのストラテジーです。StatefulSetの.spec.updateStrategy.typeRollingUpdateにセットされたとき、そのStatefulSetコントローラーは、StatefulSet内のPodを削除し、再作成します。これはPodの停止(Podの番号の降順)と同じ順番で、一度に1つのPodを更新します。コントローラーは、その前のPodの状態がRunningかつReady状態になるまで次のPodの更新を待ちます。

パーティション

RollingUpdateというアップデートストラテジーは、.spec.updateStrategy.rollingUpdate.partitionを指定することにより、パーティションに分けることができます。もしパーティションが指定されていたとき、そのパーティションの値と等しいか、大きい番号を持つPodが更新されます。パーティションの値より小さい番号を持つPodは更新されず、たとえそれらのPodが削除されたとしても、それらのPodは以前のバージョンで再作成されます。もしStatefulSetの.spec.updateStrategy.rollingUpdate.partitionが、.spec.replicasより大きい場合、.spec.templateへの更新はPodに反映されません。 多くのケースの場合、ユーザーはパーティションを使う必要はありませんが、もし一部の更新を行う場合や、カナリー版のバージョンをロールアウトする場合や、段階的ロールアウトを行う場合に最適です。

強制ロールバック

デフォルトのPod管理ポリシー(OrderedReady)によるローリングアップデートを行う際、修復のために手作業が必要な状態にすることが可能です。

もしユーザーが、決してRunningかつReady状態にならないような設定になるようにPodテンプレートを更新した場合(例えば、不正なバイナリや、アプリケーションレベルの設定エラーなど)、StatefulSetはロールアウトを停止し、待機します。

この状態では、Podテンプレートを正常な状態に戻すだけでは不十分です。既知の問題によって、StatefulSetは元の正常な状態へ戻す前に、壊れたPodがReady状態(決して起こりえない)に戻るのを待ち続けます。

そのテンプレートを戻したあと、ユーザーはまたStatefulSetが異常状態で稼働しようとしていたPodをすべて削除する必要があります。StatefulSetはその戻されたテンプレートを使ってPodの再作成を始めます。

次の項目

4 - DaemonSet

DaemonSet は全て(またはいくつか)のNodeが単一のPodのコピーを稼働させることを保証します。Nodeがクラスターに追加されるとき、PodがNode上に追加されます。Nodeがクラスターから削除されたとき、それらのPodはガーベージコレクターにより除去されます。DaemonSetの削除により、DaemonSetが作成したPodもクリーンアップします。

DaemonSetのいくつかの典型的な使用例は以下の通りです。

  • クラスターのストレージデーモンを全てのNode上で稼働させる。
  • ログ集計デーモンを全てのNode上で稼働させる。
  • Nodeのモニタリングデーモンを全てのNode上で稼働させる。

シンプルなケースとして、各タイプのデーモンにおいて、全てのNodeをカバーする1つのDaemonSetが使用されるケースがあります。さらに複雑な設定では、単一のタイプのデーモン用ですが、異なるフラグや、異なるハードウェアタイプに対するメモリー、CPUリクエストを要求する複数のDaemonSetを使用するケースもあります。

DaemonSet Specの記述

DaemonSetの作成

ユーザーはYAMLファイル内でDaemonSetの設定を記述することができます。例えば、下記のdaemonset.yamlファイルではfluentd-elasticsearchというDockerイメージを稼働させるDaemonSetの設定を記述します。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

YAMLファイルに基づいてDaemonSetを作成します。

kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml

必須のフィールド

他の全てのKubernetesの設定と同様に、DaemonSetはapiVersionkindmetadataフィールドが必須となります。設定ファイルの活用法に関する一般的な情報は、ステートレスアプリケーションの稼働コンテナの設定kubectlを用いたオブジェクトの管理といったドキュメントを参照ください。

DaemonSetオブジェクトの名前は、有効な DNSサブドメイン名である必要があります。

また、DaemonSetにおいて.specセクションも必須となります。

Podテンプレート

.spec.template.spec内での必須のフィールドの1つです。

.spec.templatePodテンプレートとなります。これはフィールドがネストされていて、apiVersionkindをもたないことを除いては、Podのテンプレートと同じスキーマとなります。

Podに対する必須のフィールドに加えて、DaemonSet内のPodテンプレートは適切なラベルを指定しなくてはなりません(Podセレクターの項目を参照ください)。

DaemonSet内のPodテンプレートでは、RestartPolicyフィールドを指定せずにデフォルトのAlwaysを使用するか、明示的にAlwaysを設定するかのどちらかである必要があります。

Podセレクター

.spec.selectorフィールドはPodセレクターとなります。これはJob.spec.selectorと同じものです。

Kubernetes1.8のように、ユーザーは.spec.templateのラベルにマッチするPodセレクターを指定しなくてはいけません。Podセレクターは、値を空のままにしてもデフォルト設定にならなくなりました。セレクターのデフォルト化はkubectl applyと互換性はありません。また、一度DaemonSetが作成されると、その.spec.selectorは変更不可能になります。Podセレクターの変更は、意図しないPodの孤立を引き起こし、ユーザーにとってやっかいなものとなります。

.spec.selectorは2つのフィールドからなるオブジェクトです。

  • matchLabels - ReplicationController.spec.selectorと同じように機能します。
  • matchExpressions - キーと、値のリストとさらにはそれらのキーとバリューに関連したオペレーターを指定することにより、より洗練された形式のセレクターを構成できます。

上記の2つが指定された場合は、2つの条件をANDでどちらも満たすものを結果として返します。

もしspec.selectorが指定されたとき、.spec.template.metadata.labelsとマッチしなければなりません。この2つの値がマッチしない設定をした場合、APIによってリジェクトされます。

選択したNode上でPodを稼働させる

もしユーザーが.spec.template.spec.nodeSelectorを指定したとき、DaemonSetコントローラーは、そのnode selectorにマッチするPodをNode上に作成します。同様に、もし.spec.template.spec.affinityを指定したとき、DaemonSetコントローラーはnode affinityマッチするPodをNode上に作成します。 もしユーザーがどちらも指定しないとき、DaemonSetコントローラーは全てのNode上にPodを作成します。

Daemon Podがどのようにスケジューリングされるか

デフォルトスケジューラーによってスケジューリングされる場合

FEATURE STATE: Kubernetes v1.22 [stable]

DaemonSetは全ての利用可能なNodeが単一のPodのコピーを稼働させることを保証します。通常、Podが稼働するNodeはKubernetesスケジューラーによって選択されます。しかし、DaemonSetのPodは代わりにDaemonSetコントローラーによって作成され、スケジューリングされます。
下記の問題について説明します:

  • 矛盾するPodのふるまい: スケジューリングされるのを待っている通常のPodは、作成されているがPending状態となりますが、DaemonSetのPodはPending状態で作成されません。これはユーザーにとって困惑するものです。
  • Podプリエンプション(Pod preemption)はデフォルトスケジューラーによってハンドルされます。もしプリエンプションが有効な場合、そのDaemonSetコントローラーはPodの優先順位とプリエンプションを考慮することなくスケジューリングの判断を行います。

ScheduleDaemonSetPodsは、DaemonSetのPodに対してNodeAffinity項目を追加することにより、DaemonSetコントローラーの代わりにデフォルトスケジューラーを使ってDaemonSetのスケジュールを可能にします。その際に、デフォルトスケジューラーはPodをターゲットのホストにバインドします。もしDaemonSetのNodeAffinityが存在するとき、それは新しいものに置き換えられます(ターゲットホストを選択する前に、元のNodeAffinityが考慮されます)。DaemonSetコントローラーはDaemonSetのPodの作成や修正を行うときのみそれらの操作を実施します。そしてDaemonSetの.spec.templateフィールドに対しては何も変更が加えられません。

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - target-host-name

さらに、node.kubernetes.io/unschedulable:NoScheduleというtolarationがDaemonSetのPodに自動的に追加されます。デフォルトスケジューラーは、DaemonSetのPodのスケジューリングのときに、unschedulableなNodeを無視します。

TaintsとTolerations

DaemonSetのPodはTaintsとTolerationsの設定を尊重します。下記のTolerationsは、関連する機能によって自動的にDaemonSetのPodに追加されます。

Toleration Key Effect Version Description
node.kubernetes.io/not-ready NoExecute 1.13+ DaemonSetのPodはネットワーク分割のようなNodeの問題が発生したときに除外されません。
node.kubernetes.io/unreachable NoExecute 1.13+ DaemonSetのPodはネットワーク分割のようなNodeの問題が発生したときに除外されません。
node.kubernetes.io/disk-pressure NoSchedule 1.8+
node.kubernetes.io/memory-pressure NoSchedule 1.8+
node.kubernetes.io/unschedulable NoSchedule 1.12+ DaemonSetのPodはデフォルトスケジューラーによってスケジュール不可能な属性を許容(tolerate)します。
node.kubernetes.io/network-unavailable NoSchedule 1.12+ ホストネットワークを使うDaemonSetのPodはデフォルトスケジューラーによってネットワーク利用不可能な属性を許容(tolerate)します。

Daemon Podとのコミュニケーション

DaemonSet内のPodとのコミュニケーションをする際に考えられるパターンは以下の通りです。:

  • Push: DaemonSet内のPodは他のサービスに対して更新情報を送信するように設定されます。
  • NodeIPとKnown Port: PodがNodeIPを介して疎通できるようにするため、DaemonSet内のPodはhostPortを使用できます。慣例により、クライアントはNodeIPのリストとポートを知っています。
  • DNS: 同じPodセレクターを持つHeadlessServiceを作成し、endpointsリソースを使ってDaemonSetを探すか、DNSから複数のAレコードを取得します。
  • Service: 同じPodセレクターを持つServiceを作成し、複数のうちのいずれかのNode上のDaemonに疎通させるためにそのServiceを使います。

DaemonSetの更新

もしNodeラベルが変更されたとき、そのDaemonSetは直ちに新しくマッチしたNodeにPodを追加し、マッチしなくなったNodeからPodを削除します。

ユーザーはDaemonSetが作成したPodを修正可能です。しかし、Podは全てのフィールドの更新を許可していません。また、DaemonSetコントローラーは次のNode(同じ名前でも)が作成されたときにオリジナルのテンプレートを使ってPodを作成します。

ユーザーはDaemonSetを削除可能です。kubectlコマンドで--cascade=falseを指定するとDaemonSetのPodはNode上に残り続けます。その後、同じセレクターで新しいDaemonSetを作成すると、新しいDaemonSetは既存のPodを再利用します。PodでDaemonSetを置き換える必要がある場合は、updateStrategyに従ってそれらを置き換えます。

ユーザーはDaemonSet上でローリングアップデートの実施が可能です。

DaemonSetの代替案

Initスクリプト

Node上で直接起動することにより(例: initupstartdsystemdを使用する)、デーモンプロセスを稼働することが可能です。この方法は非常に良いですが、このようなプロセスをDaemonSetを介して起動することはいくつかの利点があります。

  • アプリケーションと同じ方法でデーモンの監視とログの管理ができる。
  • デーモンとアプリケーションで同じ設定用の言語とツール(例: Podテンプレート、kubectl)を使える。
  • リソースリミットを使ったコンテナ内でデーモンを稼働させることにより、デーモンとアプリケーションコンテナの分離を促進します。しかし、これはPod内でなく、コンテナ内でデーモンを稼働させることにより可能です(Dockerを介して直接起動する)。

ベアPod

特定のNode上で稼働するように指定したPodを直接作成することは可能です。しかし、DaemonSetはNodeの故障やNodeの破壊的なメンテナンスやカーネルのアップグレードなど、どのような理由に限らず、削除されたもしくは停止されたPodを置き換えます。このような理由で、ユーザーはPod単体を作成するよりもむしろDaemonSetを使うべきです。

静的Pod Pods

Kubeletによって監視されているディレクトリに対してファイルを書き込むことによって、Podを作成することが可能です。これは静的Podと呼ばれます。DaemonSetと違い、静的Podはkubectlや他のKubernetes APIクライアントで管理できません。静的PodはApiServerに依存しておらず、クラスターの自立起動時に最適です。また、静的Podは将来的には廃止される予定です。

Deployment

DaemonSetは、Podの作成し、そのPodが停止されることのないプロセスを持つことにおいてDeploymentと同様です(例: webサーバー、ストレージサーバー)。

フロントエンドのようなServiceのように、どのホスト上にPodが稼働するか制御するよりも、レプリカ数をスケールアップまたはスケールダウンしたりローリングアップデートする方が重要であるような、状態をもたないServiceに対してDeploymentを使ってください。 Podのコピーが全てまたは特定のホスト上で常に稼働していることが重要な場合や、他のPodの前に起動させる必要があるときにDaemonSetを使ってください。

5 - ガベージコレクション

Kubernetesのガベージコレクターの役割は、かつてオーナーがいたが、現時点でもはやオーナーがいないようなオブジェクトの削除を行うことです。

オーナーとその従属オブジェクト

いくつかのKubernetesオブジェクトは他のオブジェクトのオーナーとなります。例えば、ReplicaSetはPodのセットに対するオーナーです。オーナーによって所有されたオブジェクトは、オーナーオブジェクトの従属オブジェクト(Dependents) と呼ばれます。全ての従属オブジェクトは、オーナーオブジェクトを指し示すmetadata.ownerReferencesというフィールドを持ちます。

時々、KubernetesはownerReferenceフィールドに値を自動的にセットします。例えば、ユーザーがReplicaSetを作成したとき、KubernetesはReplicaSet内の各PodのownerReferenceフィールドに自動的に値をセットします。Kubernetes1.8において、KubernetesはReplicaController、ReplicaSet、StatefulSet、DaemonSet、Deployment、Job、CronJobによって作成され、適用されたオブジェクトのownerReferenceフィールドに自動的にその値をセットします。

ユーザーはまたownerReferenceフィールドに手動で値をセットすることにより、オーナーと従属オブジェクト間の関係を指定することができます。

下記の例は、3つのPodを持つReplicaSetの設定ファイルとなります。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: my-repset
spec:
  replicas: 3
  selector:
    matchLabels:
      pod-is-for: garbage-collection-example
  template:
    metadata:
      labels:
        pod-is-for: garbage-collection-example
    spec:
      containers:
      - name: nginx
        image: nginx

もしユーザーがReplicaSetを作成し、Podのメタデータを見る時、ownerReferenceフィールドの値を確認できます。

kubectl apply -f https://k8s.io/examples/controllers/replicaset.yaml
kubectl get pods --output=yaml

その出力結果によると、そのPodのオーナーはmy-repsetという名前のReplicaSetです。

apiVersion: v1
kind: Pod
metadata:
  ...
  ownerReferences:
  - apiVersion: apps/v1
    controller: true
    blockOwnerDeletion: true
    kind: ReplicaSet
    name: my-repset
    uid: d9607e19-f88f-11e6-a518-42010a800195
  ...
備考:

ネームスペースをまたいだownerReferenceは意図的に許可されていません。これは以下のことを意味します。

  1. ネームスペース内のスコープの従属オブジェクトは、同一のネームスペース内のオーナーと、クラスターのスコープ内のオーナーのみ指定できます。
  2. クラスターのスコープ内の従属オブジェクトは、クラスターのスコープ内のオーナーオブジェクトのみ指定でき、ネームスペース内のスコープのオーナーオブジェクトは指定できません。

ガベージコレクターがどのように従属オブジェクトの削除をするかを制御する

ユーザーがオブジェクトを削除するとき、それに紐づく従属オブジェクトも自動で削除するか指定できます。従属オブジェクトの自動削除は、カスケード削除(Cascading deletion) と呼ばれます。カスケード削除 には2つのモードがあり、バックグラウンドフォアグラウンド があります。

もしユーザーが、従属オブジェクトの自動削除なしにあるオブジェクトを削除する場合、その従属オブジェクトはみなしご(orphaned) と呼ばれます。

フォアグラウンドのカスケード削除

フォアグラウンドのカスケード削除 において、そのルートオブジェクトは最初に"削除処理中"という状態に遷移します。その削除処理中 状態において、下記の項目は正となります。

  • そのオブジェクトはREST APIを介して確認可能です。
  • そのオブジェクトのdeletionTimestampがセットされます。
  • そのオブジェクトのmetadata.finalizersフィールドは、foregroundDeletionという値を含みます。

一度"削除処理中"状態に遷移すると、そのガベージコレクターはオブジェクトの従属オブジェクトを削除します。一度そのガベージコレクターが全ての”ブロッキングしている”従属オブジェクトを削除すると(ownerReference.blockOwnerDeletion=trueという値を持つオブジェクト)、それはオーナーのオブジェクトも削除します。

注意点として、"フォアグラウンドのカスケード削除"において、ownerReference.blockOwnerDeletion=trueフィールドを持つ従属オブジェクトのみ、そのオーナーオブジェクトの削除をブロックします。 Kubernetes1.7では、認証されていない従属オブジェクトがオーナーオブジェクトの削除を遅らせることができないようにするためにアドミッションコントローラーが追加され、それは、オーナーオブジェクトの削除パーミッションに基づいてblockOwnerDeletionの値がtrueに設定してユーザーアクセスをコントロールします。

もしオブジェクトのownerReferencesフィールドがコントローラー(DeploymentやReplicaSetなど)によってセットされている場合、blockOwnerDeletionは自動的にセットされ、ユーザーはこのフィールドを手動で修正する必要はありません。

バックグラウンドのカスケード削除

バックグラウンドのカスケード削除 において、Kubernetesはそのオーナーオブジェクトを即座に削除し、ガベージコレクションはその従属オブジェクトをバックグラウンドで削除します。

カスケード削除ポリシーの設定

カスケード削除ポリシーを制御するためには、オブジェクトをいつ設定するかdeleteOptions引数上のpropagationPolicyフィールドに設定してください。設定可能な値はOrphanForeground、もしくはBackgroundのどれかです。

下記のコマンドは従属オブジェクトをバックグラウンドで削除する例です。

kubectl proxy --port=8080
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
  -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
  -H "Content-Type: application/json"

下記のコマンドは従属オブジェクトをフォアグラウンドで削除する例です。

kubectl proxy --port=8080
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
  -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
  -H "Content-Type: application/json"

下記のコマンドは従属オブジェクトをみなしご状態になった従属オブジェクトの例です。

kubectl proxy --port=8080
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
  -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
  -H "Content-Type: application/json"

kubectlもまたカスケード削除をサポートしています。
kubectlを使って従属オブジェクトを自動的に削除するためには、--cascadeをtrueにセットしてください。 従属オブジェクトを削除せず、みなしご状態にするには--cascadeをfalseにセットしてください。 --cascadeオプションのデフォルト値はtrueになります。

下記のコマンドは、ReplicaSetを削除し、その従属オブジェクトをみなしご状態にします。

kubectl delete replicaset my-repset --cascade=false

Deploymentsに関する追記事項

Kubernetes1.7以前では、Deploymentに対するカスケード削除において、作成されたReplicaSetだけでなく、それらのPodも削除するためには、ユーザーはpropagationPolicy: Foregroundと指定しなくてはなりません 。もしこのタイプのpropagationPolicyが使われなかった場合、そのReplicaSetは削除されますが、そのPodは削除されずみなしご状態になります。
さらなる詳細に関してはkubeadm/#149を参照してください。

既知の問題について

#26120にてイシューがトラックされています。

次の項目

Design Doc 1

Design Doc 2

6 - 終了したリソースのためのTTLコントローラー(TTL Controller for Finished Resources)

FEATURE STATE: Kubernetes v1.12 [alpha]

TTLコントローラーは実行を終えたリソースオブジェクトのライフタイムを制御するためのTTL (time to live) メカニズムを提供します。
TTLコントローラーは現在Jobのみ扱っていて、将来的にPodやカスタムリソースなど、他のリソースの実行終了を扱えるように拡張される予定です。

α版の免責事項: この機能は現在α版の機能で、kube-apiserverとkube-controller-managerのFeature GateTTLAfterFinishedを有効にすることで使用可能です。

TTLコントローラー

TTLコントローラーは現在Jobに対してのみサポートされています。クラスターオペレーターはこののように、Jobの.spec.ttlSecondsAfterFinishedフィールドを指定することにより、終了したJob(完了したもしくは失敗した)を自動的に削除するためにこの機能を使うことができます。
TTLコントローラーは、そのリソースが終了したあと指定したTTLの秒数後に削除できるか推定します。言い換えると、そのTTLが期限切れになると、TTLコントローラーがリソースをクリーンアップするときに、そのリソースに紐づく従属オブジェクトも一緒に連続で削除します。注意点として、リソースが削除されるとき、ファイナライザーのようなライフサイクルに関する保証は尊重されます。

TTL秒はいつでもセット可能です。下記はJobの.spec.ttlSecondsAfterFinishedフィールドのセットに関するいくつかの例です。

  • Jobがその終了後にいくつか時間がたった後に自動的にクリーンアップできるように、そのリソースマニフェストにこの値を指定します。
  • この新しい機能を適用させるために、存在していてすでに終了したリソースに対してこのフィールドをセットします。
  • リソース作成時に、このフィールドを動的にセットするために、管理webhookの変更をさせます。クラスター管理者は、終了したリソースに対して、このTTLポリシーを強制するために使うことができます。
  • リソースが終了した後に、このフィールドを動的にセットしたり、リソースステータスやラベルなどの値に基づいて異なるTTL値を選択するために、管理webhookの変更をさせます。

注意

TTL秒の更新

注意点として、Jobの.spec.ttlSecondsAfterFinishedフィールドといったTTL期間はリソースが作成された後、もしくは終了した後に変更できます。しかし、一度Jobが削除可能(TTLの期限が切れたとき)になると、それがたとえTTLを伸ばすような更新に対してAPIのレスポンスで成功したと返されたとしても、そのシステムはJobが稼働し続けることをもはや保証しません。

タイムスキュー(Time Skew)

TTLコントローラーが、TTL値が期限切れかそうでないかを決定するためにKubernetesリソース内に保存されたタイムスタンプを使うため、この機能はクラスター内のタイムスキュー(時刻のずれ)に対してセンシティブとなります。タイムスキューは、誤った時間にTTLコントローラーに対してリソースオブジェクトのクリーンアップしてしまうことを引き起こすものです。

Kubernetesにおいてタイムスキューを避けるために、全てのNode上でNTPの稼働を必須とします(#6159を参照してください)。クロックは常に正しいものではありませんが、Node間におけるその差はとても小さいものとなります。TTLに0でない値をセットするときにこのリスクに対して注意してください。

次の項目

7 - CronJob

FEATURE STATE: Kubernetes v1.8 [beta]

CronJob は繰り返しのスケジュールによってJobを作成します。

CronJob オブジェクトとは crontab (cron table)ファイルでみられる一行のようなものです。 Cron形式で記述された指定のスケジュールの基づき、定期的にジョブが実行されます。

注意:

すべてのCronJobスケジュール: 時刻はジョブが開始されたkube-controller-managerのタイムゾーンに基づいています。

コントロールプレーンがkube-controller-managerをPodもしくは素のコンテナで実行している場合、CronJobコントローラーのタイムゾーンとして、kube-controller-managerコンテナに設定されたタイムゾーンを使用します。

CronJobリソースのためのマニフェストを作成する場合、その名前が有効なDNSサブドメイン名か確認してください。 名前は52文字を超えることはできません。これはCronJobコントローラーが自動的に、与えられたジョブ名に11文字を追加し、ジョブ名の長さは最大で63文字以内という制約があるためです。

CronJob

CronJobは、バックアップの実行やメール送信のような定期的であったり頻発するタスクの作成に役立ちます。 CronJobは、クラスターがアイドル状態になりそうなときにJobをスケジューリングするなど、特定の時間に個々のタスクをスケジュールすることもできます。

このCronJobマニフェスト例は、毎分ごとに現在の時刻とhelloメッセージを表示します。

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

(Running Automated Tasks with a CronJobではこの例をより詳しく説明しています。).

CronJobの制限

cronジョブは一度のスケジュール実行につき、 おおよそ 1つのジョブオブジェクトを作成します。ここで おおよそ と言っているのは、ある状況下では2つのジョブが作成される、もしくは1つも作成されない場合があるためです。通常、このようなことが起こらないようになっていますが、完全に防ぐことはできません。したがって、ジョブは 冪等 であるべきです。

startingDeadlineSecondsが大きな値、もしくは設定されていない(デフォルト)、そして、concurrencyPolicyAllowに設定している場合には、少なくとも一度、ジョブが実行されることを保証します。

最後にスケジュールされた時刻から現在までの間に、CronJobコントローラーはどれだけスケジュールが間に合わなかったのかをCronJobごとにチェックします。もし、100回以上スケジュールが失敗していると、ジョブは開始されずに、ログにエラーが記録されます。

Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.

startingDeadlineSecondsフィールドが設定されると(nilではない)、最後に実行された時刻から現在までではなく、startingDeadlineSecondsの値から現在までで、どれだけジョブを逃したのかをコントローラーが数えます。 startingDeadlineSeconds200の場合、過去200秒間にジョブが失敗した回数を記録します。

スケジュールされた時間にCronJobが作成できないと、失敗したとみなされます。たとえば、concurrencyPolicyForbidに設定されている場合、前回のスケジュールがまだ実行中にCronJobをスケジュールしようとすると、CronJobは作成されません。

例として、CronJobが08:30:00を開始時刻として1分ごとに新しいJobをスケジュールするように設定され、startingDeadlineSecondsフィールドが設定されていない場合を想定します。CronJobコントローラーが08:29:00 から10:21:00の間にダウンしていた場合、スケジューリングを逃したジョブの数が100を超えているため、ジョブは開始されません。

このコンセプトをさらに掘り下げるために、CronJobが08:30:00から1分ごとに新しいJobを作成し、startingDeadlineSecondsが200秒に設定されている場合を想定します。CronJobコントローラーが前回の例と同じ期間(08:29:00 から10:21:00まで)にダウンしている場合でも、10:22:00時点でJobはまだ動作しています。このようなことは、過去200秒間(言い換えると、3回の失敗)に何回スケジュールが間に合わなかったをコントローラーが確認するときに発生します。これは最後にスケジュールされた時間から今までのものではありません。

CronJobはスケジュールに一致するJobの作成にのみ関与するのに対して、JobはJobが示すPod管理を担います。

次の項目

Cron表現形式では、CronJobのscheduleフィールドのフォーマットを説明しています。

cronジョブの作成や動作の説明、CronJobマニフェストの例については、Running automated tasks with cron jobsを見てください。