有状态应用管理StatefulSet

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


1、有状态应用管理StatefulSet

StatefulSet(有状态集,缩写为sts)常用于部署有状态的且需要有序启动的应用程序,比如在进行SpringCloud项目容器化时,Eureka的部署是比较适合用StatefulSet部署方式的,可以给每个Eureka实例创建一个唯一且固定的标识符,并且每个Eureka实例无需配置多余的Service,其余Spring Boot应用可以直接通过Eureka的Headless Service即可进行注册。

Eureka的statefulset的资源名称是eureka,eureka-0 eureka-1 eureka-2
Service:headless service,没有ClusterIP eureka-svc
Eureka-0.eureka-svc.NAMESPACE_NAME eureka-1.eureka-svc …

2、StatefulSet的基本概念

StatefulSet主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群、Kafka集群和ZooKeeper集群等。

和Deployment类似,一个StatefulSet也同样管理着基于相同容器规范的Pod。不同的是,StatefulSet为每个Pod维护了一个粘性标识。这些Pod是根据相同的规范创建的,但是不可互换,每个Pod都有一个持久的标识符,在重新调度时也会保留,一般格式为StatefulSetName-Number。比如定义一个名字是Redis-Sentinel的StatefulSet,指定创建三个Pod,那么创建出来的Pod名字就为Redis-Sentinel-0、Redis-Sentinel-1、Redis-Sentinel-2。而StatefulSet创建的Pod一般使用Headless Service(无头服务)进行通信,和普通的Service的区别在于Headless Service没有ClusterIP,它使用的是Endpoint进行互相通信,Headless一般的格式为:

statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local
  • serviceName为Headless Service的名字,创建StatefulSet时,必须指定Headless Service名称;
  • 0…N-1为Pod所在的序号,从0开始到N-1;
  • statefulSetName为StatefulSet的名字;
  • namespace为服务所在的命名空间;
  • .cluster.local为Cluster Domain(集群域)。

假如公司某个项目需要在Kubernetes中部署一个主从模式的Redis,此时使用StatefulSet部署就极为合适,因为StatefulSet启动时,只有当前一个容器完全启动时,后一个容器才会被调度,并且每个容器的标识符是固定的,那么就可以通过标识符来断定当前Pod的角色。

比如用一个名为redis-ms的StatefulSet部署主从架构的Redis,第一个容器启动时,它的标识符为redis-ms-0,并且Pod内主机名也为redis-ms-0,此时就可以根据主机名来判断,当主机名为redis-ms-0的容器作为Redis的主节点,其余从节点,那么Slave连接Master主机配置就可以使用不会更改的Master的Headless Service,此时Redis从节点(Slave)配置文件如下:

port 6379
slaveof redis-ms-0.redis-ms.public-service.svc.cluster.local 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
……

其中redis-ms-0.redis-ms.public-service.svc.cluster.local是Redis Master的Headless Service,在同一命名空间下只需要写redis-ms-0.redis-ms即可,后面的public-service.svc.cluster.local可以省略。

3、StatefulSet注意事项

一般StatefulSet用于有以下一个或者多个需求的应用程序:

  • 需要稳定的独一无二的网络标识符。
  • 需要持久化数据。
  • 需要有序的、优雅的部署和扩展。
  • 需要有序的自动滚动更新。

如果应用程序不需要任何稳定的标识符或者有序的部署、删除或者扩展,应该使用无状态的控制器部署应用程序,比如Deployment或者ReplicaSet。

StatefulSet是Kubernetes 1.9版本之前的beta资源,在1.5版本之前的任何Kubernetes版本都没有。

Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配置,当然也可以不配置存储。

为了确保数据安全,删除和缩放StatefulSet不会删除与StatefulSet关联的卷,可以手动选择性地删除PVC和PV

StatefulSet目前使用Headless Service(无头服务)负责Pod的网络身份和通信,需要提前创建此服务。

删除一个StatefulSet时,不保证对Pod的终止,要在StatefulSet中实现Pod的有序和正常终止,可以在删除之前将StatefulSet的副本缩减为0。

4、创建一个StatefulSet应用

  1. 定义一个StatefulSet资源文件
[root@k8s-master ~]# vim nginx-sts.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:
  serviceName: "nginx" 
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.2
        ports:
        - containerPort: 80
          name: web
  • kind: Service定义了一个名字为Nginx的Headless
    Service,创建的Service格式为nginx-0.nginx.default.svc.cluster.local,其他的类似,因为没有指定Namespace(命名空间),所以默认部署在default。
  • kind: StatefulSet定义了一个名字为web的StatefulSet,replicas表示部署Pod的副本数,本实例为2。

在StatefulSet中必须设置Pod选择器(.spec.selector)用来匹配其标签(.spec.template.metadata.labels)。在1.8版本之前,如果未配置该字段(.spec.selector),将被设置为默认值,在1.8版本之后,如果未指定匹配Pod Selector,则会导致StatefulSet创建错误。

当StatefulSet控制器创建Pod时,它会添加一个标签statefulset.kubernetes.io/pod-name,该标签的值为Pod的名称,用于匹配Service。

  1. 创建一个StatefulSet
[root@k8s-master ~]# kubectl create -f nginx-sts.yaml 
service/nginx created
statefulset.apps/web created

#查询pod
[root@k8s-master ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS       AGE
web-0                    1/1     Running   0              10m
web-1                    1/1     Running   0              10m

#查询service
[root@k8s-master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   10d
nginx        ClusterIP   None         <none>        80/TCP    31s

  1. 扩容service
[root@k8s-master ~]# kubectl get sts
NAME   READY   AGE
web    2/2     14m
您在 /var/spool/mail/root 中有新邮件
[root@k8s-master ~]# kubectl scale --replicas=3 sts web
statefulset.apps/web scaled

#查看pod
[root@k8s-master ~]# kubectl get po 
NAME                     READY   STATUS    RESTARTS       AGE
web-0                    1/1     Running   0              17m
web-1                    1/1     Running   0              17m
web-2                    1/1     Running   0              2m17s

  1. 新增busybox,解析无头service
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - name: busybox
    image: busybox:1.28
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
  restartPolicy: Always
EOF

#查看busybox启动状态
[root@k8s-master ~]# kubectl get po 
NAME                     READY   STATUS    RESTARTS       AGE
busybox                  1/1     Running   0              28s
web-0                    1/1     Running   0              49m
web-1                    1/1     Running   0              49m
web-2                    1/1     Running   0              33m

#进入busybox容器
[root@k8s-master ~]# kubectl exec -ti busybox -- sh
/ #

#解析IP
/ # nslookup web-0.nginx
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 192.169.214.209 web-0.nginx.default.svc.cluster.local

[root@k8s-master ~]# kubectl get po -owide
NAME                     READY   STATUS    RESTARTS       AGE     IP                NODE         NOMINATED NODE   READINESS GATES
busybox                  1/1     Running   0              5m18s   192.161.125.10    k8s-node01   <none>           <none>
web-0                    1/1     Running   0              53m     192.169.214.209   k8s-node03   <none>           <none>
web-1                    1/1     Running   0              53m     192.172.82.199    k8s-master   <none>           <none>
web-2                    1/1     Running   0              38m     192.169.214.210   k8s-node03   <none>           <none>

#直接通过名称 获取访问 192.169.214.209
/ # ping web-0.nginx
PING web-0.nginx (192.169.214.209): 56 data bytes
64 bytes from 192.169.214.209: seq=0 ttl=62 time=0.785 ms
64 bytes from 192.169.214.209: seq=1 ttl=62 time=0.854 ms
64 bytes from 192.169.214.209: seq=2 ttl=62 time=0.596 ms
64 bytes from 192.169.214.209: seq=3 ttl=62 time=0.758 ms

/ # wget web-0.nginx
Connecting to web-0.nginx (192.169.214.209:80)
index.html           100% |*******************************************************|   612   0:00:00 ETA

5、StatefulSet扩容缩容

  • StatefulSet副本启动顺序按照名称0,1,2,只有web-0完全启动之后才会启动web-1,web-1完全启动之后才会启动web-2
  • 删除的时候顺序与启动相反,从最后一个序号开始,2,1,0,如果web-2删除过程中,web-0挂掉了,那么web-1不会被删除,必须等待web-0启动状态变为ready之后,才会删除web-1
  • StatefulSet滚动更新的时候会先删除旧的副本,再创建新的副本,如果只有一个副本的话,会导致业务不可用,所以要根据自己的实际情况选择使用StatefulSet或者Deployment,如果必须固定主机名或者pod名称,建议使用StatefulSet
  1. 查看pod 动态加载过程
[root@k8s-master ~]# kubectl scale --replicas=5 sts web
statefulset.apps/web scaled

#显示创建顺序
[root@k8s-master ~]# kubectl get po -l controller-revision-hash=web-759965fcf4  -w
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          7m19s
web-1   1/1     Running   0          89m
web-2   0/1     Pending   0          0s
web-2   0/1     Pending   0          0s
web-2   0/1     ContainerCreating   0          0s
web-2   1/1     Running             0          3s
web-3   0/1     Pending             0          0s
web-3   0/1     Pending             0          0s
web-3   0/1     ContainerCreating   0          0s
web-3   1/1     Running             0          2s
web-4   0/1     Pending             0          0s
web-4   0/1     Pending             0          0s
web-4   0/1     ContainerCreating   0          0s
web-4   1/1     Running             0          2s

#缩容
[root@k8s-master ~]# kubectl scale --replicas=2 sts web
statefulset.apps/web scaled

#显示缩容顺序
[root@k8s-master ~]# kubectl get po -l controller-revision-hash=web-759965fcf4  -w
NAME    READY   STATUS    RESTARTS   AGE
web-4   1/1     Terminating         0          2m5s
web-4   0/1     Terminating         0          2m6s
web-4   0/1     Terminating         0          2m9s
web-4   0/1     Terminating         0          2m9s
web-3   1/1     Terminating         0          2m11s
web-3   0/1     Terminating         0          2m13s
web-3   0/1     Terminating         0          2m14s
web-3   0/1     Terminating         0          2m14s
web-2   1/1     Terminating         0          2m17s
web-2   0/1     Terminating         0          2m18s
web-2   0/1     Terminating         0          2m19s
web-2   0/1     Terminating         0          2m19s

[root@k8s-master ~]# kubectl get po 
NAME                     READY   STATUS    RESTARTS        AGE
busybox                  1/1     Running   0               44m
web-0                    1/1     Running   0               11m
web-1                    1/1     Running   0               92m
[root@k8s-master ~]#
 
#StatefulSet部署名称是固定的
[root@k8s-master ~]# kubectl exec -ti web-0 -- sh
# hostname
web-0

6、StatefulSet更新策略

  • RollingUpdate
  • OnDelete
  • StatefulSet和Deployment一样,有几种更新方式

RollingUpdate

  1. 查看更新策略
[root@k8s-master ~]# kubectl get sts -o yaml

updateStrategy:
      rollingUpdate:
        partition: 0
      type: RollingUpdate # 默认滚动更新,从下往上更新
  1. 扩容到5个副本
[root@k8s-master ~]# kubectl scale --replicas=5 sts web
statefulset.apps/web scaled

[root@k8s-master ~]# kubectl get po
NAME                     READY   STATUS    RESTARTS        AGE
web-0                    1/1     Running   0               54m
web-1                    1/1     Running   0               136m
web-2                    1/1     Running   0               6s
web-3                    1/1     Running   0               4s
web-4                    1/1     Running   0               2s
  • 滚动更新顺序是web-2,web-1,web-0,从下往上更新,如果更新过程中web-0挂掉了,则会等待web-0恢复到状态为ready之后再继续从下往上滚动更新
[root@k8s-master ~]# kubectl edit sts web
statefulset.apps/web edited

# 修改镜像
      - image: nginx:1.21.6

#查看pod状态
[root@k8s-master ~]# kubectl get po 
NAME                     READY   STATUS        RESTARTS       AGE
web-0                    1/1     Running       0              58m
web-1                    1/1     Running       0              140m
web-2                    1/1     Running       0              4m25s
web-3                    0/1     Terminating   0              4m23s
web-4                    1/1     Running       0              4s

查看更新顺序
[root@k8s-master ~]# kubectl get po -l app=nginx -w
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          57m
web-1   1/1     Running   0          139m
web-2   1/1     Running   0          2m43s
web-3   1/1     Running   0          2m41s
web-4   1/1     Running   0          2m39s
web-4   1/1     Terminating   0          4m14s
web-4   0/1     Terminating   0          4m16s
web-4   0/1     Terminating   0          4m17s
web-4   0/1     Terminating   0          4m17s
web-3   1/1     Terminating   0          4m21s
web-3   0/1     Terminating   0          4m22s
web-3   0/1     Terminating   0          4m23s
web-3   0/1     Terminating   0          4m23s
web-2   1/1     Terminating   0          4m27s
web-2   0/1     Terminating   0          4m29s
web-2   0/1     Terminating   0          4m32s
web-2   0/1     Terminating   0          4m33s
web-1   1/1     Terminating   0          140m
web-1   0/1     Terminating   0          140m
web-1   0/1     Terminating   0          141m
web-1   0/1     Terminating   0          141m
web-0   1/1     Terminating   0          59m
web-0   0/1     Terminating   0          59m
web-0   0/1     Terminating   0          59m
web-0   0/1     Terminating   0          59m

OnDelete

  1. 修改更新状态为OnDelete
[root@k8s-master ~]# kubectl edit sts web

 updateStrategy:
    type: OnDelete
  1. 修改nginx版本
[root@k8s-master ~]# kubectl set image sts web nginx=nginx:1.20.2 --record
Flag --record has been deprecated, --record will be removed in the future
statefulset.apps/web image updated

#状态未改变
[root@k8s-master ~]# kubectl get po web-0 -oyaml | grep image
  - image: nginx:1.21.6
    imagePullPolicy: IfNotPresent
    image: nginx:1.21.6
    imageID: docker-pullable://nginx@sha256:19da26bd6ef0468ac8ef5c03f01ce1569a4dbfb82d4d7b7ffbd7aed16ad3eb46

[root@k8s-master ~]# kubectl get po -l app=nginx -w
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          61m
web-1   1/1     Running   0          62m
web-2   1/1     Running   0          62m
web-3   1/1     Running   0          62m
web-4   1/1     Running   0          62m

#删除pod web-0 显示更新过程
[root@k8s-master ~]# kubectl delete po web-0
pod "web-0" deleted

[root@k8s-master ~]# kubectl get po -l app=nginx -w
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          61m
web-1   1/1     Running   0          62m
web-2   1/1     Running   0          62m
web-3   1/1     Running   0          62m
web-4   1/1     Running   0          62m
web-0   1/1     Terminating   0          69m
web-0   0/1     Terminating   0          69m
web-0   0/1     Terminating   0          69m
web-0   0/1     Terminating   0          69m
web-0   0/1     Pending       0          0s
web-0   0/1     Pending       0          0s
web-0   0/1     ContainerCreating   0          1s
web-0   1/1     Running             0          2s

#web-0 和  web-1 显示 不同的yaml 镜像版本 
[root@k8s-master ~]# kubectl get po web-0 -oyaml | grep image
  - image: nginx:1.20.2
    imagePullPolicy: IfNotPresent
    image: nginx:1.20.2
    imageID: docker-pullable://nginx@sha256:dc43c7f22a8310cac31cb27d7a3f63c5db1ee5eb0ac7944bc89a52dbd08b6d3c
[root@k8s-master ~]# kubectl get po web-1 -oyaml | grep image
  - image: nginx:1.21.6
    imagePullPolicy: IfNotPresent
    image: nginx:1.21.6
    imageID: docker-pullable://nginx@sha256:19da26bd6ef0468ac8ef5c03f01ce1569a4dbfb82d4d7b7ffbd7aed16ad3eb46

  • OnDelete 更新策略,只有在删除pod的时候,才会更新。如果同时删除多个,会总 0 开始更新到最后。

7、StatefulSet灰度发布

  1. 修改配置
[root@k8s-master ~]# kubectl edit sts web```

updateStrategy:
    rollingUpdate:
      partition: 2  #小于2的不会被更新
    type: RollingUpdate

[root@k8s-master ~]# kubectl set image sts web nginx=nginx:1.21.6 --record
Flag --record has been deprecated, --record will be removed in the future
statefulset.apps/web image updated

#显示只更新了大于 1 的 web-4  web-3 web-2
[root@k8s-master ~]# kubectl get po -l app=nginx -w
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          22m
web-1   1/1     Running   0          22m
web-2   1/1     Running   0          22m
web-3   1/1     Running   0          21m
web-4   1/1     Running   0          21m
web-4   1/1     Terminating   0          22m
web-4   0/1     Terminating   0          22m
web-4   0/1     Terminating   0          22m
web-4   0/1     Terminating   0          22m
web-4   0/1     Pending       0          0s
web-4   0/1     Pending       0          1s
web-4   0/1     ContainerCreating   0          1s
web-4   1/1     Running             0          2s
web-3   1/1     Terminating         0          22m
web-3   0/1     Terminating         0          22m
web-3   0/1     Terminating         0          22m
web-3   0/1     Terminating         0          22m
web-3   0/1     Pending             0          0s
web-3   0/1     Pending             0          0s
web-3   0/1     ContainerCreating   0          0s
web-3   1/1     Running             0          2s
web-2   1/1     Terminating         0          22m
web-2   0/1     Terminating         0          22m
web-2   0/1     Terminating         0          22m
web-2   0/1     Terminating         0          22m
web-2   0/1     Pending             0          0s
web-2   0/1     Pending             0          0s
web-2   0/1     ContainerCreating   0          0s
  • 可以使用这种机制实现灰度机制,先发布一两个实例,确认没有问题之后再发布所有实例,这就是stateful的分段更新,相当于灰度发布的机制,也可以使用其它的方式,比如服务网格,或者myservices

8、StatefulSet级联删除和非级联删除

  • 级联删除:删除sts时同时删除Pod
  • 非级联删除:删除sts时不删Pod
  1. 默认级联删除
[root@k8s-master ~]# kubectl get po 
NAME      READY   STATUS    RESTARTS      AGE
busybox   1/1     Running   3 (23m ago)   3h24m
web-0     1/1     Running   0             7m32s
web-1     1/1     Running   0             7m45s
web-2     1/1     Running   0             13m
web-3     1/1     Running   0             13m
web-4     1/1     Running   0             14m
[root@k8s-master ~]# kubectl delete sts web
statefulset.apps "web" deleted
[root@k8s-master ~]# kubectl get po 
NAME      READY   STATUS        RESTARTS      AGE
busybox   1/1     Running       3 (24m ago)   3h24m
web-3     0/1     Terminating   0             14m
web-4     0/1     Terminating   0             14m
[root@k8s-master ~]# kubectl get po 
NAME      READY   STATUS    RESTARTS      AGE
busybox   1/1     Running   3 (24m ago)   3h24m
  1. 非级联删除
[root@k8s-master ~]# kubectl create -f nginx-sts.yaml 
service/nginx created
statefulset.apps/web created
[root@k8s-master ~]# kubectl get po
NAME      READY   STATUS    RESTARTS      AGE
busybox   1/1     Running   3 (27m ago)   3h27m
web-0     1/1     Running   0             13s
web-1     1/1     Running   0             12s

[root@k8s-master ~]# kubectl delete sts web --cascade=false
warning: --cascade=false is deprecated (boolean value) and can be replaced with --cascade=orphan.
statefulset.apps "web" deleted

[root@k8s-master ~]# kubectl get sts
No resources found in default namespace.
[root@k8s-master ~]# kubectl get po
NAME      READY   STATUS    RESTARTS      AGE
busybox   1/1     Running   3 (29m ago)   3h29m
web-0     1/1     Running   0             2m17s
web-1     1/1     Running   0             2m16s
  • 查看pod,可以看到pod依然存在,只是没有sts管理了,再次删除pod不会被重新创建
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值