StatefulSet

    • 稳定的持久化存储,即 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 格式为 ,其中

    • serviceName 为 Headless Service 的名字
    • 0..N-1 为 Pod 所在的序号,从 0 开始到 N-1
    • statefulSetName 为 StatefulSet 的名字
    • namespace 为服务所在的 namespace,Headless Service 和 StatefulSet 必须在相同的 namespace
    • .cluster.local 为 Cluster Domain

    简单示例

    1. $ kubectl create -f web.yaml
    2. service "nginx" created
    3. statefulset "web" created
    4. # 查看创建的 headless service 和 statefulset
    5. $ kubectl get service nginx
    6. NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    7. nginx None <none> 80/TCP 1m
    8. $ kubectl get statefulset web
    9. NAME DESIRED CURRENT AGE
    10. web 2 2 2m
    11. # 根据 volumeClaimTemplates 自动创建 PVC(在 GCE 中会自动创建 kubernetes.io/gce-pd 类型的 volume)
    12. $ kubectl get pvc
    13. www-web-0 Bound pvc-d064a004-d8d4-11e6-b521-42010a800002 1Gi RWO 16s
    14. www-web-1 Bound pvc-d06a3946-d8d4-11e6-b521-42010a800002 1Gi RWO 16s
    15. # 查看创建的 Pod,他们都是有序的
    16. $ kubectl get pods -l app=nginx
    17. NAME READY STATUS RESTARTS AGE
    18. web-0 1/1 Running 0 5m
    19. web-1 1/1 Running 0 4m
    20. # 使用 nslookup 查看这些 Pod 的 DNS
    21. $ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
    22. / # nslookup web-0.nginx
    23. Server: 10.0.0.10
    24. Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
    25. Name: web-0.nginx
    26. Address 1: 10.244.2.10
    27. / # nslookup web-1.nginx
    28. Server: 10.0.0.10
    29. Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
    30. Name: web-1.nginx
    31. Address 1: 10.244.3.12
    32. / # nslookup web-0.nginx.default.svc.cluster.local
    33. Server: 10.0.0.10
    34. Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
    35. Name: web-0.nginx.default.svc.cluster.local
    36. Address 1: 10.244.2.10

    还可以进行其他的操作

    v1.7 + 支持 StatefulSet 的自动更新,通过 spec.updateStrategy 设置更新策略。目前支持两种策略

    • OnDelete:当 .spec.template 更新时,并不立即删除旧的 Pod,而是等待用户手动删除这些旧 Pod 后自动创建新 Pod。这是默认的更新策略,兼容 v1.6 版本的行为
    • RollingUpdate:当 .spec.template 更新时,自动删除旧的 Pod 并创建新 Pod 替换。在更新时,这些 Pod 是按逆序的方式进行,依次删除、创建并等待 Pod 变成 Ready 状态才进行下一个 Pod 的更新。
    1. # 设置 partition 为 3
    2. $ kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
    3. statefulset "web" patched
    4. # 更新 StatefulSet
    5. $ kubectl patch statefulset web --type='json' -p='[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"gcr.io/google_containers/nginx-slim:0.7"}]'
    6. statefulset "web" patched
    7. # 验证更新
    8. $ kubectl delete po web-2
    9. pod "web-2" deleted
    10. $ kubectl get po -lapp=nginx -w
    11. NAME READY STATUS RESTARTS AGE
    12. web-0 1/1 Running 0 4m
    13. web-1 1/1 Running 0 4m
    14. web-2 0/1 ContainerCreating 0 11s
    15. web-2 1/1 Running 0 18s

    Pod 管理策略

    v1.7 + 可以通过 .spec.podManagementPolicy 设置 Pod 管理策略,支持两种方式

    • OrderedReady:默认的策略,按照 Pod 的次序依次创建每个 Pod 并等待 Ready 之后才创建后面的 Pod
    • Parallel:并行创建或删除 Pod(不等待前面的 Pod Ready 就开始创建所有的 Pod)

    Parallel 示例

    可以看到,所有 Pod 是并行创建的

    1. $ kubectl create -f webp.yaml
    2. service "nginx" created
    3. statefulset "web" created
    4. $ kubectl get po -lapp=nginx -w
    5. NAME READY STATUS RESTARTS AGE
    6. web-0 0/1 Pending 0 0s
    7. web-0 0/1 Pending 0 0s
    8. web-1 0/1 Pending 0 0s
    9. web-1 0/1 Pending 0 0s
    10. web-0 0/1 ContainerCreating 0 0s
    11. web-1 0/1 ContainerCreating 0 0s
    12. web-0 1/1 Running 0 10s
    13. web-1 1/1 Running 0 10s

    详细的使用说明见 。

    StatefulSet 注意事项

    1. 推荐在 Kubernetes v1.9 或以后的版本中使用
    2. 所有 Pod 的 Volume 必须使用 PersistentVolume 或者是管理员事先创建好
    3. 为了保证数据安全,删除 StatefulSet 时不会删除 Volume
    4. StatefulSet 需要一个 Headless Service 来定义 DNS domain,需要在 StatefulSet 之前创建好