[클라우드 네이티브 | 처음부터 Kubernetes 배우기] 23. Kubernetes 컨트롤러 Statefulset

이 문서는 "처음부터 k8 배우기" 열에 포함되어 있습니다. 이전 문서
: kubernetes 영구 저장소로 이동 하려면 클릭

여기에 이미지 설명 삽입

Statefulset 컨트롤러: 개념 및 원리 해석

StatefulSet은 상태 저장 서비스의 문제를 관리하도록 설계되었습니다.

StatefulSet에 있는 Pod의 경우 각 Pod는 자체 독립 저장소를 마운트하며, Pod가 실패하면 다른 노드에서 동일한 이름의 Pod가 시작되고 원래 Pod가 마운트된 저장소는 해당 상태에서 서비스를 계속 제공합니다.

상태 저장 서비스?

StatefulSet은 Stateful 서비스를 관리하는 Stateful 컬렉션이며 관리하는 Pod의 이름은 마음대로 변경할 수 없습니다. 데이터 지속성 디렉터리도 다르며, 각 Pod에는 고유한 데이터 지속성 저장소 디렉터리가 있습니다. MySQL 마스터-슬레이브, redis 클러스터 등

  • 각 Pod를 독립적으로 만들기
  • 각 Pod를 독립적으로 만들고 Pod 시작 순서와 고유성을 유지합니다.
  • 고유 네트워크 식별자, 영구 저장소
  • mysql의 마스터-슬레이브와 같은 질서 정연함

StatefulSet에 적합한 비즈니스에는 데이터베이스 서비스 MySQL 및 PostgreSQL, 클러스터형 관리 서비스 Zookeeper 등 및 기타 상태 저장 서비스가 포함됩니다.

StatefulSet의 또 다른 일반적인 애플리케이션 시나리오는 일반 컨테이너보다 가상 머신을 시뮬레이션하기 위한 더 안정적이고 신뢰할 수 있는 메커니즘입니다. 기존의 가상 머신은 상태가 있는 애완 동물이며 운영자는 지속적으로 유지 관리해야 합니다.컨테이너가 처음 대중화되었을 때 컨테이너를 사용하여 가상 머신의 사용을 시뮬레이션하고 모든 상태를 컨테이너에 저장하여 매우 안전하지 않음이 입증되었습니다. 신뢰할 수 없는.

StatefulSet을 사용하면 Pod는 다른 노드로 이동하여 여전히 고가용성을 제공할 수 있으며 저장소는 외부 저장소를 통해 높은 안정성을 제공할 수도 있습니다. StatefulSet이 하는 일은 특정 Pod를 특정 저장소와 연결하여 상태의 연속성을 보장하는 것입니다.

무국적 서비스?

RC, Deployment, DaemonSet은 모두 Stateless 서비스이며 관리하는 Pod의 IP, 이름, 시작 및 중지 순서는 무작위입니다. 개인은 전체에 영향을 미치지 않습니다.모든 포드는 데이터 볼륨을 공유합니다.배포된 tomcat은 stateless 서비스입니다.tomcat이 삭제되면 tomcat의 이름에 관계없이 새 tomcat을 시작하고 클러스터에 가입하십시오.

  • Think Pods는 모두 동일합니다.
  • 주문 요구 사항 없음
  • 애플리케이션이 실행 중인 노드에 관계없이
  • 원하는 대로 확장 및 확장할 수 있는 능력

StatefulSet은 다음 부분으로 구성됩니다.

1. 헤드리스 서비스: 포드 네트워크 식별자를 정의하고 확인 가능한 DNS 레코드를 생성하는 데 사용됩니다.

2. volumeClaimTemplates: 스토리지 볼륨 애플리케이션 템플릿, pvc 생성, pvc 이름 및 크기 지정, pvc 자동 생성, pvc는 스토리지 클래스에서 제공합니다.

3.StatefulSet: 파드 관리

헤드리스 서비스란?

헤드리스 서비스는 클러스터 IP를 할당하지 않습니다. 헤드리스 서비스는 서비스의 DNS를 파싱하여 모든 파드의 dns 및 IP 주소를 반환할 수 있습니다(statefulSet에 의해 배포된 파드에는 DNS가 있음). 일반 서비스의 경우 서비스의 ClusterIP는 파싱을 통해서만 반환될 수 있습니다. 서비스의 DNS.

헤드리스 서비스(서비스 IP가 없는 서비스)를 사용하는 이유는 무엇입니까?

디플로이먼트를 사용할 때 생성된 포드 이름은 순서가 지정되지 않고 임의의 문자열이 생성됩니다. statefulset을 사용하여 포드를 관리할 때 포드 이름을 정렬해야 하며 각 포드를 마음대로 교체할 수 없습니다. 포드를 다시 빌드한 후에도 포드 이름은 여전히 같은.. 팟(Pod) IP가 변경되기 때문에 팟(Pod) 이름을 사용하여 식별하십시오. 포드 이름은 포드의 고유 식별자이며 영구적이고 유효해야 합니다. 여기에서 헤드리스 서비스가 사용되며 각 포드에 고유한 이름을 부여할 수 있습니다.

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 master-slave와 같은 상태 저장 응용 프로그램에 사용되며 master-slave 데이터베이스의 데이터는 디렉터리에 저장할 수 없으므로 각 mysql 노드에는 고유한 독립 저장소 공간이 있어야 합니다. 배포에서 생성된 스토리지 볼륨은 공유 스토리지 볼륨이고 여러 포드가 동일한 스토리지 볼륨을 사용하고 해당 데이터가 동기화되며 statefulset 정의의 각 포드는 동일한 스토리지 볼륨을 사용할 수 없으므로 volumeClainTemplate을 사용해야 합니다. statefulset을 사용하여 포드를 생성하면 volumeClainTemplate은 PV 바인딩을 요청하기 위해 PVC를 자동으로 생성합니다. 각 포드에는 자체 전용 스토리지 볼륨이 있습니다. 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 리소스에는 두 개의 사양 필드가 있습니다.

첫 번째 사양은 statefulset이 정의하는 파드 복제본 수(기본적으로 하나의 파드만 배포됨), 파드 레이블과 일치하는 선택기, 파드 생성을 위한 템플릿, 스토리지 볼륨 요청 템플릿을 선언합니다.

두 번째 사양은 spec.template.spec입니다. 주로 Pod의 컨테이너 속성과 같은 구성에 사용됩니다. .spec.template의 내용은 Pod 객체를 선언할 때 정의해야 하는 다양한 속성이므로 이 부분을 PodTemplate(Pod Template)이라고도 합니다.

한 가지 더 주목할 가치가 있습니다. .spec.selector에 정의된 레이블 선택자는 spec.template.metadata.labels에 정의된 Pod 레이블과 일치할 수 있어야 합니다. 그렇지 않으면 Kubernetes는 statefulset 생성을 허용하지 않습니다.

Statefulset 사용 사례: 웹 사이트 배포

#创建存储类
[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은 포드를 관리합니다: 확장, 확장, 업데이트

#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 처음부터 배우세요
시청해주셔서 감사합니다 개인적인 이해가 섞인 글입니다 오류가 있으면 연락주시고 지적해주세요~

추천

출처blog.csdn.net/qq_45400861/article/details/127035455