StatfulSet具备一下几个特点:

    1、稳定且唯一的网络标识符

    2、稳定且持久的存储

    3、有序平滑的部署和扩展

    4、有序平滑地删除

    5、有序的滚动更新

StatfulSet控制器三个组件:headless service,StatfulSet、volumeClaimTemplate

        有状态应用需要存储的数据是不同的,如redis集群中各个节点的存储不能共享同一个持久存储。每个节点都要有自己专用的存储卷。volumeClaimTemplate 会为每一个Pod创建pvc并各自绑定pv。

16291933771573_upload.png

StatfulSet必选字段:

    replicas       <integer>

    selector       <Object> -required-

    serviceName<string> -required-

    template       <Object> -required-

    volumeClaimTemplates<[]Object>

headless service 文件:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: myapp
  name: myapp
spec:
  clusterIP: None
  ports:
  - name: redis
    port: 6379
  selector:
    app: myapp-redis
  type: ClusterIP

StatfulSet 文件:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: myapp-redis
  replicas: 2
  selector:
    matchLabels:
      app: myapp-redis
  template:
    metadata:
      labels:
        app: myapp-redis
    spec:
      containers:
      - name: redis
        image: redis:4.0
        ports:
        - name: http
          containerPort: 6379
        volumeMounts:
        - name: redis-data
          mountPath: /data
  volumeClaimTemplates: # pvc模板,自动创建pvc
  - metadata:
      name: redis-data
    spec:
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi

使用到的PV:

        可以简单的使用hostPath方式来创建PV,如果想用StorageClass 来动态创建PV则要在statefulset 中定义 volumeClaimTemplates.spec.storageClassName 字段即可,下面的PV就不用创建了。

  volumeClaimTemplates:
  - metadata:
      name: redis-data
    spec:
      accessModes:
      - ReadWriteMany
      storageClassName: "gluster-dynamic"
      resources:
        requests:
          storage: 1Gi

hostPath方式:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
spec:
  persistentVolumeReclaimPolicy: Recycle
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 1Gi
  hostPath:
    path: /data/data1
    type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
spec:
  persistentVolumeReclaimPolicy: Recycle
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 1Gi
  hostPath:
    path: /data/data2
    type: DirectoryOrCreate


创建和删除的特点:

        删除和创建statefulset都是按照顺序来的,创建是正序创建,删除是倒序删除。删除后重新创建还会绑定到原来的pv上。使用describe查看Pod中的ClaimName 删除后再创建始终会绑定到同一个ClaimName;Pod的名称且可以被解析。

在pvc的名称中包含Pod的名称:

kubectl get pvc
NAME                 STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
redis-data-redis-0   Bound    pv001    1Gi        RWX                           52m
redis-data-redis-1   Bound    pv002    1Gi        RWX                           52m


对statefulset扩容:

kubectl scale --replicas=3 statefulset redis


更新镜像:

        StatefulSet中可以定义partition的值来自定义更新sts.spec.updateStrategy.rollingUpdate.partition,在statefulset中Pod的后缀是有序数字,partition值是用来定义更新范围的,规则为 partition>= N 的将被更新。如 partition=3 那么 redis-3、redis-4 ... 之后的所有Pod的都会被更新。

并行更新:

        如果想并行更新Pod可以设置 spec.podManagermentPolicy 来实现。

spec:
  podManagermentPolicy: OrderedReady # Parallel无顺序停启, OrderedReady 按顺序停启

注意:

        更新镜像要注意应用之间的不同版本数据可能不兼容而导致更新后出现 Error 或 CrashLoopBackOff,如redis在更新版本的时候4.0和5.0之间数据是不兼容的,直接更新镜像是不行的。


更新步骤:

修改partition的值:

kubectl patch sts redis --patch='{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'

或:

kubectl edit statefulsets.apps redis

更新:

kubectl set image statefulset redis redis=redis:4.0.14 --record

再次修改partition的值:将其值改为0,这样其他的Pod就会更新到刚刚set image设置的版本了。

kubectl patch sts redis --patch='{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}'

设置partition的更新过程类似于金丝雀发布的效果,先更新一个Pod到最新版本,如果不行就回滚到旧版本。

kubectl set image sts redis redis=redis:4.0.14 --record


DNS解析后端服务:

        通过service name解析到的是后端所有的Pod IP,通过Pod_name.service_name 可以解析到Pod IP。

]# kubectl exec -it test-pod -- sh
# 解析service
/ # nslookup nginx-sts-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-sts-svc
Address 1: 10.244.2.106 nginx-sts-1.nginx-sts-svc.default.svc.cluster.local
Address 2: 10.244.1.181 nginx-sts-0.nginx-sts-svc.default.svc.cluster.local

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

Name:      nginx-sts-0.nginx-sts-svc
Address 1: 10.244.1.181 nginx-sts-0.nginx-sts-svc.default.svc.cluster.local

        删除某个Pod后StatefulSet会重建该Pod,并且Pod name不会发生变化,但是Pod IP是会变的,通过解析Pod name可以观察到。客户端直接使用 Pod_name.service_name 进行请求。

        删除Pod后并不会删除存储,除非用户手动删除,且重建的Pod依然会被关联到以前的那个PVC上。

        同其他控制器一样删除StatefulSet默认也是级联删除,即:删除控制器连同该控制器之下的Pod一起删除,如果不使用级联可以设置--cascade=false 参数来设置。