statefulset概述
stateful和stateless
”状态“
进程的时间属性,即随之时间的推进,进程处理的前后请求有无相关性,前面的请求处理对后续的请求处理有无影响,有影响的叫有状态应用;没有影响的前后的请求处理都是独立的叫无状态应用;
对于有状态的应用,k8s用statefulset控制器进行管理:保证了每个pod都由一个专用索引、有序部署、有序停止、固定的标识符、固定的存储卷,即便pod被重构后,各种特性也和之前保持一致;
statefulset的特性
statefulset的基础构成:
- headless service:用于解析各个pod的地址;
- statefulset:管理pod的生命周期;
- volumeClaimTemplate:基于静态或动态pv供给的方式绑定pv,给每一个pod
如图所示:
- 每个pod都有固定且唯一的标号
- 都有一个pvc并绑定一个pv,重构后也不变
- pod编号为数字结尾,pod启动是由小到大依次启动,停止则是反过来
statefulset基础应用
创建statefulset对象
1、创建pv对象
创建2个pv对象,后端存储是nfs,没有动态pv供给能力,但都定义在state存储类中,由后面statefulset的volumeClaimTemplates引用;
[root@client statefulset]# cat 1pv.yaml 2pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: state-pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: state
nfs:
path: /pv1
server: 192.168.80.101
apiVersion: v1
kind: PersistentVolume
metadata:
name: state-pv2
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: state
nfs:
path: /pv2
server: 192.168.80.101
[root@client statefulset]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
state-pv1 1Gi RWX Retain Available state 8s
state-pv2 1Gi RWX Retain Available state 34s
2、定义statefulset对象并创建
定义了headless的service,然后定义了statefulset控制器对象,在volumeClaimTemplates中引用了名为state的存储类,该类为上步定义的2个nfs的pv
[root@client statefulset]# cat statefulset-demo.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-state
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: app-state
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: state-stateset
spec:
serviceName: svc-state
replicas: 2
selector:
matchLabels:
app: app-state
template:
metadata:
labels:
app: app-state
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v5
ports:
- containerPort: 80
name: web
volumeMounts:
- name: myappdata
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: myappdata
spec:
accessModes:
- ReadWriteMany
storageClassName: "state"
resources:
requests:
storage: 1Gi
3、查看
查看statefulset控制器的events事件,
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 3s statefulset-controller create Claim myappdata-state-stateset-0 Pod state-stateset-0 in StatefulSet state-stateset success
Normal SuccessfulCreate 3s statefulset-controller create Pod state-stateset-0 in StatefulSet state-stateset successful
4、问题?
Warning FailedMount 22s kubelet, node1 MountVolume.SetUp failed for volume "state-pv2" : mount failed: exit status 32
创建pod时卡住,查看pod事件为绑定卷阶段出错了,
固定的pod标识符和存储卷
若statefulset创建成功,观察到的现象应该是:依次启动或停止;重建pod后,其主机名、存储卷pv、dns的解析记录cname都不变,其中dns解析的是cname保持不变,但具体到pod的ip还是会变;
statefulset资源扩缩容
statefulset扩容pod时,和deployment控制器类似,采用kubectl scale 加 --replicas=数量N即可,或者修改yaml文件再重新apply也可以;
statefulset的扩缩容,也都是按照顺序,串行执行的;
statefulset资源更新
滚动更新
kubectl set image statefulset state_name image_name=image_new_version
滚动更新也是按照顺序来的
设置字段:[root@client k8s_yaml]# kubectl explain statefulset.spec.updateStrategy
暂存更新
假设statefulset设置的副本数为3,那么其pod编号就是xx-0,xx-1,xx-2,所谓暂存更新就是将paritions数值设置为和副本数相等,即比pod编号大1,partions分区的意义为大于及等级该数值的pod会被更新;(需要先set image或直接修改yaml文件修改镜像的版本号)
默认partition数值是0,即更新了镜像版本后,pod会立刻开始逐个按照次序更新
如果将partition数值设置的一开始就和副本数一样大,那么即便更改了镜像版本,pod也不会开始更新,即暂存更新
语法:
[root@client k8s_yaml]# kubectl explain statefulset.spec.updateStrategy.rollingUpdate
KIND: StatefulSet
VERSION: apps/v1
RESOURCE: rollingUpdate <Object>
DESCRIPTION:
RollingUpdate is used to communicate parameters when Type is
RollingUpdateStatefulSetStrategyType.
RollingUpdateStatefulSetStrategy is used to communicate parameter for
RollingUpdateStatefulSetStrategyType.
FIELDS:
partition <integer>
Partition indicates the ordinal at which the StatefulSet should be
partitioned. Default value is 0.
金丝雀部署
在上一步设置了partition分区数值的基础之上,逐步调小分区数的值,假设调整到了2,那么编码为xx-2的pod会开始进行更新;
分阶段更新
和金丝雀部署更新类似,即分阶段修改分区数的值,直到0,假设pod有6个,编码分别从0-5,可以分3次将分区数设置为5、3、0,那么statefulset控制器会控制pod,进行3次更新,更新编码5、更新编码4,3、更新剩下的2,1,0;直到全部pod更新完毕;
ps:通常statefulset无法真正实现有状态应用pod的管理,因为不同类型的应用所需的运维操作不同,一般需要为不同的应用创建不同的operator,operator是对statefulset的进一步封装;一种operator只能管理一种有状态应用,如mysql、redis
红帽对operator介绍:https://www.redhat.com/en/topics/containers/what-is-a-kubernetes-operator