15.实践篇:StatefulSet控制器是如何实现金丝雀发布的?

15.实践篇:StatefulSet控制器是如何实现金丝雀发布的?

2020-02-07 14:42:48

        如果说Deployments和ReplicaSets解决的是无状态服务部署、扩缩容的刚需,那么StatefulSet控制器则是为了解决有状态服务的部署难题。

1.What is StatefulSet?

StatefulSet是一个管理有状态应用的API对象。StatefulSet作为Controller为Pod提供其唯一的标识。它可以保证应用程序部署和扩展的先后顺序

2.StatefulSet的应用场景

StatefulSet 适用于有以下某个或多个需求的应用场景:

稳定,具有唯一的网络标志
稳定,含有持久化存储
有序,需要优雅地部署和扩展
有序,能够自动滚动升级

3.StatefulSet的使用限制

为了解决有状态应用的部署难题,StatefulSet也有其对应的使用限制:

对应pod上面的存储必须以存储类(https://github.com/kubernetes/examples/tree/master/staging/persistent-volume-provisioning/README.md)的方式提供,或者预先由管理员进行手动配置

我们再来回顾一下:

PVC:好比接口,使用者只需要知道这个接口如何使用即可,比如该传哪些参数,哪些是必传的等等,他并不需要了解接口是如何实现的。

PV:就是这些接口的实现,内部是用nfs,还是ceph的存储系统等等。

SC(存储类):则是这些接口根据一系列规则所进行的抽象类,通过接收pvc请求,从而启到动态实例化pv的效果。

删除或扩展StatefulSet将不会删除与StatefulSet相关联的volum。

这样做是为了确保数据安全性,通常比自动清除所有相关StatefulSet资源更有价值
StatefulSets现在要求以 Headless Service(https://kubernetes.io/docs/concepts/services-networking/service/#headless-services)网络模式进行`Pod`的网络身份标示

Headless Service知识点回顾:

这是一个比较特殊的service类型,有时候,你没必要或者不需要负载均衡和一个对外提供服务的ip地址。

在这种情况下,你可以在.spec.clusterIp中定义None字段,来申明一个Headless Service。

他可以通过coredns组件内部的解析功能,以完成相关地址解析的支持作用。

4.StatefulSet组成

Headless Service:用于为Pod资源标识符生成可解析的DNS记录,每个pod有唯一且有序的名称(在 [0,N)之间)。注意: [0,N)是一个左闭右开的区间!!!

VolumeClaimTemplates(存储卷申请模板):基于静态或动态PV供给方式为Pod资源提供专有的固定存储。

StatefulSet:用于管控Pod资源。

1>Headless Service在statefulset中是十分必要的,他给每个pod分配了唯一且有序的名称,当pod资源重建时候,他们将保持自己原有的序号。

2>statefulset定义中的每一个pod都不能使用同一个存储卷,并且有状态应用多半都需要存储系统,所以这时候这就需要引入volumeClainTemplate,当在使用statefulset创建pod时,会自动生成一个PVC,从而绑定一个自己专用的PV。

5.简单示例

开始操作前的准备工作:

你需要先准备一个存储类:storage-class。

我这里的存储类就选择之前配置的managed-nfs-storage(NFS Provisioner),你要记得使用的时候替换关键配置信息!

1)首先我们创建nginx.yaml的配置文件,其中serviceName申明了自己的headless service域,另外storageClassName需要指定成你自己的存储类。

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None    #我是headless
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"   #声明它属于哪个Headless Service.
  replicas: 2
  selector:
     matchLabels:
       app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      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"]
      volumeMode: Filesystem
      resources:
        requests:
          storage: 50Mi
      storageClassName: managed-nfs-storage      #存储类名,记得改为集群中已存在的

其中:

Headless Service:名为nginx,用来定义Pod网络标识( DNS domain)。
StatefulSet:定义具体应用,名为Nginx,有2个Pod副本,并为每个Pod定义了一个域名。
volumeClaimTemplates: 存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应。

2)使用kubectl apply -f生成资源,你会发现:

1.pod资源的生成是有序的,从0到1
2.pvc和pod有一定的命名规范
3.pvc和pv均为动态供给

#pod生成的条目
web-0   0/1   Pending   0     0s    <none>   <none>   <none>   <none>
web-0   0/1   Pending   0     0s    <none>   <none>   <none>   <none>
web-0   0/1   Pending   0     0s    <none>   k8s-node01.shared   <none>   <none>
web-0   0/1   ContainerCreating   0     0s    <none>   k8s-node01.shared   <none>   <none>
web-0   1/1   Running   0     9s    10.244.0.34   k8s-node01.shared   <none>   <none>
web-1   0/1   Pending   0     <invalid>   <none>   <none>   <none>   <none>
web-1   0/1   Pending   0     <invalid>   <none>   <none>   <none>   <none>
web-1   0/1   Pending   0     <invalid>   <none>   k8s-node01.shared   <none>   <none>
web-1   0/1   ContainerCreating   0     <invalid>   <none>   k8s-node01.shared   <none>   <none>
web-1   1/1   Running   0     4s    10.244.0.35   k8s-node01.shared   <none>   <none>

#sc、pv和pvc详情
[root@k8s-etcd-mater01 web]# kubectl get sc,pv,pvc
NAME                                              PROVISIONER      AGE
storageclass.storage.k8s.io/managed-nfs-storage   fuseim.pri/ifs   23m

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
persistentvolume/pvc-1a1a952c-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            2m46s
persistentvolume/pvc-2283c042-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            2m32s

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/www-web-0   Bound    pvc-1a1a952c-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   2m46s
persistentvolumeclaim/www-web-1   Bound    pvc-2283c042-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   2m32s

3)接下来我们对其进行扩容成5个节点,观察pod的生成次序以及pvc和pv的变化

kubectl scale statefulset web --replicas=5

#pod按序生成
web-2   0/1   Pending   0     0s    <none>   <none>   <none>   <none>
web-2   0/1   Pending   0     0s    <none>   <none>   <none>   <none>
web-2   0/1   Pending   0     0s    <none>   <none>   <none>   <none>
web-2   0/1   Pending   0     0s    <none>   k8s-node01.shared   <none>   <none>
web-2   0/1   ContainerCreating   0     0s    <none>   k8s-node01.shared   <none>   <none>
web-2   0/1   ErrImagePull   0     18s   10.244.0.37   k8s-node01.shared   <none>   <none>
web-2   0/1   ImagePullBackOff   0     33s   10.244.0.37   k8s-node01.shared   <none>   <none>
web-2   1/1   Running   0     56s   10.244.0.37   k8s-node01.shared   <none>   <none>
web-3   0/1   Pending   0     5s    <none>   <none>   <none>   <none>
web-3   0/1   Pending   0     5s    <none>   <none>   <none>   <none>
web-3   0/1   Pending   0     5s    <none>   <none>   <none>   <none>
web-3   0/1   Pending   0     5s    <none>   k8s-node01.shared   <none>   <none>
web-3   0/1   ContainerCreating   0     5s    <none>   k8s-node01.shared   <none>   <none>
web-3   1/1   Running   0     11s   10.244.0.38   k8s-node01.shared   <none>   <none>
web-4   0/1   Pending   0     0s    <none>   <none>   <none>   <none>
web-4   0/1   Pending   0     0s    <none>   <none>   <none>   <none>
web-4   0/1   Pending   0     3s    <none>   <none>   <none>   <none>
web-4   0/1   Pending   0     3s    <none>   k8s-node01.shared   <none>   <none>
web-4   0/1   ContainerCreating   0     3s    <none>   k8s-node01.shared   <none>   <none>
web-4   0/1   ErrImagePull   0     31s   10.244.0.39   k8s-node01.shared   <none>   <none>
web-4   0/1   ImagePullBackOff   0     43s   10.244.0.39   k8s-node01.shared   <none>   <none>
web-4   1/1   Running   0     47s   10.244.0.39   k8s-node01.shared   <none>   <none>

#sc、pv和pvc详情
[root@k8s-etcd-mater01 web]# kubectl get sc,pv,pvc
NAME                                              PROVISIONER      AGE
storageclass.storage.k8s.io/managed-nfs-storage   fuseim.pri/ifs   99m

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
persistentvolume/pvc-1a1a952c-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            78m
persistentvolume/pvc-2283c042-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            78m
persistentvolume/pvc-8d755bf2-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-2   managed-nfs-storage            61m
persistentvolume/pvc-ac75e90e-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-3   managed-nfs-storage            60m
persistentvolume/pvc-b32b1c9b-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-4   managed-nfs-storage            60m

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/www-web-0   Bound    pvc-1a1a952c-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   78m
persistentvolumeclaim/www-web-1   Bound    pvc-2283c042-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   78m
persistentvolumeclaim/www-web-2   Bound    pvc-8d755bf2-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   61m
persistentvolumeclaim/www-web-3   Bound    pvc-ac75e90e-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   60m
persistentvolumeclaim/www-web-4   Bound    pvc-b32b1c9b-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   60m

你可以发现他们都是按序生成的。

4)现在,我们将其缩容至1个节点

kubectl patch statefulset web -p '{"spec":{"replicas":1}}'

#pod是逆序下线的
web-4   1/1   Terminating   0     62m   10.244.0.39   k8s-node01.shared   <none>   <none>
web-4   0/1   Terminating   0     62m   10.244.0.39   k8s-node01.shared   <none>   <none>
web-4   0/1   Terminating   0     63m   10.244.0.39   k8s-node01.shared   <none>   <none>
web-4   0/1   Terminating   0     63m   10.244.0.39   k8s-node01.shared   <none>   <none>
web-3   1/1   Terminating   0     63m   10.244.0.38   k8s-node01.shared   <none>   <none>
web-3   0/1   Terminating   0     63m   <none>   k8s-node01.shared   <none>   <none>
web-3   0/1   Terminating   0     63m   <none>   k8s-node01.shared   <none>   <none>
web-3   0/1   Terminating   0     63m   <none>   k8s-node01.shared   <none>   <none>
web-2   1/1   Terminating   0     64m   10.244.0.37   k8s-node01.shared   <none>   <none>
web-2   0/1   Terminating   0     64m   10.244.0.37   k8s-node01.shared   <none>   <none>
web-2   0/1   Terminating   0     64m   10.244.0.37   k8s-node01.shared   <none>   <none>
web-2   0/1   Terminating   0     64m   10.244.0.37   k8s-node01.shared   <none>   <none>
web-1   1/1   Terminating   0     81m   10.244.0.35   k8s-node01.shared   <none>   <none>
web-1   0/1   Terminating   0     81m   10.244.0.35   k8s-node01.shared   <none>   <none>
web-1   0/1   Terminating   0     81m   10.244.0.35   k8s-node01.shared   <none>   <none>
web-1   0/1   Terminating   0     81m   10.244.0.35   k8s-node01.shared   <none>   <none>

#但pvc和pv还是存在的
[root@k8s-etcd-mater01 web]# kubectl get sc,pv,pvc
NAME                                              PROVISIONER      AGE
storageclass.storage.k8s.io/managed-nfs-storage   fuseim.pri/ifs   103m

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
persistentvolume/pvc-1a1a952c-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            83m
persistentvolume/pvc-2283c042-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            83m
persistentvolume/pvc-8d755bf2-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-2   managed-nfs-storage            65m
persistentvolume/pvc-ac75e90e-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-3   managed-nfs-storage            64m
persistentvolume/pvc-b32b1c9b-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            Delete           Bound    default/www-web-4   managed-nfs-storage            64m

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/www-web-0   Bound    pvc-1a1a952c-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   83m
persistentvolumeclaim/www-web-1   Bound    pvc-2283c042-2ef4-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   83m
persistentvolumeclaim/www-web-2   Bound    pvc-8d755bf2-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   65m
persistentvolumeclaim/www-web-3   Bound    pvc-ac75e90e-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   64m
persistentvolumeclaim/www-web-4   Bound    pvc-b32b1c9b-2ef6-11ea-82c1-001c42662fdd   50Mi       RWO            managed-nfs-storage   64m

5)最后我们delete -f nginx.yaml,你会发现pvc和pv还是存在的,这种设计是很合理的。

如果数据不再使用,也是需要手动删除的

kubectl delete pvc www-web-0 www-web-1 www-web-2 www-web-3 www-web-4

提示:pvc和pv的数据是否关联删除,是通过存储类中的archiveOnDelete字段决定的。
你是否还记得呢?

6.金丝雀发布的实现

我在deployment中也提过如何使用pause命令进行金丝雀发布,不知你是否还记得?
这里,我要讲的是statefulset中金丝雀发布的逻辑。

1) 具体金丝雀发布流程如下图所示

sts-canarydeploy.png

2) 说明:

statefulset资源是按序生成、命名规律,且逆序更新(是否还记得刚才的缩容操作)

partition参数:指定需要分区的数量。

当partition=3时,表示将Pod web-0、Pod web-1、Pod web-2视为1个分区,新版本只会更新Pod web-3和Pod web-4
当partition=0时,发布策略将会把剩余的Pod也都发布成新版本

partition字段的申明帮助:

kubectl explain sts.spec.updateStrategy.rollingUpdate.partition

@版权声明:51CTO独家出品,未经允许不能转载,否则追究法律责任


版权声明:
作者:WaterBear
链接:https://l-t.top/2051.html
来源:雷霆运维
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录