StatefulSet常用于部署有状态的且需要有序启动的应用程序。和Deployment类似,一个StatefulSet也同样管理着基于相同容器规范的Pod,不同的是,StatefulSet为每个Pod维护了一个粘性标识。
一般StatefulSet用于有以下一个或者多个需求的应用程序:
需要稳定的独一无二的网络标识;
需要持久化数据;
需要有序的,优雅的部署和扩展;
需要有序的自动滚动更新。
1. 定义一个 StatefulSet 资源文件
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:
serviceName: "nginx" # 和Deployment的区别之一
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.cn-beijing.aliyuncs.com/jiangxiaonan/nginx:1.22.1
ports:
- containerPort: 80
name: web
Service定义了一个名字为Nginx的Headless Service,创建的Service格式为nginx-0.nginx.defaule.svc.cluster.local,其他的类似,因为没有指定Namespace(命名空间),所以默认部署在defaule;
StatefulSet定义了一个名字为web的StatefulSet, replicas表示部署Pod的副本数, 本实例为2。
在 StatefulSet 中 必 须 设 置 Pod 选 择 器 ( .spec.selector ) 用 来 匹 配 其 标 签(.spec.template.metadata.labels)。
当 StatefulSet 控制器创建 Pod 时,它会添加一个标签 statefulset.kubernetes.io/pod-name,该标签的值为 Pod 的名称,用于匹配 Service。
2. 创建 StatefulSet
kubectl create -f sts-web.yaml # 也可以使用-n 部署到其他 namespace
# kubectl get sts
NAME READY AGE
web 2/2 10m
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 169d
nginx ClusterIP None <none> 80/TCP 11m
kubectl get po -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 8m54s
web-1 1/1 Running 0 8m52s
StatefulSet 创建 Pod 流程:
StatefulSet 管理的 Pod 部署和扩展规则如下:
1. 对于具有N个副本的StatefulSet,将按顺序从0到N-1开始创建Pod;
2. 当删除Pod时,将按照N-1到0的反顺序终止;
3. 在缩放Pod之前,必须保证当前的Pod是Running(运行中)或者Ready(就绪);
4. 在终止Pod之前,它所有的继任者必须是完全关闭状态。
3. StatefulSet 扩容和缩容
和 Deployment 类似,可以通过更新 replicas 字段扩容/缩容 StatefulSet,也可以使用 kubectlscale、 kubectl edit 和 kubectl patch 来扩容/缩容一个 StatefulSet。
可以直接修改副本数,例如:
kubectl scale sts web --replicas=5
# 或者使用patch命令
kubectl patch sts web -p '{"spec":{"replicas":3}}'
查看扩容后 Pod 的状态:
kubectl get po
也可使用以下命令动态查看:
kubectl get pods -w -l app=nginx
4. StatefulSet 更新策略
On Delete 策略
OnDelete 更新策略实现了传统(1.7 版本之前)的行为,它也是默认的更新策略。 当我们选择这个更新策略并修改 StatefulSet 的.spec.template 字段时, StatefulSet 控制器不会自动更新 Pod,必须手动删除 Pod 才能使控制器创建新的 Pod。
RollingUpdate 策略
RollingUpdate(滚动更新) 更新策略会自动更新一个 StatefulSet 中所有的 Pod,采用与序号索引相反的顺序进行滚动更新。
分段更新
StatefulSet可以使用RollingUpdate更新策略的partition参数来分段更新一个StatefulSet。分段更新将会使StatefulSet中其余的所有Pod(序号小于分区)保持当前版本,只更新序号大于等于分区的Pod,利用此特性可以简单实现金丝雀发布(灰度发布)或者分阶段推出新功能等。
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
说明:有了partition参数不会自动更新,需要手动删除pod进行更新。
5. 删除StatefulSet
删除StatefulSet有两种方式,级联删除和非级联删除。使用非级联删除方式删除StatefulSet时,StatefulSet的Pod不会被删除;使用级联删除时,StatefulSet和他的Pod都会被删除。
级联删除:
kubectl delete statefulset web
非级联删除:
kubectl delete statefulset web --cascade=false # 采用非级联删除
说明:在级联删除的基础上,加上--cascade=false即为非级联删除。
使用非级联删除方式删除StatefulSet,它管理的Pod变成了“孤儿”Pod,因此单独删除Pod时,该Pod不会被重建。