1.はじめに
インスタンスと、インスタンスが外部データに依存しているアプリケーションとの間の不平等な関係は、「ステートフルアプリケーション」と呼ばれます。
インスタンス間のいわゆる不均等な関係は、分散アプリケーションの場合、各インスタンスと各アプリケーションの間に比較的大きな依存関係があることが多いことを意味します。たとえば、アプリケーションは他のアプリケーションの前に起動する必要があります。そうしないと、他のアプリケーションは起動されません。
外部データに依存する最も重要なアプリケーションはデータベースアプリケーションです。データベースアプリケーションの場合、データを永続的に保存する必要があります。ステートレスアプリケーションの場合、データベース内のデータを再起動すると、アプリケーションは接続を失います。明らかに違反私たちの当初の意図は、それを本番環境に移行することではありませんでした。
したがって、Kubernetesでのステートフルアプリケーションの効果的なサポートを解決するために、KubernetesはStatefulSetを使用してステートフルアプリケーションを調整および管理します。
StatefulSetはReplicaSetに似ていますが、ポッドの起動シーケンスを制御でき、ポッドごとに一意の識別子を設定できる点が異なります。次の機能があります。
-
安定した一意のネットワーク識別子
-
安定した永続的なストレージ
-
整然としたエレガントな展開とスケーリング
- 整然とした自動ローリングアップデート
StatefulSetの設計は理解しやすく、現実世界を次の2つの状況に抽象化します。
(1)トポロジー状態。これは、アプリケーション間に非対称の関係があることを意味します。アプリケーションは特定の順序で起動する必要があります。アプリケーションを再起動しても、指定された順序で再起動する必要があり、ネットワークIDは再起動後の元のネットワークIDと同じである必要があります。元のアクセスが保証されるように、ユーザーは同じ方法で新しいポッドにアクセスできます。
(2)ストレージの状態。つまり、アプリケーションは、いつ、どのような状況であっても、ストレージ内のデータが変更されない限り、読み取られるデータは同じである必要があり、保存されたデータにバインドされます。
したがって、StatefulSetのコア機能は、ポッドの状態を特定の方法で記録し、ポッドが再作成されたときに何らかの方法でその状態を復元することです。
二、ヘッドレスサービス
StatefulSetを紹介する前に、まずヘッドレスサービスとは何かを理解しましょう。
Kubernetesでは、サービスはポッドのグループへの外部アクセスを提供する方法であることを私たちは知っています。通常、サービスを使用してポッドにアクセスするには、次の2つの方法があります。
(1)クラスターIPを介して、このクラスターIPはVIPと同等です。このIPにアクセスすると、リクエストはバックエンドポッドに転送されます。
(2)DNSを介してこの方法では、最初にKubernetesクラスターにDNSサービスがあることを確認する必要があります。このとき、「my-service.my-namespace.svc、cluster.local」にアクセスする限り、my-serviceという名前のサービスによってプロキシされるバックエンドポッドにアクセスできます。
2番目の方法には、次の2つの処理方法があります。
(1)通常のサービス、つまりドメイン名を解決し、クラスターIPを取得してから、方法1に従ってアクセスします。
(2)ヘッドレスサービス、つまり、ドメイン名を解決して取得します。バックエンドのポッドのIPアドレスであるため、直接アクセスできます。
2番目の処理方法では、クラスターIPは必要ないことがわかりますが、バックエンドポッドのIPアドレスは、アクセス用のドメイン名を介して直接解決されます。
以下は、ヘッドレスサービスの簡単なYAMLファイル定義です。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
上記のYAMLファイルから、通常のサービス定義とあまり違いがないことがわかります。唯一の違いは、clusterIPがNoneに設定されている、つまりクラスターが不要であるということです。このサービスはkubectl apply-fを使用して作成します。 、次にサービスのクラスターIPがNoneであることを確認します。
この方法で作成されたサービスはヘッドレスサービスであり、VIPがないため、プロキシされたポッドがDNSレコードの形式で公開されます。
3、StatefulSetを使用します
次のように、StatefulSetを作成する前にPVを作成します。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01
labels:
release: stable
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: /tmp/data
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv02
labels:
release: stable
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: /tmp/data
次に、次のようにkubectl apply-fを実行してPVを開始します。
[root@master statefulset]# kubectl apply -f pv.yaml
persistentvolume/pv01 created
persistentvolume/pv02 created
[root@master statefulset]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01 1Gi RWO Recycle Available 10s
pv02 1Gi RWO Recycle Available 9s
2つのPVの状態が両方とも利用可能であることがわかり、StatefulSetのYAMLファイルを書き込みます。
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
role: stateful
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
role: stateful
spec:
containers:
- name: nginx
image: cnych/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
volumeMountsに関連付けられた上記のYAMLファイルは新しい属性であることに注意してください:volumeClaimTemplates、この属性は管理用のpvcオブジェクトとpvを自動的に宣言します。serviceName: "nginx"は、制御ループの実行時にnginxのヘッドレスが使用されることを意味します。ポッドの解決可能なIDを保存するサービス。
次に、ここで2つのターミナルウィンドウを開きます。最初のターミナルで、kubectl getを使用して、StatefulSetのポッドの作成を表示します。
$ kubectl get pods -w -l role=stateful
別のターミナルで、kubectl createを使用して、statefulset-demo.yamlで定義されたヘッドレスサービスとStatefulSetを作成します。
$ kubectl create -f statefulset-demo.yaml
service "nginx" created
statefulset.apps "web" created
次に、ポッドの起動シーケンスを観察します。
[root@master ~]# kubectl get pods -w -l role=stateful
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 3m12s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 1s
web-1 0/1 ContainerCreating 0 1s
web-1 1/1 Running 0 5s
上記の作成プロセスを通じて、StatefulSetが管理するポッドに番号を付けることがわかります。その命名規則は[statefulset-name]-[index]であり、インデックスは0から始まります。これはStatefulSetの各ポッドインスタンスと同じです。対応、繰り返さないでください。さらに重要なことに、ポッドの作成プロセスはシーケンシャルです。上記のように、web-1は、web-0が実行状態に入った後、保留状態になります。
このコマンドを使用して、作成結果を表示します。
[root@master statefulset]# kubectl get statefulset web
NAME READY AGE
web 2/2 17m
[root@master statefulset]# kubectl get pods -l role=stateful
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 17m
web-1 1/1 Running 0 14m
[root@master statefulset]# kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 17m
両方のポッドが実行状態に入ると、それぞれのネットワークIDを表示できます。次のようにkubectlexecを介して表示できます。
[root@master statefulset]# kubectl exec web-0 -- sh -c 'hostname'
web-0
[root@master statefulset]# kubectl exec web-1 -- sh -c 'hostname'
web-1
2つのポッドのホスト名とポッド名が同じであり、すべて対応する番号が割り当てられていることがわかります。次に、DNSを使用してヘッドレスサービスにアクセスします。
まず、次のコマンドでポッドを起動します。
kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
次に、nslookupを使用して、このポッド内のポッドに対応するヘッドレスサービスを解析します。
kubectl run -i --tty --image centos dns-test --restart=Never --rm /bin/sh
sh-4.2# yum install bind-utils -y
sh-4.2# nslookup web-0.nginx
Server: 10.68.0.2
Address: 10.68.0.2#53
Name: web-0.nginx.default.svc.cluster.local
Address: 172.20.2.63
sh-4.2# nslookup web-1.nginx
Server: 10.68.0.2
Address: 10.68.0.2#53
Name: web-1.nginx.default.svc.cluster.local
Address: 172.20.2.64
nslookupの結果の分析から、web-0.nginxにアクセスすると、ポッドweb-0のIPが解析され、もう一方は同じです。
このとき、2つのポッドを削除した場合は、ポッドを再起動するプロセスを確認してください。
[root@master statefulset]# kubectl delete pod -l role=stateful
pod "web-0" deleted
pod "web-1" deleted
次に、次のように再起動シーケンスを確認します。
[root@master ~]# kubectl get pods -w -l role=stateful
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 2s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 2s
ポッドを削除した後も、その再起動シーケンスは元の番号に従って再起動され、ネットワークIDは以前と同じままであることがわかります。
この厳密な対応ルールにより、StatefulSetはポッドのネットワークIDの安定性を保証します。この方法により、ポッドのトポロジ状態をポッドの名前+番号に従って固定できます。さらに、Kubernetesは、ポッドごとに固定された一意のアクセスエントリ、つまりポッドのDNSレコードも提供します。
PVとPVCの結合も確認できます。
[root@master statefulset]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01 1Gi RWO Recycle Bound default/www-web-0 129m
pv02 1Gi RWO Recycle Bound default/www-web-1 129m
[root@master statefulset]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pv01 1Gi RWO 124m
www-web-1 Bound pv02 1Gi RWO 116m
したがって、StatefulSetは次のように分類されます。
(1)、StatefulSetはポッドを直接管理します。これは、StatefulSetのPodインスタンスがReplicaSetのPodインスタンスと完全に同じではないためです。これらはわずかに異なります。たとえば、各Podの名前とホスト名が異なり、StatefulSetがこれらのインスタンスを区別する方法は次のとおりです。ポッド番号を追加するには、
(2)、Kubernetesは、ヘッドレスサービスを介して、この番号の付いたポッドのDNSサーバーに同じ番号のレコードを生成します。StatefulSetがこのポッドの数が変更されないことを保証できる限り、サービスのweb-0.nginx.default.svc.cluster.localに類似したDNSレコードは変更されず、ポッドのIPアドレスはこのレコードによって解決されますポッドの再作成で自動的に更新されます。
(3)StatefulSetは、各ポッドのポッドと同じ番号のPVCを割り当てて作成することもできます。このようにして、Kubernetesは、Persitent Volumeメカニズムを介して対応するPVをこのPVCにバインドし、各ポッドに独立したボリュームがあることを確認できます。この場合、ポッドが削除されても、対応するPVCとPVは保持されるため、ポッドが再作成されると、Kubernetesは同じ番号のPVCを見つけて、PVCに対応するボリュームをマウントします。Get前のボリュームの前のデータ。
4、まとめ
StatefulSetコントローラーの主な機能の1つは、ポッドテンプレートを使用してポッドを作成するときにそれらに番号を付け、番号の順序でタスクを完了することです。StatefulSetの制御ループが、ポッドの実際の状態がと矛盾していることを検出した場合期待される状態で、ポッドも順番に操作します。
もちろん、StatefulSetには他の機能もあります。実際のプロジェクトでは、自分で完全に保持できない限り、StatefulSetを介してステートフルサービスに戻って直接デプロイすることはめったにありません。特定のサービスによっては、より高度なオペレーターを使用する場合があります。 etcd-operator、prometheus-operatorなどとして。ステートフルアプリケーションの場合、最も重要なことはデータリカバリ、フェイルオーバーなどであるため、これらのアプリケーションは、StatefulSetを使用してポッドをデプロイするだけでなく、ステートフルサービスを非常にうまく管理できます。
終了