Kubernetes StatefulSet 笔记

StatefulSet#

StatefulSet 用来管理有状态应用的工作负载 API 对象。

和 Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

使用 StatefulSet#

StatefulSet 对于需要满足以下一个或多个需求的应用程序很有价值:

  • 稳定的、唯一的网络标识符。
  • 稳定的、持久的存储。
  • 有序的、优雅的部署和扩缩。
  • 有序的、自动的滚动更新

限制#

  • 给定 Pod 的存储必须由 PersistentVolume Provisioner 基于所请求的 storage class 来制备,或者由管理员预先制备。
  • 删除或者扩缩 StatefulSet 并不会删除它关联的存储卷。 这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。
  • StatefulSet 当前需要无头服务来负责 Pod 的网络标识。你需要负责创建此服务。
  • 当删除一个 StatefulSet 时,该 StatefulSet 不提供任何终止 Pod 的保证。 为了实现 StatefulSet 中的 Pod 可以有序且体面地终止,可以在删除之前将 StatefulSet 缩容到 0。
  • 在默认 Pod 管理策略(OrderedReady) 时使用滚动更新, 可能进入需要人工干预才能修复的损坏状态。

nginx-sts.yaml#

[root@master01 stateful-set]# vim nginx-sts.yaml
[root@master01 stateful-set]# cat 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:
  selector:
    matchLabels:
      app: nginx # 必须匹配 .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # 默认值是 1
  minReadySeconds: 10 # 默认值是 0
  template:
    metadata:
      labels:
        app: nginx # 必须匹配 .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx:1.15.2
        ports:
        - containerPort: 80
          name: web
  • 名为 nginx 的 Headless Service 用来控制网络域名
  • 名为 web 的 StatefulSet 有一个 Spec,它表明将在独立的 3 个 Pod 副本中启动 nginx 容器。
  • volumeClaimTemplates 将通过 PersistentVolume 制备程序所准备的 PersistentVolumes 来提供稳定的存储

创建#

[root@master01 stateful-set]# kubectl create  -f nginx-sts.yaml 
service/nginx created
statefulset.apps/web created

查看状态#

[root@master01 stateful-set]# kubectl get po
NAME    READY   STATUS              RESTARTS   AGE
nginx   1/1     Running             2          3d20h
web-0   1/1     Running             0          5s
web-1   0/1     ContainerCreating   0          1s
[root@master01 stateful-set]# kubectl get svc 
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   8d
nginx        ClusterIP   None         <none>        80/TCP    13s
[root@master01 stateful-set]# kubectl get po
NAME    READY   STATUS              RESTARTS   AGE
nginx   1/1     Running             2          3d20h
web-0   1/1     Running             0          17s
web-1   1/1     Running             0          13s
web-2   0/1     ContainerCreating   0          9s

扩容#

[root@master01 stateful-set]# kubectl scale --replicas=5 sts web 
statefulset.apps/web scaled
[root@master01 stateful-set]# kubectl get po
NAME    READY   STATUS              RESTARTS   AGE
nginx   1/1     Running             2          3d20h
web-0   1/1     Running             0          95s
web-1   1/1     Running             0          91s
web-2   1/1     Running             0          87s
web-3   0/1     ContainerCreating   0          3s

Pod 选择算符#

必须设置 StatefulSet 的 .spec.selector 字段,使之匹配其在 .spec.template.metadata.labels 中设置的标签。 未指定匹配的 Pod 选择算符将在创建 StatefulSet 期间导致验证错误。

VolumeClaimTemplates#

可以设置 .spec.volumeClaimTemplates, 它可以使用 PersistentVolume 制备程序所准备的 PersistentVolumes 来提供稳定的存储

最短就绪秒数#

特性状态: Kubernetes v1.25 [stable]

.spec.minReadySeconds 是一个可选字段。 它指定新创建的 Pod 应该在没有任何容器崩溃的情况下运行并准备就绪,才能被认为是可用的。 这用于在使用滚动更新策略时检查滚动的进度。 该字段默认为 0(Pod 准备就绪后将被视为可用)

Pod 标识#

StatefulSet Pod 具有唯一的标识,该标识包括顺序标识、稳定的网络标识和稳定的存储。 该标识和 Pod 是绑定的,与该 Pod 调度到哪个节点上无关。

有序索引#

对于具有 N 个副本的 StatefulSet,该 StatefulSet 中的每个 Pod 将被分配一个从 0 到 N-1 的整数序号,该序号在此 StatefulSet 上是唯一的。

稳定的网络 ID#

StatefulSet 中的每个 Pod 根据 StatefulSet 的名称和 Pod 的序号派生出它的主机名。 组合主机名的格式为$(StatefulSet 名称)-$(序号)。 上例将会创建三个名称分别为 web-0、web-1、web-2 的 Pod

StatefulSet 可以使用 Headless Service 控制它的 Pod 的网络域。管理域的这个服务的格式为: $(服务名称).$(名字空间).svc.cluster.local,其中 cluster.local 是集群域。

一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为: $(pod 名称).$(所属服务的 DNS 域名),其中所属服务由 StatefulSet 的 serviceName 域来设定。

测试
  1. 启动busybox
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
  1. 查询
[root@master01 stateful-set]# kubectl exec -it busybox -- sh 
/ # nslookup web-0.nginx
Server:		10.96.0.10
Address:	10.96.0.10:53

** server can't find web-0.nginx: NXDOMAIN

取决于集群域内部 DNS 的配置,有可能无法查询一个刚刚启动的 Pod 的 DNS 命名。 当集群内其他客户端在 Pod 创建完成前发出 Pod 主机名查询时,就会发生这种情况。 负缓存 (在 DNS 中较为常见) 意味着之前失败的查询结果会被记录和重用至少若干秒钟, 即使 Pod 已经正常运行了也是如此。
如果需要在 Pod 被创建之后及时发现它们,可使用以下选项:

直接查询 Kubernetes API(比如,利用 watch 机制)而不是依赖于 DNS 查询
缩短 Kubernetes DNS 驱动的缓存时长(通常这意味着修改 CoreDNS 的 ConfigMap,目前缓存时长为 30 秒)

[root@master01 ~]# kubectl get po -owide
NAME      READY   STATUS    RESTARTS   AGE     IP               NODE       NOMINATED NODE   READINESS GATES
busybox   1/1     Running   0          96s     172.18.71.23     master03   <none>           <none>
nginx     1/1     Running   3          3d22h   172.31.112.150   master01   <none>           <none>
web-0     1/1     Running   1          65m     172.21.231.149   node02     <none>           <none>
web-1     1/1     Running   1          64m     172.20.59.210    master02   <none>           <none>
web-2     1/1     Running   1          64m     172.31.112.152   master01   <none>           <none>


[root@master01 ~]# kubectl exec  busybox -n default -- 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: 172.21.231.149 web-0.nginx.default.svc.cluster.local

稳定的存储#

对于 StatefulSet 中定义的每个 VolumeClaimTemplate,每个 Pod 接收到一个 PersistentVolumeClaim

Pod 名称标签#

当 StatefulSet 控制器创建 Pod 时, 它会添加一个标签 statefulset.kubernetes.io/pod-name,该标签值设置为 Pod 名称。 这个标签允许你给 StatefulSet 中的特定 Pod 绑定一个 Service。

部署和扩缩保证#

  • 对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为 0..N-1
  • 当删除 Pod 时,它们是逆序终止的,顺序为 N-1..0。
  • 在将扩缩操作应用到 Pod 之前,它前面的所有 Pod 必须是 Running 和 Ready 状态。
  • 在一个 Pod 终止之前,所有的继任者必须完全关闭。

Pod 管理策略#

StatefulSet 允许你放宽其排序保证, 同时通过它的 .spec.podManagementPolicy 域保持其唯一性和身份保证。

OrderedReady Pod 管理

OrderedReady Pod 管理是 StatefulSet 的默认设置。 它实现了上面描述的功能

并行 Pod 管理

Parallel Pod 管理让 StatefulSet 控制器并行的启动或终止所有的 Pod, 启动或者终止其他 Pod 前,无需等待 Pod 进入 Running 和 Ready 或者完全停止状态。 这个选项只会影响扩缩操作的行为,更新则不会被影响。

更新策略#

StatefulSet 的 .spec.updateStrategy 字段让你可以配置和禁用掉自动滚动更新 Pod 的容器、标签、资源请求或限制、以及注解。有两个允许的值:

OnDelete#

当 StatefulSet 的 .spec.updateStrategy.type 设置为 OnDelete 时, 它的控制器将不会自动更新 StatefulSet 中的 Pod。 用户必须手动删除 Pod 以便让控制器创建新的 Pod,以此来对 StatefulSet 的 .spec.template 的变动作出反应。

RollingUpdate#

RollingUpdate 更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。这是默认的更新策略

滚动更新#

当 StatefulSet 的 .spec.updateStrategy.type 被设置为 RollingUpdate 时, StatefulSet 控制器会删除和重建 StatefulSet 中的每个 Pod。 它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。

Kubernetes 会等到被更新的 Pod 进入 Running 和 Ready 状态,然后再更新其前身。 如果你设置了 .spec.minReadySeconds(查看最短就绪秒数), 控制平面在 Pod 就绪后会额外等待一定的时间再执行下一步

分区滚动更新#

通过声明 .spec.updateStrategy.rollingUpdate.partition 的方式,RollingUpdate 更新策略可以实现分区。

如果声明了一个分区,当 StatefulSet 的 .spec.template 被更新时, 所有序号大于等于该分区序号的 Pod 都会被更新。 所有序号小于该分区序号的 Pod 都不会被更新,并且,即使它们被删除也会依据之前的版本进行重建。

如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大于它的 .spec.replicas,则对它的 .spec.template 的更新将不会传递到它的 Pod。

在大多数情况下,你不需要使用分区,但如果你希望进行阶段更新、执行金丝雀或执行分阶段上线,则这些分区会非常有用。

强制回滚#

在默认 Pod 管理策略(OrderedReady) 下使用滚动更新, 可能进入需要人工干预才能修复的损坏状态。

如果更新后 Pod 模板配置进入无法运行或就绪的状态(例如, 由于错误的二进制文件或应用程序级配置错误),StatefulSet 将停止回滚并等待。

在这种状态下,仅将 Pod 模板还原为正确的配置是不够的。 由于已知问题,StatefulSet 将继续等待损坏状态的 Pod 准备就绪(永远不会发生),然后再尝试将其恢复为正常工作配置。

恢复模板后,还必须删除 StatefulSet 尝试使用错误的配置来运行的 Pod。这样, StatefulSet 才会开始使用被还原的模板来重新创建 Pod。

删除#

级联删除#

删除 sts 同时删除 pod

默认为级联删除

[root@master01 stateful-set]# kubectl get po
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          6m45s
nginx     1/1     Running   3          3d22h
web-0     1/1     Running   1          70m
web-1     1/1     Running   1          70m
web-2     1/1     Running   1          70m
[root@master01 stateful-set]# kubectl get svc 
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   8d
nginx        ClusterIP   None         <none>        80/TCP    70m
[root@master01 stateful-set]# kubectl get sts 
NAME   READY   AGE
web    3/3     70m
[root@master01 stateful-set]# kubectl delete sts web 
statefulset.apps "web" deleted
[root@master01 stateful-set]# kubectl get po 
NAME      READY   STATUS        RESTARTS   AGE
busybox   1/1     Running       0          7m12s
nginx     1/1     Running       3          3d22h
web-1     0/1     Terminating   1          70m
web-2     0/1     Terminating   1          70m
[root@master01 stateful-set]# kubectl get po 
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          7m24s
nginx     1/1     Running   3          3d22h

非级联删除#

删除 sts 不同时删除 pod

[root@master01 stateful-set]# kubectl get po
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          8m32s
nginx     1/1     Running   3          3d22h
web-0     1/1     Running   0          14s
web-1     1/1     Running   0          11s
web-2     1/1     Running   0          7s
[root@master01 stateful-set]# kubectl get sts 
NAME   READY   AGE
web    3/3     26s
[root@master01 stateful-set]# 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@master01 stateful-set]# kubectl get po 
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          9m25s
nginx     1/1     Running   3          3d22h
web-0     1/1     Running   0          67s
web-1     1/1     Running   0          64s
web-2     1/1     Running   0          60s
[root@master01 stateful-set]# kubectl get sts 
No resources found in default namespace.
posted @   平凡键客  阅读(193)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示
主题色彩