该篇文章已经被专栏《从零开始学k8s》收录
上一篇文章:kubernetes持久化存储下 点击跳转
Statefulset 控制器:概念、原明确读
StatefulSet 是为了管理有状态服务的问题而设计的
对于StatefulSet中的Pod,每个Pod挂载本身独立的存储,假如一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续以它的状态提供服务。
有状态服务?
StatefulSet 是有状态的聚集,管理有状态的服务,它所管理的 Pod 的名称不能随意变革。数据持久化的目录也是不一样,每一个 Pod 都有本身独有的数据持久化存储目录。比如 MySQL 主从、redis 集群等。
- 让每个Pod独立的
- 让每个Pod独立的,保持Pod启动次序和唯一性
- 唯一的网络标识符,持久存储
- 有序,比如mysql中的主从
适合StatefulSet的业务包括数据库服务 MySQL 和 PostgreSQL,集群化管理服务Zookeeper、etcd等有状态服务
StatefulSet的另一种典范应用场景是作为一种比普通容器更稳定可靠的模拟虚拟机的机制。传统的虚拟机正是一种有状态的宠物,运维人员需要不断地维护它,容器刚开始流行时,我们用容器来模拟虚拟机使用,所有状态都保存在容器里,而这已被证明是非常不安全、不可靠的。
使用StatefulSet,Pod仍然可以通过漂移到差别节点提供高可用,而存储也可以通过外挂的存储来提供高可靠性,StatefulSet做的只是将确定的Pod与确定的存储关联起来保证状态的连续性。
无状态服务?
RC、Deployment、DaemonSet 都是管理无状态的服务,它们所管理的 Pod 的 IP、名字,启停次序等都是随机的。个体对团体无影响,所有 pod 都是共用一个数据卷的,摆设的 tomcat 就是无状态的服务,tomcat 被删除,在启动一个新的 tomcat,到场到集群即可,跟 tomcat 的名字无关。
- 以为Pod都是一样的
- 没有次序要求
- 不考虑应用在哪个node上运行
- 可以大概举行随意伸缩和扩展
StatefulSet 由以下几个部门组成:
1.Headless Service:用来定义 pod 网路标识,生成可剖析的 DNS 记录
2.volumeClaimTemplates:存储卷申请模板,创建 pvc,指定 pvc 名称巨细,主动创建 pvc,且 pvc 由存储类供应。
3.StatefulSet:管理 pod 的
什么是 Headless service
Headless service 不分配 clusterIP,headless service 可以通过剖析 service 的 DNS,返回所有 Pod 的 dns 和 ip 地点 (statefulSet 摆设的 Pod 才有 DNS),普通的 service,只能通过剖析 service 的 DNS 返回 service 的 ClusterIP。
为什么要用 headless service(没有 service ip 的 service)?
在使用 Deployment 时,创建的 Pod 名称是没有次序的,是随机字符串,在用 statefulset 管理 pod 时要求 pod 名称必须是有序的 ,每一个 pod 不能被随意代替,pod 重建后 pod 名称还是一样的。因为 pod IP 是变革的,以是要用 Pod 名称来辨认。pod 名称是 pod 唯一性的标识符, 必须持久稳定有用。这时间要用到无头服务,它可以给每个 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 主从,由于主从数据库的数据是不能存放在一个目录下的,每个 mysql 节点都需要有本身独立的存储空间。而在 deployment 中创建的存储卷是一个共享的存储卷,多个 pod 使用同一个存储卷,它们数据是同步的,而 statefulset 定义中的每一个 pod 都不能使用同一个存储卷,这就需要使用 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 资源中有两个 spec 字段。
第一个 spec 声明的是 statefulset 定义多少个 Pod 副本(默认将仅摆设 1 个 Pod)、匹配 Pod 标签的选择器、创建 pod 的模板、存储卷申请模板。
第二个 spec 是 spec.template.spec:主要用于 Pod 里的容器属性等配置。.spec.template 里的内容是声明 Pod 对象时要定义的各种属性,以是这部门也叫做 PodTemplate(Pod 模板)。
另有一个值得留意的地方是:在.spec.selector 中定义的标签选择器必须可以大概匹配到 spec.template.metadata.labels 里定义的 Pod 标签,否则 Kubernetes 将 不答应创建 statefulset。
Statefulset 使用案例:摆设 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 了
复制代码 写在最后
创作不易,假如觉得内容对你有帮助,麻烦给个三连关注支持一下我!假如有错误,请在评论区指出,我会实时更改!
目前正在更新的系列:从零开始学k8s
感谢各位的观看,文章掺杂个人明确,如有错误请联系我指出~
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |