StatefulSet
StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
- 有序收缩,有序删除(即从N-1到0)
从上面的应用场景可以发现,StatefulSet由以下几个部分组成:
- 用于定义网络标志(DNS domain)的Headless Service
- 用于创建PersistentVolumes的volumeClaimTemplates
- 定义具体应用的StatefulSet
StatefulSet中每个Pod的DNS格式为statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local
,其中
serviceName
为Headless Service的名字0..N-1
为Pod所在的序号,从0开始到N-1statefulSetName
为StatefulSet的名字namespace
为服务所在的namespace,Headless Servic和StatefulSet必须在相同的namespace.cluster.local
为Cluster Domain,
简单示例
以一个简单的 nginx 服务 web.yaml 为例:
[root@kube pv-pvc]# cat pv_statefulset.yaml
//PV 需要事先创建
//persistentVolumeReclaimPolicy: Recycle storageClassName: slow 这两个字段不定义,否则 volumeClaimTemplates: 无法动态生成pvc
apiVersion: v1 kind: PersistentVolume metadata: name: pv0001 spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteOnce nfs: path: /nfs/data/v1 server: 10.2.61.21 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv0002 spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteOnce nfs: path: /nfs/data/v2 server: 10.2.61.21 [root@kube pv-pvc]#
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: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 2Gi
[root@kube pv-pvc]# kubectl get pv //查看 pv ,pvc ,sts NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv0001 5Gi RWO Retain Bound default/www-web-0 5m3s pv0002 5Gi RWO Retain Bound default/www-web-1 5m3s [root@kube pv-pvc]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pv0001 5Gi RWO 4m41s www-web-1 Bound pv0002 5Gi RWO 4m19s [root@kube pv-pvc]# kubectl get pods //查看 pod 都是 有序的 NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 4m46s web-1 1/1 Running 0 4m24s [root@kube pv-pvc]# kubectl get sts NAME READY AGE web 2/2 4m53s [root@kube pv-pvc]#
[root@kube pv-pvc]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1443/TCP 10m nginx ClusterIP None 80/ TCP 6m9s // Headless service [root@kube pv-pvc]#
还可以进行其他的操作:
//扩容
[root@kube pv-pvc]# kubectl scale statefulset web --replicas=5 statefulset.apps/web scaled [root@kube pv-pvc]# kubectl get pods NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 16m web-1 1/1 Running 0 15m web-2 1/1 Running 0 7m19s web-3 1/1 Running 0 2m5s web-4 1/1 Running 0 103s //缩减
[root@kube pv-pvc]# kubectl patch statefulset web -p '{"spec":{"replicas":3}}' statefulset.apps/web patched [root@kube pv-pvc]# kubectl get pods
[root@kube pv-pvc]# kubectl get pvc //statefulset 缩减后 pvc 仍然保留 NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pv0001 5Gi RWO 19m www-web-1 Bound pv0002 5Gi RWO 19m www-web-2 Bound pv0003 5Gi RWO 11m www-web-3 Bound pv0005 5Gi RWO 5m52s www-web-4 Bound pv0004 5Gi RWO 5m30s
更新 StatefulSet
v1.7 + 支持 StatefulSet 的自动更新,通过 spec.updateStrategy
设置更新策略。目前支持两种策略
- OnDelete:当
.spec.template
更新时,并不立即删除旧的 Pod,而是等待用户手动删除这些旧 Pod 后自动创建新 Pod。这是默认的更新策略,兼容 v1.6 版本的行为 - RollingUpdate:当
.spec.template
更新时,自动删除旧的 Pod 并创建新 Pod 替换。在更新时,这些 Pod 是按逆序的方式进行,依次删除、创建并等待 Pod 变成 Ready 状态才进行下一个 Pod 的更新。
Partitions
RollingUpdate 还支持 Partitions,通过 .spec.updateStrategy.rollingUpdate.partition
来设置。当 partition 设置后,只有序号大于或等于 partition 的 Pod 会在 .spec.template
更新的时候滚动更新,而其余的 Pod 则保持不变(即便是删除后也是用以前的版本重新创建)。
Pod 管理策略
v1.7 + 可以通过 .spec.podManagementPolicy
设置 Pod 管理策略,支持两种方式
- OrderedReady:默认的策略,按照 Pod 的次序依次创建每个 Pod 并等待 Ready 之后才创建后面的 Pod
- Parallel:并行创建或删除 Pod(不等待前面的 Pod Ready 就开始创建所有的 Pod)
StatefulSet 注意事项
- 推荐在 Kubernetes v1.9 或以后的版本中使用
- 所有 Pod 的 Volume 必须使用 PersistentVolume 或者是管理员事先创建好
- 为了保证数据安全,删除 StatefulSet 时不会删除 Volume
- StatefulSet 需要一个 Headless Service 来定义 DNS domain,需要在 StatefulSet 之前创建好