訳しながら理解していくKubernetes_ StatefulSets編

# はじめに
Kubernetesのドキュメントって英語だし、英検3級レベルで英語力のない私にはつらい・・・
そして、一回(google翻訳を使って)訳しながら読んでまた忘れてまた(google翻訳を使って)訳すを繰り返すのをやめたい。
調べるときは全文を見ずに、必要な部分だけを見てたりするので、公式ドキュメントを訳しながら全体を理解していこうと思う。

英語読むのめんどくせーーーとなっている人の助けになればと思い公開した

今回は [StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)


## 注意事項
* 基本的にGoogle翻訳のまんまです。
* 一応、意味が分かるようには訳してるつもりですが、ちょいちょい意味分からない部分もあります。  
誤訳がある可能性があるので、最後はちゃんと公式ドキュメントを読みましょう
* 私の知りたい部分からやるので、訳す部分はバラバラになります。
* 公式ドキュメントに記載されていない部分(自分で調べた部分とか)は_italic_で記載しています。
* V1.11でのドキュメントを記載


## StatefulSets

StatefulSetは、ステートフルなアプリケーションを管理するために使用されるワークロードAPIオブジェクトです。

注：StatefulSetは1.9で安定(stable)しています（GA）。

一連のPodsの配置とスケーリングを管理し、これらのPodsの順序と一意性について保証します。

Deploymentと同様に、StatefulSetは、同一のコンテナ仕様に基づいたPodsを管理します。Deploymentとは異なり、StatefulSetはそれぞれのPodsに固定されたIDを保持します。これらのポッドは同じ仕様で作成されていますが、互換性はありません。各ポッドは、どの再スケジューリングでも維持される永続的な識別子を持っています。

StatefulSetは、他のコントローラと同じパターンで動作します。StatefulSetオブジェクトで目的の状態を定義すると、StatefulSet controllerは現在の状態から必要な更新を行います。

## Using StatefulSets
StatefulSetは、次のうちの1つ以上を必要とするアプリケーションにとって有益です。

* 安定したユニークなネットワーク識別子。
* 安定した永続ストレージ。
* 順序付けされたgracefulなdeploymentとスケーリング。
* 順序付けされたgracefulな削除と終了。
* 順序付けされたrolling update。

---
上記において、stableはPod（再）スケジューリングの持続性と同義です。アプリケーションが安定した識別子を必要とせず、デプロイメント、削除、スケーリングを命じられた場合は、ステートレスレプリカのセットを提供するコントローラーでアプリケーションをデプロイする必要があります。DeploymentやReplicaSetなどのコントローラは、ステートレスなニーズに適しています。

## Limitations

* StatefulSetは1.9より前のベータリソースで、1.5より前のKubernetesリリースでは利用できませんでした。
* すべてのalpha / betaリソースと同じように、apiserverに渡される`--runtime-config`オプションによってStatefulSetを無効にすることができます。
* 特定のPodのストレージは、要求された`storage class`に基づく[PersistentVolume Provisioner](https://github.com/kubernetes/examples/blob/master/staging/persistent-volume-provisioning/README.md)によってプロビジョニングされるか、管理者によって事前にプロビジョニングされる必要があります。
* StatefulSetを削除したりスケールしたりしても、StatefulSetに関連付けられたボリュームは削除されません。これは、データの安全性を確保するために行われます。これは、関連するすべてのStatefulSetリソースの自動パージよりも一般的に重要です。
* 現在、StatefulSetsは、[Headless Service](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services)が、PodsのネットワークIDを担当する必要があります。あなたはこのサービスを作成する責任があります。

## Components
以下の例は、StatefulSetのコンポーネントを示しています。

* nginxという名前のHeadless Serviceは、ネットワークドメインを制御するために使用されます。
* webという名前のStatefulSetには、nginxコンテナの3つのレプリカが一意のPodで起動されることを示すSpecがあります。
* volumeClaimTemplatesは、[PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) ProvisionerによってプロビジョニングされたPersistentVolumesを使用して安定したストレージを提供します。

---

```yaml

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 # デフォルトは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
```

## Pod Selector
StatefulSetの`.spec.selector`フィールドを`.spec.template.metadata.labels`のラベルと一致するように設定する必要があります。Kubernetes 1.8より前のバージョンでは、`.spec.selector`フィールドが省略されたときにデフォルト設定されていました。1.8以降のバージョンでは、一致するPod Selectorの指定に失敗すると、StatefulSetの作成時に検証エラーが発生します。

## Pod Identity
StatefulSet Podsには、序数、安定したネットワークID、安定したストレージで構成されたユニークなIDがあります。アイデンティティは、どのノードに（再）スケジュールされているかにかかわらず、Podに固執します。

### Ordinal Index
N個のレプリカを持つStatefulSetの場合、StatefulSet内の各Podには0以上N-1までの整数序数が割り当てられます。

### Stable Network ID
StatefulSetの各Podは、StatefulSetの名前とPodの序数からホスト名を派生します。構築されたホスト名のパターンは`$（ステートフルセット名） - $（序数）`です。上記の例では、web-0、web-1、web-2という3つのポッドが作成されます。 StatefulSetは、[Headless Service](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services)を使用して、そのPodsのドメインを制御できます。このサービスによって管理されるドメインは、`$（サービス名）.$（名前空間）.svc.cluster.local`という形式をとります。ここで、 "cluster.local"はクラスタドメインです。各ポッドが作成されると、`$（podname）.$（統治的な(govering)サービスドメイン）`という形式で、対応するDNSサブドメインが取得されます。統治的(governing)なサービスはStatefulSetの`serviceName`フィールドで定義されます。

Cluster Domain、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}|

クラスタドメインは、[特に設定](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#how-it-works)されていない限り、`cluster.local`に設定されます。

### Stable Storage
Kubernetesは、各VolumeClaimTemplateに対して1つの[PersistentVolume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)を作成します。上記のnginxの例では、各Podは`my-storage-classのStorageClass`とプロビジョニングされたストレージの1Gibを持つ単一のPersistentVolumeを受け取ります。StorageClassが指定されていない場合、デフォルトのStorageClassが使用されます。Podがノードに(再)スケジュールされると、その`volumeMounts`はPersistentVolumeClaimsに関連付けられたPersistentVolumesをマウントします。PodsのPersistentVolumeClaimに関連付けられたPersistentVolumeは、PodsまたはStatefulSetが削除されても削除されません。これは手動で行う必要があります。

### Pod Name Label
StatefulSetコントローラがPodを作成すると、Podの名前に設定されたラベル`statefulset.kubernetes.io/pod-name`が追加されます。このラベルを使用すると、StatefulSet内の特定のPodにサービスを添付できます。

## Deployment and Scaling Guarantees

* N個のレプリカを持つStatefulSetの場合、Podがデプロイされるとき、それらは{0..N-1}の順番で順番に作成されます。
* Podsが削除されると、それらは{N-1..0}から逆の順序で終了します。
* スケーリング操作がPodに適用される前に、すべての先行操作が実行中であり、準備完了(Running and Ready)でなければなりません。
* Podが終了する前に、すべての後継者を完全にシャットダウンする必要があります。

---
StatefulSetは、`pod.Spec.TerminationGracePeriodSeconds`を0に指定するべきではありません。このプラクティスは安全ではなく、強くお勧めします。詳しい説明は、[StatefulSet Podを強制的に削除する](https://kubernetes.io/docs/tasks/run-application/force-delete-stateful-set-pod/)を参照してください。

上記のnginxの例を作成すると、3つのPodがweb-0、web-1、web-2の順番で配備されます。 web-0が実行され準備が整う前にweb-1は配備されず、web-1が実行され準備が整うまでweb-2は配備されません。web-0が失敗すると、web-1が実行中で準備完了ですが、web-2が起動する前にweb-0が正常に再起動され、実行中および準備完了になるまでWeb-2は起動しません。

`replicas=1`になるようにStatefulSetにパッチを当てることで、デプロイされたサンプルをスケーリングすると、web-2が最初に終了します。web-1は、web-2が完全に停止して削除されるまで終了しません。web-2が終了して完全にシャットダウンされた後、web-1の終了前にweb-0が失敗した場合、web-0が実行中でありReadyになるまでweb-1は終了しません。

### Pod Management Policies
Kubernetes 1.7以降では、StatefulSetを使用すると、`.spec.podManagementPolicy`フィールドを使用して一意性とID保証を保持したまま、順序保証を緩和することができます。

#### OrderedReady Pod Management
`OrderedReady`ポッドの管理は、StatefulSetのデフォルトです。これは、[上記](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#deployment-and-scaling-guarantees)の動作を実装します。

#### Parallel Pod Management
`並列(Parallel)`ポッド管理は、すべてのポッドを並行して起動または終了し、別のPodを起動または終了する前に、Podsが実行中であり準備完了または完全に終了するのを待機しないようにStatefulSetコントローラに指示します。

## Update Strategies
Kubernetes 1.7以降では、StatefulSetの`.spec.updateStrategy`フィールドで、コンテナ、ラベル、リソース要求/制限、StatefulSet内のPodの注釈(annotation)の自動ローリングアップデートを設定および無効にすることができます。

### On Delete
`OnDelete`更新戦略は、従来の（1.6以前の）動作を実装します。StatefulSetの`.spec.updateStrategy.type`が`OnDelete`に設定されている場合、StatefulSetコントローラはStatefulSet内のPodを自動的に更新しません。ユーザーは手動でポッドを削除して、コントローラにステートフルセットの`.spec.template`に加えられた変更を反映する新しいポッドを作成させる必要があります。

### Rolling Updates
`RollingUpdate`更新戦略は、StatefulSet内のPodの自動更新を実装します。`.spec.updateStrategy`が指定されていない場合のデフォルト戦略です。StatefulSetの`.spec.updateStrategy.type`がRollingUpdateに設定されている場合、StatefulSetコントローラはStatefulSet内の各Podを削除して再作成します。これは、一度に1つずつ各ポッドを更新して、ポッド終了と同じ順序で（最大の序数から最小の序数に）進められます。

#### Partitions
`RollingUpdate`更新戦略は、`.spec.updateStrategy.rollingUpdate.partition`を指定してパーティション分割できます。パーティションが指定されている場合は、StatefulSetの`.spec.template`が更新されると、そのパーティション以上の序数を持つすべてのポッドが更新されます。パーティションより小さい序数を持つすべてのポッドは更新されず、削除されても以前のバージョンで再作成されます。StatefulSetの`.spec.updateStrategy.rollingUpdate.partition`が`.spec.replicas`より大きい場合、`.spec.template`への更新はそのポッドに伝播されません。ほとんどの場合、パーティションを使用する必要はありませんが、更新をステージングしたり、カナリーをロールアウトしたり、段階的にロールアウトしたりする場合に便利です。