Kubernetes / 云计算

Kubernetes Statefulset控制器

浅时光 · 11月22日 · 2020年 2075次已读

一、场景概述


在应用程序中,我们大体称为有两类,一种是有状态应用,一种是无状态应用

  • 无状态应用比如Nginx
  • 有状态应用比如Redis、MySQL、ETCD、zk等都要存储数据的我们都称之为有状态应用

它们不只有所谓的节点之分,节点还有每个Pod对应的角色之分,有的是主节点,有的是从节点,然后这些从节点不光有所谓的从之分,还有前后顺序之分。

不同的分布式系统,它们的运维逻辑、运维管理和运维操作是不尽相同的,因此没有办法;有一种控制器把每一种功能都同步进来,让我们非常简单的去操作这些有状态的应用;即便后面有了Statefulset控制器,我们用Statefulset去实现真正的功能控制时,也是极其麻烦的;

       Statefulset控制器即便在一定文章来源(Source):https://www.dqzboy.com程度上能实现有状态应用的管理技巧,但是需要我们自行把我们对于某个应用的运维管理过程写成脚本注入到Statefulset应用文件中才能使用;

       在K8S中支持CRD(第三方资源或自定义资源)这种机制,甚至还支持更为复杂的机制,比如:Api聚合(需修改K8S源代码,增强我们需要的功能),所以使用Statefulset去封装所有的有状态应用还是一个难题;后来CoreOS在此基础之上提供了Operator组件,我们可以把运维操作封装在此组件当中就可以实现很复杂的运维逻辑了。

二、Statefulset控制器


Statefulset叫做有状态应用副本集;在无状态中我们更关注的是群体,任何一个都可以轻易被其他的所取代,换一个或新增一个,我们不需要关注跟原来是否一模一样,我们只需要保证应用程序一样即可,因为它没有任何数据和自己本地的状态;但是对于有状态应用来说,这些我们就需要保证跟原来的一模一样,有状态应用更关注的是个体。

Statefulset主要管理以下有特性的服务:

       (1)稳定且需要唯一的网络标识符

       (2)稳定且持久的存储设备;例如某个节点down了,那么这个节点重新启动时,需要保证这个节点存储的数据还在

       (3)要求有序平滑的部署和扩展;例如Redis集群,我们需要先启动主节点,然后在启动从节点,如果从有先后顺序,那么还需要按顺序启动从节点

       (4)有序平滑的终止和删除;例如一个一主八从的Redis集群,那关闭时则需要根据启动顺序关闭从节点,最后关闭主节点

       (5)有序的滚动更新;例如Redis集群,更新时则需要先更新从节点,从节点也是需要逆序的顺序进行更新,最后更新主节点

三、Statefulset的组件


1、headless service

无头服务

例如在使用Deploment控制器去创建Pod时,每一个Pod的名称是随机字符串,我们无法识别它们的顺序,因此它是无序的;但是在Statefulset中必须是有序的,所以每一个节点每一个Pod都不能被随意被取代,此前是什么状态重启之后还需保证与之前一模一样;

例如在Redis集群中,它们有很多的槽位来存储数据,如果某文章来源(Source):https://www.dqzboy.com个节点挂了之后重启起来之后的数据没有顺序了,那则出现了严重的问题;Pod的IP地址基本上是变化的,所以以Pod节点名称来识别,从而这个节点名称不能变,在有状态集当中每个节点的节点名称是不能变的,第一次是什么名称那么重建之后的Pod名称还必须是此前的名称,因为Pod的名称是作为识别Pod唯一性的标识符,这个标识符必须稳定持久和有效;保证这个Pod标识符稳定持久有效就需要用到headless service(无头服务),通过headless service来确保我们解析的名称是直达后端Pod IP地址的,还必须给每个Pod配置一个唯一的Pod名称。

2、StatefulSet

statefulset控制器

3、volumeClaimTemplate

存储卷申请模板

       例如创建3节点的Redis集文章来源(Source):https://www.dqzboy.com群中,那么这3个节点中存储的数据是不一样的,所文章来源(Source):https://www.dqzboy.com以这3个Pod是不能使用同一个存储卷的,每个节点必须有自己专用的存储卷,一定不能共享给其他节点,因为它是放自己的专有数据的;

       比如在Deployment的Pod模板中去定义了存储卷,那么创建了5个Pod副本那么这5个Pod访问是同一个存储卷,因为是文章来源(Source):https://www.dqzboy.com基于Pod模板创建Pod,这个Pod模板中定义了存储卷,那么基于这个Pod模板创建的所有Pod都是共享的同一个存储卷;

文章来源(Source):https://www.dqzboy.com

 &nb文章来源(Source):https://www.dqzboy.comsp;     但是在Statefulset中,每个Pod的存储卷都不能共享给其他的Pod,因此我们基于Pod模板来创建Pod是不适用的,这也就是为啥要给每个Pod定义volumeClaimTemplate的原因,这样我们每创建一个Pod时,它会自动为每个Pod生成一个专用PVC,从而绑定一个PV,实现每个Pod有自己专用的存储卷。

四、Statefulset的示例


  • 注意:每一个Statefulset控制器的服务都有以下三部分组成:

       (1)Service:服务,这个Service服务必须为无头服务

       (2)Statefulset控制器

       (3)存储卷

  • 注意:需要提前准备PV所绑定的存储集群设备
[[email protected] ~]# 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资源创建情况
[[email protected] ~]# kubectl get pv,pvc
Kubernetes Statefulset控制器-浅时光博客
  • 查看sts资源
[[email protected] ~]# kubectl get sts
NAME   READY   AGE
web    3/3     3d18h
  • 查看pod
[[email protected] ~]# kubectl get pods
Kubernetes Statefulset控制器-浅时光博客
可以通过文章来源(Source):https://www.dqzboy.com kubectl get po -w文章来源(Source):https://www.dqzboy.com 来动态查看pod的创建和删除的顺序

五、Statefulset扩缩容


1、说明

扩容和缩容,Statefulset控制器服务的扩容缩容都是顺序执行的。扩容正序,缩容为逆序

2、扩容

方式1
[[email protected] ~]# kubectl scale sts web --replicas=5
方式2
[[email protected] ~]# kubectl patch sts web -p '{"spec":{"replicas":5}}'

[[email protected] ~]# 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、缩容

方式1
[[email protected] ~]# kubectl scale sts web --replicas=2
方式2
[[email protected] ~]# kubectl patch sts web -p '{"spec":{"replicas":2}}'

[[email protected] ~]# 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更新是逆序的
文章来源(Source):https://www.dqzboy.com

4.1:打补丁

  • 以下表示为当前的Pod模板设置partition,然后更新时只有大于该值的Pod才会进行更新,这就实现了金丝雀发布
#例如:下面将partition设置为2
[[email protected] ~]# kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'

statefulset.apps/web patched

[[email protected] ~]# kubectl describe sts web
Kubernetes Statefulset控制器-浅时光博客
[[email protected] ~]# 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:金丝雀发布

[[email protected] ~]# kubectl set image sts/web nginx=nginx:1.16
statefulset.apps/web image updated
  • 参数说明:
    • sts/web:Statefulset资源下的Pod
    • nginx=nginx:1.16:更新Pod中容器名称为nginx的容器镜像版本
[[email protected] ~]# kubectl get sts web -o wide
NAME   READY   AGE     CONTAINERS   IMAGES
web    3/3     3d22h   nginx        nginx:1.16

[[email protected] ~]# kubectl get po
Kubernetes Statefulset控制器-浅时光博客
[[email protected] ~]# kubectl get po web-2 -o yaml
Kubernetes Statefulset控制器-浅时光博客
  • 可以看下web-0的Pod镜像版本,是保持原来的版本的
[[email protected] ~]# kubectl get po web-0 -o yaml
Kubernetes Statefulset控制器-浅时光博客

4.3:滚动更新

  • 滚动更新,则只需要把partition值改为0即可,这样Pod会以逆序的方式先终止Pod然后在进行重建
kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
  • 查看之前没有更新版本的web-0的pod的镜像是不是也已经更新到了1.16版本
[[email protected] ~]# kubectl describe po web-0
Kubernetes Statefulset控制器-浅时光博客
Kubernetes Statefulset控制器-浅时光博客
0 条回应
    本站已安全运行: | 耗时 0.717 秒 | 查询 106 次 | 内存 18.90 MB