ステートフルセット
ステートフルセット コントローラー: 概念と原則の解釈
StatefulSet は、ステートフル サービスの問題を管理するように設計されています。
StatefulSet 内の Pod の場合、各 Pod は独自の独立したストレージをマウントします. Pod が失敗した場合、同じ名前の Pod が別のノードから開始され、元の Pod がマウントされているストレージは、その状態でサービスを提供し続けます.
ステートフル サービス?
StatefulSet は、ステートフル サービスを管理するステートフル コレクションであり、それが管理する Pod の名前は自由に変更できません。データ永続化ディレクトリも異なり、各 Pod には独自のデータ永続化ストレージ ディレクトリがあります。MySQL マスタースレーブ、redis クラスターなど。
- 各 Pod を独立させる
- 各 Pod を独立させ、Pod の起動順序と一意性を維持する
- 一意のネットワーク識別子、永続ストレージ
- mysql の master-slave などの整然とした
StatefulSet に適したビジネスには、データベース サービスの MySQL と PostgreSQL、クラスター化された管理サービス Zookeeper、etcd およびその他のステートフル サービスが含まれます。
StatefulSet のもう 1 つの典型的なアプリケーション シナリオは、通常のコンテナーよりも仮想マシンをシミュレートするためのより安定した信頼性の高いメカニズムです。従来の仮想マシンはステートフルなペットであり、オペレーターは常にそれを維持する必要があります. コンテナーが普及した当初、仮想マシンの使用をシミュレートするためにコンテナーを使用しました. すべての状態はコンテナーに格納されていました.信頼できない。
StatefulSet を使用すると、Pod は異なるノードにドリフトすることで高可用性を維持でき、ストレージは外部ストレージを介して高い信頼性を提供することもできます.StatefulSet が行うことは、特定の Pod を特定のストレージに関連付けて、状態の継続性を確保することです.
ステートレス サービス?
RC、Deployment、および DaemonSet はすべてステートレス サービスであり、それらが管理する Pod の IP、名前、開始および停止順序はランダムです。個々は全体に影響を与えません. すべてのポッドはデータ ボリュームを共有します. デプロイされた tomcat はステートレス サービスです. tomcat が削除された場合, tomcat の名前に関係なく、新しい tomcat を起動してクラスターに参加します.
- ポッドはすべて同じだと思います
- 注文不要
- アプリケーションが実行されているノードに関係なく
- 自由にスケーリングおよび拡張する機能
StatefulSet は次の部分で構成されます。
1. ヘッドレス サービス: ポッド ネットワーク識別子を定義し、解決可能な DNS レコードを生成するために使用されます。
2. volumeClaimTemplates: ストレージ ボリューム アプリケーション テンプレート、PVC の作成、PVC の名前とサイズの指定、PVC の自動作成、PVC はストレージ クラスによって提供されます。
3.StatefulSet: ポッドを管理します
ヘッドレスサービスとは
ヘッドレス サービスは clusterIP を割り当てません。ヘッドレス サービスは、サービスの DNS を解析することによって、すべてのポッドの dns と IP アドレスを返すことができます (statefulSet によってデプロイされたポッドには DNS があります)。通常のサービスの場合、サービスの ClusterIP は解析によってのみ返すことができます。サービスの DNS。
ヘッドレス サービス (サービス IP のないサービス) を使用する理由
Deployment を使用する場合、作成された Pod 名は順序付けされませんが、ランダムな文字列です. Statefulset を使用して Pod を管理する場合、Pod 名は順序付けする必要があり、各 Pod を自由に置き換えることはできません. Pod が再構築された後、Pod 名はそのままです.同じです。ポッドの IP は変更されるため、ポッド名を使用してそれらを識別します。ポッド名はポッドの一意の識別子であり、永続的で有効である必要があります。これは、各ポッドに一意の名前を付けることができるヘッドレス サービスが使用される場所です。
1.headless service 会为 service 分配一个域名
<service name>.$<namespace name>.svc.cluster.local
K8s 中资源的全局 FQDN 格式:
Service_NAME.NameSpace_NAME.Domain.LTD.
Domain.LTD.=svc.cluster.local. #这是默认 k8s 集群的域名。
FQDN 全称 Fully Qualified Domain Name 即全限定域名:同时带有主机名和域名的名称
FQDN = Hostname + DomainName
如 主机名是 paopao 域名是 csdn.com
FQDN= paopao.csdn.com
2.StatefulSet 会为关联的 Pod 保持一个不变的 Pod Name
statefulset 中 Pod 的名字格式为$(StatefulSet name)-$(pod 序号)
3.StatefulSet 会为关联的 Pod 分配一个 dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local
volumeClaimTemplate を使用する理由
永続ストレージは、mysql マスター/スレーブなどのステートフル アプリケーションに使用されます. マスター/スレーブ データベースのデータはディレクトリに保存できないため、各 mysql ノードには独自の独立したストレージ スペースが必要です. デプロイで作成されたストレージ ボリュームは共有ストレージ ボリュームであり、複数のポッドが同じストレージ ボリュームを使用し、それらのデータが同期されます。statefulset 定義の各ポッドは同じストレージ ボリュームを使用できません。これには、volumeClainTemplate の使用が必要です。 statefulset を使用して Pod を作成すると、volumeClainTemplate は PVC を自動的に生成して PV のバインドを要求します。各 Pod には専用のストレージ ボリュームがあります。Pod、PVC、および PV に対応する関係図は次のとおりです。
Statefulset リソース マニフェスト ファイルの記述スキル
#查看定义 Statefulset 资源需要的字段
[root@k8smaster ~]# kubectl explain statefulset
KIND: StatefulSet
VERSION: apps/v1
DESCRIPTION:
StatefulSet represents a set of pods with consistent identities. Identities
are defined as: - Network: A single stable DNS and hostname. - Storage: As
many VolumeClaims as requested. The StatefulSet guarantees that a given
network identity will always map to the same storage identity.
FIELDS:
apiVersion <string> #定义 statefulset 资源需要使用的 api 版本
kind <string> #定义的资源类型
metadata<Object> #元数据
spec <Object> #定义容器相关的信息
#查看 statefulset.spec 字段如何定义?
[root@k8smaster ~]# kubectl explain statefulset.spec
KIND: StatefulSet
VERSION: apps/v1
RESOURCE: spec <Object>
DESCRIPTION:
Spec defines the desired identities of pods in this set.
A StatefulSetSpec is the specification of a StatefulSet.
FIELDS:
podManagementPolicy <string> #pod 管理策略
replicas <integer> #副本数
revisionHistoryLimit <integer> #保留的历史版本
selector <Object> -required- #标签选择器,选择它所关联的 pod
serviceName <string> -required- #headless service 的名字
template <Object> -required- #生成 pod 的模板
updateStrategy <Object> #更新策略
volumeClaimTemplates<[]Object> #存储卷申请模板
#查看 statefulset 的 spec.template 字段如何定义?
#对于 template 而言,其内部定义的就是 pod,pod 模板是一个独立的对象
[root@k8smaster ~]# kubectl explain statefulset.spec.template
KIND: StatefulSet
VERSION: apps/v1
RESOURCE: template <Object>
DESCRIPTION:
template is the object that describes the pod that will be created if
insufficient replicas are detected. Each pod stamped out by the StatefulSet
will fulfill this Template, but have a unique identity from the rest of the
StatefulSet.
PodTemplateSpec describes the data a pod should have when created from a
template
FIELDS:
metadata <Object>
spec <Object> #定义容器属性的
上記のように、statefulset リソースには 2 つの仕様フィールドがあります。
最初の仕様は、ステートフル セットが定義する Pod レプリカの数 (デフォルトでは 1 つの Pod のみがデプロイされます)、Pod ラベルに一致するセレクター、Pod を作成するためのテンプレート、およびストレージ ボリューム リクエスト テンプレートを宣言します。
2 つ目の仕様は spec.template.spec です。主に Pod のコンテナ プロパティなどの設定に使用されます。.spec.template の内容は、Pod オブジェクトを宣言する際に定義する各種プロパティであるため、この部分も PodTemplate (Pod Template) と呼ばれます。
注目に値するもう 1 つの点: .spec.selector で定義されたラベル セレクターは、spec.template.metadata.labels で定義された Pod ラベルと一致できる必要があります。一致しない場合、Kubernetes はステートフル セットの作成を許可しません。
ステートフル セットのユース ケース: Web サイトのデプロイ
#创建存储类
[root@k8smaster ~]# mkdir state
[root@k8smaster ~]# cd state/
[root@k8smaster state]# vim class-web.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-web
provisioner: example.com/nfs
#更新资源清单文件
[root@xianchaomaster1 ~]# kubectl apply -f class-web.yaml
[root@k8smaster state]# kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-web example.com/nfs Delete Immediate false 6m16s
#编写一个 Statefulset 资源清单文件
[root@k8smaster state]# vim statefulset.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
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-web"
resources:
requests:
storage: 1Gi
#更新资源清单文件
[root@k8smaster state]# kubectl apply -f statefulset.yaml
service/nginx created
statefulset.apps/web created
#查看 statefulset 是否创建成功
[root@k8smaster state]# kubectl get sts -o wide
NAME READY AGE CONTAINERS IMAGES
web 2/2 59s nginx nginx
#查看 pod
[root@k8smaster state]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 76s
web-1 1/1 Pending 0 76s
#通过上面可以看到创建的 pod 是有序的
#查看 headless service
[root@k8smaster state]# kubectl get svc -l app=nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 3m
#查看 pvc
[root@k8smaster state]# kubectl get pvc
www-web-0 Bound pvc-13a0482f-4927-63ff-9f2e-1b926b299c6f 1Gi RWO,RWX nfs-web 4m45s
www-web-1 Bound pvc-bc23p2a9-5bjd-00df-829f-ccb4d24g01h1 1Gi RWO,RWX nfs-web 4m41s
#查看 pv
[root@k8smaster state]# kubectl get pv
pvc-13a0482f-4927-63ff-9f2e-1b926b299c6f 1Gi RWO,RWX Delete Bound default/www-web-0 nfs-web 5m3s
pvc-bc23p2a9-5bjd-00df-829f-ccb4d24g01h1 1Gi RWO,RWX Delete Bound default/www-web-1 nfs-web 5m59s
#在data nfs_pro目录下划分的pv
#查看 pod 主机名
[root@k8smaster ~]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname';done
web-0
web-1
#使用 kubectl run 运行一个提供 nslookup 命令的容器的,这个命令来自于 dnsutils 包,通过对 pod 主机名执行 nslookup,可以检查它们在集群内部的 DNS 地址:
[root@k8smaster ~]# kubectl exec -it web-1 -- /bin/bash
root@web-1:/# apt-get update
root@web-1:/# apt-get install dnsutils -y
root@web-1:/# nslookup web-0.nginx.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: web-0.nginx.default.svc.cluster.local
#statefulset 创建的 pod 也是有 dns 记录的
Address: 10.244.103.139 #解析到的是 pod 的 ip 地址
root@web-1:/# nslookup nginx.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: nginx.default.svc.cluster.local #查询 service dns,会把对应的 pod ip 解析出来
Address: 10.244.103.139
Name: nginx.default.svc.cluster.local
Address: 10.244.121.93
[root@k8smaster state]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Type: ClusterIP
IP: none
Port: web 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.103.139:80,10.244.121.93:80 #这两个pod都有app=ngin的标签,service把这两个都写入endpoints列表了
Session Affinity: None
Events: <none>
root@web-1:/# dig -t A nginx.default.svc.cluster.local @10.96.0.10
; <<>> DiG 9.11.5-P4-5.1+deb10u3-Debian <<>> -t A nginx.default.svc.cluster.local @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16869
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 1cf973a5daa99ac7 (echoed)
;; QUESTION SECTION:
;nginx.default.svc.cluster.local. IN A
;; ANSWER SECTION:
nginx.default.svc.cluster.local. 30 IN A 10.244.103.139
nginx.default.svc.cluster.local. 30 IN A 10.244.121.93
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Jul 14 06:49:51 UTC 2022
;; MSG SIZE rcvd: 166
root@web-1:/# nslookup kubernetes.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
#解析kubernertes,有ip会把ip解析出来,没有会解析后端pod
dig 的使用
dig -t A nginx.default.svc.cluster.local @10.96.0.10
格式如下:
@来指定域名服务器
A 为解析类型 ,A 记录
-t 指定要解析的类型
A 记录:
A 记录是解析域名到 IP
资源清单详细解读:
apiVersion: v1 #定义 api 版本
kind: Service #定义要创建的资源:service
metadata:
name: nginx #定义 service 的名字
labels:
app: nginx #service 的标签
spec:
ports:
- port: 80
name: web
clusterIP: None #创建一个没有 ip 的 service
selector:
app: nginx #选择拥有 app=nginx 标签的 pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx" #headless service 的名字
replicas: 2 #副本数
template: #定义 pod 的模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: #存储卷申请模板
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-web" #指定从哪个存储类申请 pv
resources:
requests:
storage: 1Gi #需要 1G 的 pvc,会自动跟符合条件的 pv 绑定
扩展:
service 和 headless service 区别:
#deployment 创建的 pod 是随机生成的 解析的是 service 的 ip 地址
Statefulset は Pod を管理します: スケーリング、スケーリング、更新
#Statefulset 实现 pod 的动态扩容
如果我们觉得两个副本太少了,想要增加,只需要修改配置文件 statefulset.yaml 里的 replicas的值即可,原来 replicas: 2,现在变成 replicaset: 3,修改之后,执行如下命令更新:
[root@k8smaster state]# kubectl apply -f statefulset.yaml
service/nginx unchanged
statefulset.apps/web configured
[root@k8smaster state]# kubectl get sts
web 3/3 30m
[root@k8smaster state]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 61m
web-1 1/1 Running 0 60m
web-2 1/1 Running 0 79s
#也可以直接编辑控制器实现扩容
[root@xianchaomaster1 ~]# kubectl edit sts web
#这个是我们把请求提交给了 apiserver,实时修改,把 spec 下的 replicas 后面的值改成 4,保存退出
[root@xianchaomaster1 ~]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 62m
web-1 1/1 Running 0 62m
web-2 1/1 Running 0 3m13s
web-3 1/1 Running 0 26s
#Statefulset 实现 pod 的动态缩容
如果我们觉得 4 个 Pod 副本太多了,想要减少,只需要修改配置文件 statefulset.yaml 里的
replicas 的值即可,把 replicaset:4 变成 replicas: 2,修改之后,执行如下命令更新:
[root@k8smaster state]# kubectl apply -f statefulset.yaml
service/nginx unchanged
statefulset.apps/web configured
[root@k8smaster state]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 64m
web-1 1/1 Running 0 63m
#Statefulset 实现 pod 的更新
[root@k8smaster state]# kubectl edit sts web
#修改镜像 nginx 变成 image: tomcat,修改之后保存退出
[root@k8smaster state]# kubectl get pods -o wide -l app=nginx
NAME READY STATUS RESTARTS AGE IP NODE
web-0 1/1 Running 0 18s 10.244.201.106 k8snode
web-1 1/1 Running 0 36s 10.244.133.176 k8snode2
#查看 pod 详细信息
[root@k8smaster state]# kubectl describe pods web-0
通过上面可以看到 pod 已经使用刚才更新的镜像 tomcat 了
最後に書く
作成するのは簡単ではありません。コンテンツが役立つと思われる場合は、3 つのリンクをフォローしてサポートしてください。間違いがあればコメントで指摘していただければ修正します!
現在更新中のシリーズ:ゼロからk8sを学ぶ ご覧
いただきありがとうございます 記事には個人的な理解が混在しています 誤りがある場合は、私に連絡して指摘してください〜