StatefulSet:

 RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群,Redis等。

StatefulSet应用场景:
  • 稳定且唯一的网络标识符。
  • 稳定且持久的存储。
  • 有序,平滑地部署和扩展。
  • 有序,平滑地终止和删除。
  • 有序的滚动更新。
StatefulSet组成:
  • Headless Service:名为nginx,用来定义Pod网络标识。
  • StatefulSet:定义具体应用,名为nginx,有三个Pod副本,并为每个Pod定义了一个域名。
  • volumeClaim Templates:存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应。

#创建PV
[root@k8smaster data]# vim pv-demo.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
spec:
  nfs:
    path: /data/nfs/volumes/v1
    server: k8snfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
    path: /data/nfs/volumes/v2
    server: k8snfs
  accessModes: ["ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
    path: /data/nfs/volumes/v3
    server: k8snfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels:
    name: pv004
spec:
  nfs:
    path: /data/nfs/volumes/v4
    server: k8snfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
    path: /data/nfs/volumes/v5
    server: k8snfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi

[root@k8smaster data]# kubectl apply -f pv-demo.yaml 
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
[root@k8smaster data]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv001   5Gi        RWO,RWX        Retain           Available                                   8s
pv002   5Gi        RWO            Retain           Available                                   8s
pv003   5Gi        RWO,RWX        Retain           Available                                   8s
pv004   1Gi        RWO,RWX        Retain           Available                                   8s
pv005   1Gi        RWO,RWX        Retain           Available                                   8s

#定义Statefulset
[root@k8smaster data]# vim statfulset-demo.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  labels:
    app: myapp-svc
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: myapp-pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myapp
spec:
  serviceName: myapp-svc
  replicas: 3
  selector:
    matchLabels:
      app: myapp-pod
  template:
    metadata:
      labels:
        app: myapp-pod
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: myappdata
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: myappdata
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
启停策略:
  • 有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
  • 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。
  • 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。

[root@k8smaster data]# kubectl apply -f statfulset-demo.yaml 
service/myapp-svc created
statefulset.apps/myapp created
[root@k8smaster data]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   53d
myapp        ClusterIP   None         <none>        80/TCP    10m
[root@k8smaster data]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                       STORAGECLASS   REASON   AGE
pv001   1Gi        RWO,RWX        Retain           Available                                                       16s
pv002   1Gi        RWO            Retain           Bound       default/myappdata-myapp-0                           16s
pv003   1Gi        RWO,RWX        Retain           Available                                                       16s
pv004   1Gi        RWO,RWX        Retain           Bound       default/myappdata-myapp-1                           16s
pv005   1Gi        RWO,RWX        Retain           Bound       default/myappdata-myapp-2                           16s
[root@k8smaster data]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
myapp-0   1/1     Running   0          5m23s
myapp-1   1/1     Running   0          5m20s
myapp-2   1/1     Running   0          5m16s
[root@k8smaster data]# kubectl get pvc
NAME                STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myappdata-myapp-0   Bound    pv002    1Gi        RWO                           5m28s
myappdata-myapp-1   Bound    pv004    1Gi        RWO,RWX                       5m25s
myappdata-myapp-2   Bound    pv005    1Gi        RWO,RWX                       5m21s
[root@k8smaster data]# kubectl get sts
NAME    READY   AGE
myapp   3/3     6m27s

#修改副本数为5个。
[root@k8smaster data]# kubectl scale sts myapp --replicas=5
statefulset.apps/myapp scaled
[root@k8smaster data]# kubectl get sts
NAME    READY   AGE
myapp   5/5     19m

#修改更新策略:对partition为4及以上的pod进行滚动更新。
[root@k8smaster data]# kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":4}}}}'
statefulset.apps/myapp patched
[root@k8smaster data]# kubectl set image sts/myapp myapp=ikubernetes/myapp:v2
statefulset.apps/myapp image updated
[root@k8smaster data]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
myapp-0   1/1     Running   0          44m   10.244.1.130   k8snode1   <none>           <none>
myapp-1   1/1     Running   0          44m   10.244.2.118   k8snode2   <none>           <none>
myapp-2   1/1     Running   0          44m   10.244.1.131   k8snode1   <none>           <none>
myapp-3   1/1     Running   0          25m   10.244.2.119   k8snode2   <none>           <none>
myapp-4   1/1     Running   0          12s   10.244.2.121   k8snode2   <none>           <none>

#myapp-4的image已经发生改变了。
[root@k8smaster data]# kubectl get pod myapp-4 -o yaml    
... ...
  - containerID: docker://d6c48772d6bce56b9a81c9aebae921626949ff8d83f9610acd90f7b37ab4b275
image: ikubernetes/myapp:v2
... ...
#myapp-3的image并没有更新。
[root@k8smaster data]# kubectl get pod myapp-3 -o yaml
... ...
  - containerID: docker://c78bc6eb8dccde06f07622bb265f6a2815ebae2e3a936f7893062a1c110e07a3
image: ikubernetes/myapp:v1
... ...

#打开一个终端进行监控。
[root@k8smaster ~]# kubectl get pod -w
NAME      READY   STATUS    RESTARTS   AGE
myapp-0   1/1     Running   0          52m
myapp-1   1/1     Running   0          52m
myapp-2   1/1     Running   0          52m
myapp-3   1/1     Running   0          34m
myapp-4   1/1     Running   0          8m42s

#修改更新策略:对partition为0及以上的pod进行滚动更新。
[root@k8smaster data]# kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
statefulset.apps/myapp patched

#我们发现myapp-0~3的pod也都进行了滚动更新。
[root@k8smaster ~]# kubectl get pod -w
NAME      READY   STATUS    RESTARTS   AGE
myapp-0   1/1     Running   0          52m
myapp-1   1/1     Running   0          52m
myapp-2   1/1     Running   0          52m
myapp-3   1/1     Running   0          34m
myapp-4   1/1     Running   0          8m42s
myapp-3   1/1     Terminating   0          34m
myapp-3   0/1     Terminating   0          34m
myapp-3   0/1     Terminating   0          34m
myapp-3   0/1     Terminating   0          34m
myapp-3   0/1     Pending       0          0s
myapp-3   0/1     Pending       0          0s
myapp-3   0/1     ContainerCreating   0          0s
myapp-3   1/1     Running             0          3s
myapp-2   1/1     Terminating         0          53m
myapp-2   0/1     Terminating         0          53m
myapp-2   0/1     Terminating         0          53m
myapp-2   0/1     Terminating         0          53m
myapp-2   0/1     Pending             0          0s
myapp-2   0/1     Pending             0          0s
myapp-2   0/1     ContainerCreating   0          0s
myapp-2   1/1     Running             0          1s
myapp-1   1/1     Terminating         0          53m
myapp-1   0/1     Terminating         0          53m
myapp-1   0/1     Terminating         0          53m
myapp-1   0/1     Terminating         0          53m
myapp-1   0/1     Pending             0          0s
myapp-1   0/1     Pending             0          0s
myapp-1   0/1     ContainerCreating   0          0s
myapp-1   1/1     Running             0          1s
myapp-0   1/1     Terminating         0          53m
myapp-0   0/1     Terminating         0          53m
myapp-0   0/1     Terminating         0          53m
myapp-0   0/1     Terminating         0          53m
myapp-0   0/1     Pending             0          0s
myapp-0   0/1     Pending             0          0s
myapp-0   0/1     ContainerCreating   0          0s
myapp-0   1/1     Running             0          1s
更新策略:
  • OnDelete:通过.spec.updateStrategy.type 字段设置为OnDelete,StatefulSet控制器不会自动更新StatefulSet中的Pod。用户必须手动删除Pod,以使控制器创建新的Pod。
  • RollingUpdate:通过.spec.updateStrategy.type 字段设置为RollingUpdate,实现了Pod的自动滚动更新,如果.spec.updateStrategy未指定,则此为默认策略。
    StatefulSet控制器将删除并重新创建StatefulSet中的每个Pod。它将以Pod终止(从最大序数到最小序数)的顺序进行,一次更新每个Pod。在更新下一个Pod之前,必须等待这个Pod Running and Ready。
  • Partitions:通过指定 .spec.updateStrategy.rollingUpdate.partition 来对 RollingUpdate 更新策略进行分区,如果指定了分区,则当 StatefulSet 的 .spec.template 更新时,具有大于或等于分区序数的所有 Pod 将被更新。
    具有小于分区的序数的所有 Pod 将不会被更新,即使删除它们也将被重新创建。如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大于其 .spec.replicas,则其 .spec.template 的更新将不会传播到 Pod。在大多数情况下,不需要使用分区。
参考文档:https://blog.51cto.com/newfly/2140004
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐