官方文档,https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/
1. StatefulSet基本概述
对于我们部署的应⽤,⼤体可以分为两类,⼀类是⽆状态应⽤
,⼀类是有状态应⽤
像web这种类型的应用,就属于无状态应用,他们不需要存储任何数据至本地,也没有任何次序之分,同时所提供的服务也是完全一样的,像这类应用,就可以通过Deployment控制器来进行编排和部署;
像MySQL、Redis这类需要存储数据的应用程序,称之为有状态应用,它们有的有角色之分,有的是主节点,有的是从节点,而有的又存在先后次序之分。
1.0 应用场景
StatefulSet是一种用于运行有状态应用程序的控制器
,它具有稳定的网络标识符
、有序的
、逐个更新的部署方式以
及持久性存储
等特点,适用于需要这些特性的有状态应用程序
简单来说:
- Pod有序的部署、扩容、删除和停止
- Pod分配一个稳定的且唯一的网络标识
- Pod分配一个独享的存储
1.1 什么是StatefulSet
StatefulSet 是用来管理有状态应用的工作负载 API 对象。
StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。
Kubernetes StatefulSet是一种用于运行有状态应用的控制器。
StatefulSet是一个有序的、可标识的Pod组,并且每个Pod都有一个独特的标识符。
这使得StatefulSet能够管理有状态应用程序,例如数据库或队列服务,这些应用程序需要稳定的网络标识符或持久性存储,并且需要有序的、逐个更新的部署方式。
ReplicaSet 控制器能够从一个预置的 Pod 模板创建一个或者多个 Pod 资源,除了主机名和 IP 地址之外,这些 Pod 资源并没有本质上的区别,就连 Pod 的名称也是使用同一种散列模式生成,具有很强的相似性。
若 ReplicaSet 控制器在 Pod 模板中包含了某些 PVC(Persistent Volume Claim)的引用,则由它创建的所有 Pod 资源都将共享此存储卷。PVC 后端的 PV 访问模型配置为 ReadOnlyMany 或者 ReadWriteMany 时,这些 Pod 资源中的容器应用挂载存储卷后也就有了相同的数据集。
不过大多数情况是,一个集群系统的分布式应用中,每个实例都有可能需要存储使用不同的数据集,或者各自拥有其专有的数据副本,例如:分布式系统 GlusterFS 和 分布式文档存储 MongoDB 中的每个实例各自使用专有的数据集,分布式服务框架 Zookeeper 以及主从复制集群中的 Redis 的每个实例各自拥有其专用的数据副本。
由于 ReplicaSet 控制器使用同一个模板生成 Pod 资源,显然,它无法实现为每个 Pod 资源创建专用的存储卷,以及组织多个只负责生成一个 Pod 资源的 ReplicaSet 控制器则有规模扩展不变的尴尬。自主式 Pod 资源又没有自愈能力。
其次,除了要用到专用持久化存储卷外,有些集群类的分布式应用实例在运行期间还存在角色上的差异,它们存在 单向/双向 的基于 IP 地址或 主机名 的引用关系,例如 主从复制集群中的 MySQL 从节点的引用。这类应用实例,每一个都应当作一个独立的个体对待。ReplicaSet 对象控制下的 Pod 资源重构后,其 名称 和 IP地址 都存在变动的可能性,因此无法适配此种场景需求。
因此,StatefulSet(有副本状态集)则是专门用来满足此类应用的控制器类型,由其管控的每个 Pod 对象都有着固定的主机名和专用存储卷,即便被重构后亦能保持不变。
1.2 StatefulSet特点
1. 稳定且唯一的网络标识符
2. 稳定且持久的存储.
3. 有序、平滑地部署和扩展.
4. 有序、平滑的删除和终止.
5. 有序的滚动更新
1. 稳定且唯一的网络标识符
2. 稳定且持久的存储.
3. 有序、平滑地部署和扩展.
4. 有序、平滑的删除和终止.
5. 有序的滚动更新
1.(StatefulSet提供稳定的Pod名称,结合HeadLessService提供Pod唯⼀的DNS标识)
2.为每个Pod提供⼀个PVC,作为后端的存储,Pod故障重新启动任然会使⽤此前的PVC
3.⽐如redis主从复制r1-r6,⼀般先启动主节点r1,⽽后启动从节点r2-r6
4.⽐如redis主从复制r1-r6,⼀般先从r6-r2从节点开始删除,最后删除r1主节点
5.⽐如Redis主从复制r1-r6,⼀般先更新r2-r6从节点,⽽后更新r1主节点,前提是能兼容
在上⾯描述中,“稳定的”意味着 Pod 调度或重调度的整个过程是有持久性的(名称不变、pvc不变)。如果应⽤程序不需要任何稳定的标识符或有序的部署以及删除,则应该使⽤⽆状态的副本控制器来部署应⽤程序,⽐如Deployment或者ReplicaSet
1.3 StatefulSet资源状态
StatefulSet 资源的状态主要包括以下几个方面:
- Replicas: 指定的副本数,即 .spec.replicas字段的值。表示 StatefulSet 管理的副本数量。
- ReadyReplicas: 表示已经就绪的副本数量,即当前运行且已经READY的Pod数。
- CurrentReplicas: 表示当前正在运行的副本数量,即运行中的Pod总数。
- UpdatedReplicas: 表示已经更新的副本数量,即最近一次更新中,更新成功的Pod数。
- CurrentRevision: 当前正在执行的修订版本号。
- UpdateRevision: StatefulSet 的当前修订版本号。 StatefulSet 的模板(.spec.template)每次更新时,这个值就会增加1
- collisionCount:表示在创建 Pod 时发生的命名冲突的次数。
- UpdateStatus: 最近一次更新的状态,可以是"Running"或者"Failed"。
- ObservedGeneration: 最近一次对 StatefulSet 资源的更改,已经被看到的 Generation 数。也就是说如果 StatefulSet 的 .spec 字段被修改,该值会更新。
status:
observedGeneration: 2
replicas: 3
readyReplicas: 3
currentReplicas: 3
updatedReplicas: 3
updateRevision: "2"
currentRevision: "2"
observedGeneration 是 2,表示 StatefulSet 的 .spec 字段已经修改过两次。
replicas 是 3,表示指定的副本数为 3。
readyReplicas, currentReplicas 和 updatedReplicas 都是 3,表示所有的 3 个副本都已经准备就绪。
updateRevision 和 currentRevision 都是 "2",表示 StatefulSet 的模板已经更新两次,当前正在运行的也是第 2 个版本。
updateStatus 没有出现,表示最近一次更新状态是正常的。
status:
observedGeneration: 2
replicas: 3
readyReplicas: 3
currentReplicas: 3
updatedReplicas: 3
updateRevision: "2"
currentRevision: "2"
observedGeneration 是 2,表示 StatefulSet 的 .spec 字段已经修改过两次。
replicas 是 3,表示指定的副本数为 3。
readyReplicas, currentReplicas 和 updatedReplicas 都是 3,表示所有的 3 个副本都已经准备就绪。
updateRevision 和 currentRevision 都是 "2",表示 StatefulSet 的模板已经更新两次,当前正在运行的也是第 2 个版本。
updateStatus 没有出现,表示最近一次更新状态是正常的。
1.4 StatefulSet组成部分
StatefulSet由三个组件组成:HeadLessService
、StateFulSet控制器
、VolumeClaimTemplate
StatefulSet控制器
StatefulSet名称是固定,且创建时按照顺序进⾏创建,并固定对应的Pod名称
Headless Service
用于为Pod资源标识符生成可解析的DNS记录
为什么要有headless
在deployment中,每一个pod是没有名称,是随机字符串,是无序的。而statefulset中是要求有序的,每一个pod的名称必须是固定的。当节点挂了,重建之后的标识符是不变的,每一个节点的节点名称是不能改变的。pod名称是作为pod识别的唯一标识符,必须保证其标识符的稳定并且唯一。 为了实现标识符的稳定,这时候就需要一个headless service 解析直达到pod,还需要给pod配置一个唯一的名称。
headless 使用场景
集群内部通信:Headless Service可以被用来实现Pod之间的直接通信,例如数据库集群中的各个节点之间的通信。
分布式计算:Headless Service可以被用来实现分布式计算
中的任务分发和结果收集,例如MapReduce中的Map和Reduce节点之间的通信。
自定义服务发现:Headless Service可以被用来实现一些自定义的服务发现机制,例如一些复杂的应用程序中的服务发现和路由。
Headless 和 Service对比
⽤来配置每个Pod的DNS名称,只要Pod的名称不变化,他们的DNS就是稳定且持久的
Headless Service是没有Cluster IP的Service(与普通Service的区别),在Headless Service中可以看到spec.ClusterIP=None。
若解析Headless Service的DNS域名,返回的是该Service对应的全部pod的Endpoint列表,StatefulSet在Headless Service基础上为StatefulSet控制的每个pod实例创建DNS域名,格式为$(pod_name).$(headless_service_name),全限定域名为:FQDN:$(pod_name).$(headless_service_name).$(namespace_name).svc.cluster.local
案例
apiVersion: v1
kind: Service #资源类型
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None # 为none,
selector:
app: nginx
apiVersion: v1
kind: Service #资源类型
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None # 为none,
selector:
app: nginx
这个 Service 被创建后并不会被分配一个 VIP,而是会以 DNS 记录的方式暴露出它所代理的 Pod格式为
<pod-name>.<svc-name>.<namespace>.svc.cluster.local
<pod-name>.<svc-name>.<namespace>.svc.cluster.local
VolumeClaimTemplate
作为分布式系统,每个Pod的数据是不⼀样的,所以每个Pod应该有⾃⼰的专有数据,所以他们不能使⽤同⼀个存储卷,应该使⽤各⾃⾃⼰的存储卷。(存储卷申请模板)
为什么要 有volumeClainTemplate
大部分有状态副本集都会用到持久存储,比如分布式系统来说,由于数据是不一样的,每个节点都需要自己专用的存储节点。而在deployment中pod模板中创建的存储卷是一个共享的存储卷
,多个pod使用同一个存储卷,而statefulset定义中的每一个pod都不能使用同一个存储卷,由此基于pod模板创建pod是不适应的,这就需要引入volumeClainTemplate,当在使用statefulset创建pod时,会自动生成一个PVC,从而请求绑定一个PV,从而有自己专用的存储卷。
1.4 StatefulSet更新策略
Kubernetes 1.7 版本起,StatefulSet 资源支持自动更新机制,其更新策略由 spec.updateStrategy 字段定义,默认为 RollingUpdate,即滚动更新
StatefulSet 的更新⽀持两种策略:onDelete
和RollingUpdate
,在.spec.updateStrategy 进⾏设定.并且滚动更新支持分区
滚动更新
RollingUpdate滚动更新
RollingUpdate 更新策略在 StatefulSet 中实现 Pod 的自动滚动更新。
当StatefulSet的 .spec.updateStrategy.type 设置为 RollingUpdate 时,默认为:RollingUpdate。
StatefulSet 控制器将在 StatefulSet 中删除并重新创建每个 Pod。 它将以与 Pod 终止相同的顺序进行(从最大的序数到最小的序数),每次更新一个 Pod。 在更新其前身之前,它将等待正在更新的 Pod 状态变成正在运行并就绪。
#默认更新策略RollingUpdate
updateStrategy:
rollingUpdate:
partition: 0 #不更新小于 N 的副本
type: RollingUpdate
#默认更新策略RollingUpdate
updateStrategy:
rollingUpdate:
partition: 0 #不更新小于 N 的副本
type: RollingUpdate
#命令跟踪 StatefulSet 资源滚动更新过程中的状态信息
kubectl rollout status
#命令跟踪 StatefulSet 资源滚动更新过程中的状态信息
kubectl rollout status
OnDelete更新
当 StatefulSet 的 .spec.updateStrategy.type
设置为OnDelete
时, 控制器将不会⾃动更新 StatefulSet 中的 Pod。⽤户必须⼿动删除 Pod 以便让控制器创建新的 Pod,以此来对StatefulSet 的 .spec.template
的变动作出反应。
修改:
updateStrategy:
rollingUpdate:
partition: 0
type: RollingUpdate
改为:
updateStrategy:
type: OnDelete #修改为OnDelete更新模式并保存,该更新策略是,删除时才会进行更新
修改:
updateStrategy:
rollingUpdate:
partition: 0
type: RollingUpdate
改为:
updateStrategy:
type: OnDelete #修改为OnDelete更新模式并保存,该更新策略是,删除时才会进行更新
💡 总结
StatefulSet 这个控制器的主要作用之一,就是使用 Pod 模板创建 Pod 的时候,对它们进行编号,并且按照编号顺序逐一完成创建工作。而当 StatefulSet 的“控制循环”发现 Pod 的“实际状态”与“期望状态”不一致,需要新建或者删除 Pod 进行“调谐”的时候,它会严格按照这些 Pod 编号的顺序,逐一完成这些操作.
在StatefulSet中,每个Pod都会被分配一个唯一的标识符和DNS记录,例如web-0.web.default.svc.cluster.local、web-1.web.default.svc.cluster.local等
1.5 暂存更新操作
当用户需要设定一个更新操作,但又不希望它立即执行时,可将更新操作予以 "暂存",待条件满足后再手动触发其执行更新。
StatefulSet 资源的分区更新机制能够实现此项功能。在设定更新操作之前,将.spec.updateStrategy.rollingUpdate.partition 字段的值设置为 Pod 资源的副本数量,即比 Pod 资源的最大索引号大 1,这就意味着,所有的 Pod 资源都不会处于可直接更新的分区之内,那么于其后设定的更新操作也就不会真正执行,直到用户降低分区编号至现有 Pod 资源索引号范围之内。
#查看帮助
kubectl explain statefulset.spec.updateStrategy.rollingUpdate.partition
#查看帮助
kubectl explain statefulset.spec.updateStrategy.rollingUpdate.partition
下面测试滚动更新暂存更新操作,首先将 StatefulSet 资源滚动更新分区值设定为 3:
kubectl patch statefulset myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":3}}}}'
kubectl patch statefulset myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":3}}}}'
暂存状态的更新操作对所有的 Pod 资源均不产生影响,比如即使删除某 Pod 资源,它依然会基于旧的版本镜像进行重建
2. 案例
💡 说明
创建顺序如下:
1、Volume
2、Persistent Volume
3、Persistent Volume Claim
4、Headless Service
5、StatefulSet
Volume可以有很多种类型,比如nfs、glusterfs,ceph RBD等
2.1 Statefulset资源规范
#查看帮助
kubectl explain statefulset
[root@kube-master statefulSet]# 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- #选择器,必选项
serviceName <string> -required- #服务名称,必选项
template <Object> -required- #模板,必选项
updateStrategy <Object> #更新策略
volumeClaimTemplates <[]Object> #存储卷申请模板,列表对象形式
#查看帮助
kubectl explain statefulset
[root@kube-master statefulSet]# 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- #选择器,必选项
serviceName <string> -required- #服务名称,必选项
template <Object> -required- #模板,必选项
updateStrategy <Object> #更新策略
volumeClaimTemplates <[]Object> #存储卷申请模板,列表对象形式
2.2 创建Headless
[root@kube-master statefulSet]# cat 01-web-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: web-svc #这里要创建statefulset 里面的serviceName的名字保持一致
spec:
selector:
app: my-app
clusterIP: None
ports:
- port: 80
targetPort: 80
[root@kube-master statefulSet]# cat 01-web-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: web-svc #这里要创建statefulset 里面的serviceName的名字保持一致
spec:
selector:
app: my-app
clusterIP: None
ports:
- port: 80
targetPort: 80
- 执行
[root@kube-master statefulSet]# kubectl apply -f 01-web-headless.yaml
service/my-service-headless created
[root@kube-master statefulSet]# kubectl apply -f 01-web-headless.yaml
service/my-service-headless created
2.3 创建StatefulSet服务
[root@kube-master statefulSet]# cat 2-web-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: my-app #必须匹配 .spec.template.metadata.labels
serviceName: web-svc #声明它属于哪个Headless Service.
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app-web-nginx
image: nginx:1.16
ports:
- containerPort: 80
volumeMounts:
- name: my-app-web-vol
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: my-app-web-vol
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "nfs-provisioner-storage"
resources:
requests:
storage: 1Gi
[root@kube-master statefulSet]# cat 2-web-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: my-app #必须匹配 .spec.template.metadata.labels
serviceName: web-svc #声明它属于哪个Headless Service.
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app-web-nginx
image: nginx:1.16
ports:
- containerPort: 80
volumeMounts:
- name: my-app-web-vol
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: my-app-web-vol
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "nfs-provisioner-storage"
resources:
requests:
storage: 1Gi
❌ 注意
定义 StatefulSet 资源时,spec 中必须要嵌套的字段为 "serviceName" 和 "template",用于指定关联的 Headless Service 和要使用的 Pod 模板
- 查看
[root@kube-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 1 (13m ago) 19m
web-1 1/1 Running 1 (12m ago) 19m
web-2 1/1 Running 1 (12m ago) 19m
[root@kube-master statefulSet]# kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/my-app-web-vol-myapp-web-sts-0 Bound pvc-0aad5ba3-1921-4772-a410-44ab7239523e 1Gi RWO nfs-provisioner-storage 82m
persistentvolumeclaim/my-app-web-vol-myapp-web-sts-1 Bound pvc-1348f5f1-1505-49fd-aa33-f251ef8ffc00 1Gi RWO nfs-provisioner-storage 17m
persistentvolumeclaim/my-app-web-vol-myapp-web-sts-2 Bound pvc-7d8f415d-3ebe-49f9-9910-8f3ef36bba57 1Gi RWO nfs-provisioner-storage 15m
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-0aad5ba3-1921-4772-a410-44ab7239523e 1Gi RWO Delete Bound default/my-app-web-vol-myapp-web-sts-0 nfs-provisioner-storage 82m
persistentvolume/pvc-1348f5f1-1505-49fd-aa33-f251ef8ffc00 1Gi RWO Delete Bound default/my-app-web-vol-myapp-web-sts-1 nfs-provisioner-storage 17m
persistentvolume/pvc-7d8f415d-3ebe-49f9-9910-8f3ef36bba57 1Gi RWO Delete Bound default/my-app-web-vol-myapp-web-sts-2 nfs-provisioner-storage 15m
[root@kube-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 1 (13m ago) 19m
web-1 1/1 Running 1 (12m ago) 19m
web-2 1/1 Running 1 (12m ago) 19m
[root@kube-master statefulSet]# kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/my-app-web-vol-myapp-web-sts-0 Bound pvc-0aad5ba3-1921-4772-a410-44ab7239523e 1Gi RWO nfs-provisioner-storage 82m
persistentvolumeclaim/my-app-web-vol-myapp-web-sts-1 Bound pvc-1348f5f1-1505-49fd-aa33-f251ef8ffc00 1Gi RWO nfs-provisioner-storage 17m
persistentvolumeclaim/my-app-web-vol-myapp-web-sts-2 Bound pvc-7d8f415d-3ebe-49f9-9910-8f3ef36bba57 1Gi RWO nfs-provisioner-storage 15m
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-0aad5ba3-1921-4772-a410-44ab7239523e 1Gi RWO Delete Bound default/my-app-web-vol-myapp-web-sts-0 nfs-provisioner-storage 82m
persistentvolume/pvc-1348f5f1-1505-49fd-aa33-f251ef8ffc00 1Gi RWO Delete Bound default/my-app-web-vol-myapp-web-sts-1 nfs-provisioner-storage 17m
persistentvolume/pvc-7d8f415d-3ebe-49f9-9910-8f3ef36bba57 1Gi RWO Delete Bound default/my-app-web-vol-myapp-web-sts-2 nfs-provisioner-storage 15m
2.4 测试dns解析
测试格式,$(pod_name).$(headless_service_name).$(namespace_name).svc.cluster.local
也可以简写为,$(pod_name).$(headless_service_name)
kubectl run -it --image=busybox:1.28.3 dns-test --restart=Never --rm /bin/sh
/ # nslookup web-1.web-svc
Server: 192.168.0.10
Address 1: 192.168.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.web-svc
Address 1: 172.17.74.114 web-1.web-svc.default.svc.cluster.local
测试格式,$(pod_name).$(headless_service_name).$(namespace_name).svc.cluster.local
也可以简写为,$(pod_name).$(headless_service_name)
kubectl run -it --image=busybox:1.28.3 dns-test --restart=Never --rm /bin/sh
/ # nslookup web-1.web-svc
Server: 192.168.0.10
Address 1: 192.168.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.web-svc
Address 1: 172.17.74.114 web-1.web-svc.default.svc.cluster.local
- 删除pod
[root@kube-master statefulSet]# kubectl get pod -owide -l app=my-app
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 2m58s 172.30.0.148 kube-node01 <none> <none>
web-1 1/1 Running 0 2m56s 172.17.74.117 kube-node03 <none> <none>
web-2 1/1 Running 0 2m54s 172.23.127.102 kube-node02 <none> <none>
[root@kube-master statefulSet]# kubectl delete pod -l app=my-app
pod "web-0" deleted
pod "web-1" deleted
pod "web-2" deleted
[root@kube-master statefulSet]# kubectl get pod -owide -l app=my-app
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 6s 172.30.0.176 kube-node01 <none> <none>
web-1 1/1 Running 0 4s 172.17.74.115 kube-node03 <none> <none>
web-2 1/1 Running 0 3s 172.23.127.87 kube-node02 <none> <none>
[root@kube-master statefulSet]# kubectl get pod -owide -l app=my-app
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 2m58s 172.30.0.148 kube-node01 <none> <none>
web-1 1/1 Running 0 2m56s 172.17.74.117 kube-node03 <none> <none>
web-2 1/1 Running 0 2m54s 172.23.127.102 kube-node02 <none> <none>
[root@kube-master statefulSet]# kubectl delete pod -l app=my-app
pod "web-0" deleted
pod "web-1" deleted
pod "web-2" deleted
[root@kube-master statefulSet]# kubectl get pod -owide -l app=my-app
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 6s 172.30.0.176 kube-node01 <none> <none>
web-1 1/1 Running 0 4s 172.17.74.115 kube-node03 <none> <none>
web-2 1/1 Running 0 3s 172.23.127.87 kube-node02 <none> <none>
Pod 的序号、主机名、SRV 条目和记录名称没有改变,但和 Pod 相关联的 IP 地址可能发生了改变 如果你需要查找并连接一个 StatefulSet 的活动成员,你应该查询 Headless Service 的 CNAME和 CNAME 相关联的 SRV 记录只会包含 StatefulSet 中处于 Running 和 Ready 状态的 Pod。
2.5 扩缩StatefulSet
对 StatefulSet 资源来说,kubectl scale
和 kubectl path
命令均可实现此功能,也可以使用 kubectl edit 命令直接修改其副本,或者在修改配置文件之后,由 Kubectl apply 命令重新声明
扩展StatefulSet副本数,它则会按照编号⼀个⼀个的顺序创建出来
kubectl scale statefulset web --replicas=5
kubectl scale statefulset web --replicas=5
查看Pod的创建过程,对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为0..N-1
kubectl get pod -l app=my-app -w
kubectl get pod -l app=my-app -w
或者
kubectl patch sts web -p '{"spec":{"replicas":4}}' -n nginx-ss #扩容
kubectl patch sts web -p '{"spec":{"replicas":2}}' -n nginx-ss #缩容
kubectl patch sts web -p '{"spec":{"replicas":4}}' -n nginx-ss #扩容
kubectl patch sts web -p '{"spec":{"replicas":2}}' -n nginx-ss #缩容
2.6 更新策略和版本升级
修改更新策略,以partition方式进行更新,更新值为2,只有myapp编号大于等于2的才会进行更新。类似于金丝雀部署方式
updateStrategy
rollingUpdate:
partition: 2 #副本大于设置的值时进行更新,也就是分段更新,这里是大于2的副本更新
type: RollingUpdate
updateStrategy
rollingUpdate:
partition: 2 #副本大于设置的值时进行更新,也就是分段更新,这里是大于2的副本更新
type: RollingUpdate
partiton是保留几个pod不更新,其他的pod进行更新
[root@k8s-master mainfests]# kubectl edit sts web
或者
[root@k8s-master mainfests]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
statefulset.apps/myapp patched
[root@k8s-master ~]# kubectl get sts web
NAME DESIRED CURRENT AGE
myapp 4 4 1h
[root@k8s-master ~]# kubectl describe sts web
Name: myapp
Namespace: default
CreationTimestamp: Wed, 10 Oct 2018 21:58:24 -0400
Selector: app=myapp-pod
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"apps/v1","kind":"StatefulSet","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"replicas":3,"selector":{"match...
Replicas: 4 desired | 4 total
Update Strategy: RollingUpdate
Partition: 2
......
[root@k8s-master mainfests]# kubectl edit sts web
或者
[root@k8s-master mainfests]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
statefulset.apps/myapp patched
[root@k8s-master ~]# kubectl get sts web
NAME DESIRED CURRENT AGE
myapp 4 4 1h
[root@k8s-master ~]# kubectl describe sts web
Name: myapp
Namespace: default
CreationTimestamp: Wed, 10 Oct 2018 21:58:24 -0400
Selector: app=myapp-pod
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"apps/v1","kind":"StatefulSet","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"replicas":3,"selector":{"match...
Replicas: 4 desired | 4 total
Update Strategy: RollingUpdate
Partition: 2
......
版本升级,将image的版本升级为v2,升级后对比web-2和web-1的image版本是不同的。这样就实现了金丝雀发布的效果。
[root@k8s-master mainfests]# kubectl set image sts/web myapp=ikubernetes/myapp:v3
statefulset.apps/myapp image updated
[root@k8s-master ~]# kubectl get sts -o wide
NAME DESIRED CURRENT AGE CONTAINERS IMAGES
web 4 4 1h myapp ikubernetes/myapp:v3
[root@k8s-master ~]# kubectl get pods web-2 -o yaml |grep image
- image: ikubernetes/myapp:v3
imagePullPolicy: IfNotPresent
image: ikubernetes/myapp:v3
imageID: docker-pullable://ikubernetes/myapp@sha256:b8d74db2515d3c1391c78c5768272b9344428035ef6d72158fd9f6c4239b2c69
[root@k8s-master ~]# kubectl get pods web-1 -o yaml |grep image
- image: ikubernetes/myapp:v2
imagePullPolicy: IfNotPresent
image: ikubernetes/myapp:v2
imageID: docker-pullable://ikubernetes/myapp@sha256:85a2b81a62f09a414ea33b74fb8aa686ed9b168294b26b4c819df0be0712d358
[root@k8s-master mainfests]# kubectl set image sts/web myapp=ikubernetes/myapp:v3
statefulset.apps/myapp image updated
[root@k8s-master ~]# kubectl get sts -o wide
NAME DESIRED CURRENT AGE CONTAINERS IMAGES
web 4 4 1h myapp ikubernetes/myapp:v3
[root@k8s-master ~]# kubectl get pods web-2 -o yaml |grep image
- image: ikubernetes/myapp:v3
imagePullPolicy: IfNotPresent
image: ikubernetes/myapp:v3
imageID: docker-pullable://ikubernetes/myapp@sha256:b8d74db2515d3c1391c78c5768272b9344428035ef6d72158fd9f6c4239b2c69
[root@k8s-master ~]# kubectl get pods web-1 -o yaml |grep image
- image: ikubernetes/myapp:v2
imagePullPolicy: IfNotPresent
image: ikubernetes/myapp:v2
imageID: docker-pullable://ikubernetes/myapp@sha256:85a2b81a62f09a414ea33b74fb8aa686ed9b168294b26b4c819df0be0712d358
将剩余的Pod也更新版本,只需要将更新策略的partition值改为0即可,如下:
[root@k8s-master mainfests]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched
[root@k8s-master ~]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 58m
web-1 1/1 Running 0 58m
web-2 1/1 Running 0 13m
web-3 1/1 Running 0 13m
web-1 1/1 Terminating 0 58m
web-1 0/1 Terminating 0 58m
web-1 0/1 Terminating 0 58m
web-1 0/1 Terminating 0 58m
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
web-0 1/1 Terminating 0 58m
web-0 0/1 Terminating 0 58m
web-0 0/1 Terminating 0 58m
web-0 0/1 Terminating 0 58m
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 2s
[root@k8s-master mainfests]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched
[root@k8s-master ~]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 58m
web-1 1/1 Running 0 58m
web-2 1/1 Running 0 13m
web-3 1/1 Running 0 13m
web-1 1/1 Terminating 0 58m
web-1 0/1 Terminating 0 58m
web-1 0/1 Terminating 0 58m
web-1 0/1 Terminating 0 58m
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
web-0 1/1 Terminating 0 58m
web-0 0/1 Terminating 0 58m
web-0 0/1 Terminating 0 58m
web-0 0/1 Terminating 0 58m
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 2s
2.7 删除StatefulSet
删除StatefulSet,它会从后往前删除,先删除web-1,然后删除web-0
kubectl delete statefulsets name
kubectl delete statefulsets name
删除 Pod 时,它们是逆序终⽌的,顺序为 N-1..0
statefulset删除分为两种
级联删除[默认] 删除statefulset时删除pod
非级联删除 删除statefulset时不删除pod
级联删除
kubectl delete statefulsets name
kubectl delete statefulsets name
非级联删除
[root@kube-master statefulSet]# kubectl delete sts web --cascade=orphan
statefulset.apps "web" deleted
[root@kube-master statefulSet]# kubectl delete sts web --cascade=orphan
statefulset.apps "web" deleted
[root@kube-master statefulSet]# kubectl get pod -l app=my-app
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 58m
web-1 1/1 Running 0 58m
[root@kube-master statefulSet]# kubectl get sts
No resources found in default namespace.
[root@kube-master statefulSet]# kubectl get pod -l app=my-app
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 58m
web-1 1/1 Running 0 58m
[root@kube-master statefulSet]# kubectl get sts
No resources found in default namespace.
💡 说明
非级联删除时,删除了sts 但是pod并未被删除
kubernetes 1.24以前版本参数 --cascade=false
kubernetes 1.24以后版本参数 --cascade=orphan