StatefulSetが必要な理由
Deploymentでは、Deploymentについて説明しました。Deploymentコントローラーの下のポッドには共通の機能があります。つまり、各ポッドは名前とIPアドレスを除いて同一です。必要に応じて、Deploymentはポッドテンプレートを介して新しいポッドを作成できます。不要な場合、Deploymentは任意のポッドを削除できます。
ただし、一部のシナリオでは、これは需要を満たしません。たとえば、一部の分散シナリオでは、分散データベースなど、各ポッドに独自の個別の状態が必要な場合、各ポッドには個別のストレージが必要です。需要を満たすことができません。
ステートフルアプリケーションの要件の詳細な分析では、分散ステートフルネスの特徴は、主にアプリケーションの各部分の役割(つまり、分業)が異なることです。たとえば、データベースにはアクティブとスタンバイがあり、ポッド間に依存関係があります。Kubernetesに対応するのはポッドです。要件は次のとおりです。
- ポッドは他のポッドで見つけることができます。ポッドには固定のロゴが必要です。
- 各ポッドには個別のストレージがあります。ポッドを削除して復元した後、読み取られるデータは以前と同じである必要があります。そうでない場合、ステータスに一貫性がなくなります。
Kubernetesは、この問題を解決するためのStatefulSetを提供しています。これは次のとおりです。
- StatefulSetは、各ポッドに固定名を提供します。ポッド名は、0からNまでの固定サフィックスを追加します。ポッドが再スケジュールされた後、ポッド名とHostNameは変更されません。
- StatefulSetは、ヘッドレスサービスを介して各ポッドに固定アクセスドメイン名を提供します。サービスの概念については、サービスで詳しく説明します。
- StatefulSetは、固定識別子を持つPVCを作成することにより、ポッドが再スケジュールされた後でも同じ永続データにアクセスできるようにします。
以下では、StatefulSetを作成することにより、StatefulSetのこれらの特性を体験します。
ヘッドレスサービスを作成する
前述のように、ステートフルセットを作成するには、ポッドアクセス用のヘッドレスサービスが必要です。サービスの概念については、サービスで詳しく説明します。ここでは、最初にヘッドレスサービスを作成する方法を紹介します。
次のファイルを使用して、ヘッドレスサービスについて説明します。
- spec.clusterIP:Noneに設定する必要があります。これは、ヘッドレスサービスを意味します。
- spec.ports.port:ポッド間の通信ポート番号。
- spec.ports.name:ポッド間の通信ポートの名前。
apiVersion: v1 kind: Service # 对象类型为Service metadata: name: nginx labels: app: nginx spec: ports: - name: nginx # Pod间通信的端口名称 port: 80 # Pod间通信的端口号 selector: app: nginx # 选择标签为app:nginx的Pod clusterIP: None # 必须设置为None,表示Headless Service
次のコマンドを実行して、ヘッドレスサービスを作成します。
# kubectl create -f headless.yaml
service/nginx created
作成後にサービスを照会できます。
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 5s
Statefulsetを作成する
StatefulsetのYAML定義は基本的に他のオブジェクトと同じですが、2つの主な違いがあります。
- serviceNameは、Statefulsetが使用するヘッドレスサービスを指定し、ヘッドレスサービスの名前を入力する必要があります。
- volumeClaimTemplatesは、永続宣言PVCを適用するために使用されます。dataという名前のテンプレートがここで定義されます。ポッドごとにPVCが作成されます。storageClassNameは、永続ストレージのタイプを指定します。これについては、PV、PVC、およびStorageClassで詳しく説明します。volumeMountsポッド用のストレージをマウントすることです。もちろん、volumeClaimTemplatesフィールドとvolumeMountsフィールドを保存する必要がない場合は、それらを削除できます。
apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx spec: serviceName: nginx # headless service的名称 replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: container-0 image: nginx:alpine resources: limits: cpu: 100m memory: 200Mi requests: cpu: 100m memory: 200Mi volumeMounts: # Pod挂载的存储 - name: data mountPath: /usr/share/nginx/html # 存储挂载到/usr/share/nginx/html imagePullSecrets: - name: default-secret volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi storageClassName: csi-nas # 持久化存储的类型
次のコマンドを実行して作成します。
# kubectl create -f statefulset.yaml
statefulset.apps/nginx created
コマンドが実行された後、StatefulSetとPodを照会すると、ポッドの名前の接尾辞が0から2で始まり、1つずつ増加していることがわかります。
# kubectl get statefulset
NAME READY AGE
nginx 3/3 107s
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-0 1/1 Running 0 112s
nginx-1 1/1 Running 0 69s
nginx-2 1/1 Running 0 39s
この時点で、nginx-1ポッドを手動で削除してから、ポッドを再度クエリすると、StatefulSetが同じ名前のポッドを再作成したことがわかります。nginx-1は作成時間5秒までに作成されたばかりであることがわかります。
# kubectl delete pod nginx-1
pod "nginx-1" deleted
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-0 1/1 Running 0 3m4s
nginx-1 1/1 Running 0 5s
nginx-2 1/1 Running 0 1m10s
コンテナを入力してコンテナのホスト名を表示します。これもnginx-0、nginx-1、およびnginx-2であることがわかります。
# kubectl exec nginx-0 -- sh -c 'hostname'
nginx-0
# kubectl exec nginx-1 -- sh -c 'hostname'
nginx-1
# kubectl exec nginx-2 -- sh -c 'hostname'
nginx-2
同時に、StatefulSetによって作成されたPVCを確認できます。これらのPVCには、「PVC name-StatefulSet name-number」という名前が付けられ、バインドされた状態になっていることがわかります。
# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-nginx-0 Bound pvc-f58bc1a9-6a52-4664-a587-a9a1c904ba29 1Gi RWX csi-nas 2m24s
data-nginx-1 Bound pvc-066e3a3a-fd65-4e65-87cd-6c3fd0ae6485 1Gi RWX csi-nas 101s
data-nginx-2 Bound pvc-a18cf1ce-708b-4e94-af83-766007250b0c 1Gi RWX csi-nas 71s
StatefulSetのネットワークID
StatefulSetが作成されると、ポッドの名前が固定されていることがわかります。ヘッドレスサービスはどのように機能しますか?DNSを使用してポッドの固定ドメイン名を提供し、ポッドが再作成された場合でもドメイン名を使用してポッドにアクセスできるようにします。その結果、ポッドのIPアドレスが変更され、ドメイン名は変更されません。
ヘッドレスサービスが作成されると、各ポッドのIPには次の形式のドメイン名が付けられます。
<pod-name>。<svc-name>。<namespace> .svc.cluster.local
たとえば、上記の3つのポッドのドメイン名は次のとおりです。
- nginx-0.nginx.default.svc.cluster.local
- nginx-1.nginx.default.svc.cluster.local
- nginx-1.nginx.default.svc.cluster.local
は、実際のアクセス時には省略できます。<namespace> .svc.cluster.local。
次のコマンドは、tutum / dnsutilsイメージを使用してポッドを作成し、ポッドコンテナーに入り、nslookupコマンドを使用してポッドに対応するドメイン名を表示します。ポッドのIPアドレスを解決できることがわかります。ここで、DNSサーバーのアドレスが10.247.3.10であることがわかります。これは、DNSサービスを提供するCCEクラスターを作成するときのCoreDNSプラグインのデフォルトのインストールです。CoreDNSの役割については、後でKubernetesネットワークで詳しく説明します。
$ kubectl run -i --tty --image tutum/dnsutils dnsutils --restart=Never --rm /bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx-0.nginx
Server: 10.247.3.10
Address: 10.247.3.10#53
Name: nginx-0.nginx.default.svc.cluster.local
Address: 172.16.0.31
/ # nslookup nginx-1.nginx
Server: 10.247.3.10
Address: 10.247.3.10#53
Name: nginx-1.nginx.default.svc.cluster.local
Address: 172.16.0.18
/ # nslookup nginx-2.nginx
Server: 10.247.3.10
Address: 10.247.3.10#53
Name: nginx-2.nginx.default.svc.cluster.local
Address: 172.16.0.19
この時点で、これら2つのポッドを手動で削除し、StatefulSetによって再作成されたポッドのIPを照会してから、nslookupコマンドを使用してポッドのドメイン名を解決すると、nginx-0.nginxおよびnginx-1.nginxが対応するポッドを解決できることがわかります。これにより、StatefulSetネットワークIDが変更されないことが保証されます。
StatefulSetは状態を保存します
前述のように、StatefulSetをPVCを介した永続ストレージに使用して、ポッドの再スケジュール後に同じ永続データにアクセスできるようにすることができます。ポッドが削除されても、PVCは削除されません。
図1StatefulSetのポッド再構築プロセス
以下は、これが実際の操作でどのように行われるかを確認し、次のコマンドを実行し、nginx-1のディレクトリ/ usr / share / nginx / htmlにコンテンツを書き込みます。たとえば、index.htmlのコンテンツを「hello」に変更します。世界"。
# kubectl exec nginx-1 -- sh -c 'echo hello world > /usr/share/nginx/html/index.html'
変更後、ポッドでアクセスした場合“http://localhost”,那就会返回“hello world”
。
# kubectl exec -it nginx-1 -- curl localhost
hello world
この時点で、nginx-1ポッドを手動で削除してから、ポッドを再度クエリすると、StatefulSetが同じ名前のポッドを再作成したことがわかり、nginx-1が作成時間4秒までに作成されたことがわかります。
# kubectl delete pod nginx-1
pod "nginx-1" deleted
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-0 1/1 Running 0 14m
nginx-1 1/1 Running 0 4s
nginx-2 1/1 Running 0 13m
ポッドのindex.htmlページに再度アクセスすると、「hello world」がまだ返されていることがわかります。これは、ポッドが引き続き同じストレージにアクセスしていることを意味します。
# kubectl exec -it nginx-1 -- curl localhost
hello world