一、场景概述
在应用程序中,我们大体称为有两类,一种是有状态应用,一种是无状态应用
- 无状态应用比如Nginx
- 有状态应用比如Redis、MySQL、ETCD、zk等都要存储数据的我们都称之为有状态应用
它们不只有所谓的节点之分,节点还有每个Pod对应的角色之分,有的是主节点,有的是从节点,然后这些从节点不光有所谓的从之分,还有前后顺序之分。
不同的分布式系统,它们的运维逻辑、运维管理和运维操作是不尽相同的,因此没有办法;有一种控制器把每一种功能都同步进来,让我们非常简单的去操作这些有状态的应用;即便后面有了Statef
Statefulset控制器即便在一定程度上能实现有状态应用的管理技巧,但是需要我们自行把我们对于某个应用的运维管理过程写成脚本注入到Statefulset应用文件中才能使用;
在K8S中支持CRD(第三方资源或自定义资源)这种机制,甚至还支持更为复杂的机制,比如:Api聚合(需修改K8S源代码,增
二、Statefulset控制器
Statefulset叫做有状态应用副本集;在无状态中我们更关注的是群体,任何一个都可以轻易被其他的所取代,换一个或新增一个,我们不需要关注跟原来是否一模一样,我们只需要保证应用程序一样即可,因为它没有任何数据和自己本地的状态;但是对于有状态应用来说,这些我们就需要保证
(1)稳定且需要唯一的网络标识符
(2)稳定且持久的存储设备;例如某个节点down了,那么这个节点重新启动时,需要保证这个节点存储的数据还在
(3)要求有序平滑的部署和扩展;例如Redis集群,我们需要先启动主节点,然后在启动从节点,如果从有先后顺序,那么还需要按顺序启动从节点
(4)有序平滑的终止和删除;例如一个一主八从的Redis集群,那关闭时则需要根据启动顺序关闭从节点,最后关闭主节点
(5)有序的滚动更新;例如Redis集群,更新时则需要先更新从节点,从节点也是需要逆序的顺序进行更新,最后更新主节点
三、Statefulset的组件
1、headless service
例如在使用Deploment控制器去创建Pod时,每一个Pod的名称是随机字符串,我们无法识别它们的顺序,因此它是无序的;但是在Statefulset中必须是有序的,所以每一个节点每一个Pod都不能被随意被取代,此前是什么状态重启之后还需保证与之前一模一样;
例如在Redis集群中,它们有很多的槽位来存储数据,如果某个节点挂了之后重启起来之后的数据没有顺序了,那则出现了严重的问题;Pod的IP地址基本上是变化的,所以以Pod节点名称来识别,从而这个节点名称不能变,在有状态集当中每个节点的节点名称是不能变的,第一次是什么名称那么重建之后的Pod名称还必须是此前的名称,因为Pod的名称是作为识别Pod唯一性的标识符,这个标识符必须稳定持久和有效;保证这个Pod标识符稳定持久有效就需要用到headless service(无头服务)
,通过headless service
来确保我们解析的名称是直达后端Pod IP地址的,还必须给每个Pod配置一个唯一的Pod名称。
2、StatefulSet
3、volumeClaimTemplate
例如创建3节点的Redis集群中,那么这3个节点中存储的数据是不一样的,所以这3个Pod是不能使用同一个存储卷的,每个节点必须有自己专用的存储卷,一定不能共享给其他节点,因为它是放自己的专有数据的;
比如在Deployment的Pod模板中去定义了存储卷,那么创建了5个Pod副本那么这5个Pod访问是同一个存储卷,因为是基于Pod模板创建Pod,这个Pod模板中定义了存储卷,那么基于这个Pod模板创建的所有Pod都是共享的同一个存储卷;
但是在Statefulset中,每个Pod的存储卷都不能共享给其他的Pod,因此我们基于Pod模板来创建Pod是不适用的,
四、Statefulset的示例
- 注意:每一个Statefulset控制器的服务都有以下三部分组成:
(1)Service:服务,这个Service服务必须为无头服务
(2)Statefulset控制器
(3)存储卷
- 注意:需要提前准备PV所绑定的存储集群设备
[root@k8s-master1 ~]# vim statefulset-demo.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: 3 #副本数
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
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: "managed-nfs-storage" #这里与storage类文件定义的名称保持一致
resources:
requests:
storage: 1Gi
- 查看pv,pvc资源创建情况
[root@k8s-master1 ~]# kubectl get pv,pvc
- 查看sts资源
[root@k8s-master1 ~]# kubectl get sts
NAME READY AGE
web 3/3 3d18h
- 查看pod
[root@k8s-master1 ~]# kubectl get pods
五、Statefulset扩缩容
1、说明
扩容和缩容,Statefulset控制器服务的扩容缩容都是顺序执行的。扩容正序,缩容为逆序
2、扩容
[root@k8s-master1 ~]# kubectl scale sts web --replicas=5
[root@k8s-master1 ~]# kubectl patch sts web -p '{"spec":{"replicas":5}}'
[root@k8s-master1 ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 1 3d18h
web-1 1/1 Running 1 3d18h
web-2 1/1 Running 1 3d18h
web-3 1/1 Running 1 120s
web-4 1/1 Running 1 106s
3、缩容
[root@k8s-master1 ~]# kubectl scale sts web --replicas=2
[root@k8s-master1 ~]# kubectl patch sts web -p '{"spec":{"replicas":2}}'
[root@k8s-master1 ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 1 3d18h
web-1 1/1 Running 1 3d18h
4、滚动更新
- Statefulset默认更新策略:RollingUpdate,滚动更新
- 注意:sts更新是逆序的
4.1:打补丁
- 以下表示为当前的Pod模板设置
partition
,然后更新时只有大于该值的Pod才会进行更新,这就实现了金丝雀发布
#例如:下面将partition设置为2
[root@k8s-master1 ~]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
statefulset.apps/web patched
[root@k8s-master1 ~]# kubectl describe sts web
[root@k8s-master1 ~]# kubectl get po
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 1 3d22h
web-1 1/1 Running 1 3d22h
web-2 1/1 Running 0 5m15s
- 说明:以上设置2,表示只有Pod数量大于2的Pod才会进行更新,比如我现在Pods运行了3个,那么进行更新时,只会将web-2、web-1中的镜像进行更新,而web-0则保持原来的;更新是逆序的
4.2:金丝雀发布
[root@k8s-master1 ~]# kubectl set image sts/web nginx=nginx:1.16
statefulset.apps/web image updated
- 参数说明:
- sts/web:Statefulset资源下
文章来源(Source):浅时光博客 的Pod - nginx=nginx:1.16:更新Pod中容器名称为nginx的容器镜像版本
- sts/web:Statefulset资源下
[root@k8s-master1 ~]# kubectl get sts web -o wide
NAME READY AGE CONTAINERS IMAGES
web 3/3 3d22h nginx nginx:1.16
[root@k8s-master1 ~]# kubectl get po
[root@k8s-master1 ~]# kubectl get po web-2 -o yaml
- 可以看下
web-0
的Pod镜像版本,是保持原来的版本的
[root@k8s-master1 ~]# kubectl get po web-0 -o yaml
4.3:滚动更新
- 滚动更新,则只需要把
partition
值改为0即可,这样Pod会以逆序的方式先终止Pod然后在进行重建
kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
- 查看之前没有更新版本的web-0的pod的镜像是不是也已经更新到了1.16版本
[root@k8s-master1 ~]# kubectl describe po web-0
必须 注册 为本站用户, 登录 后才可以发表评论!