Kubernetes StatefulSet有状态应用

网友投稿 297 2022-09-10

Kubernetes StatefulSet有状态应用

文章目录

​​0. 简介​​​​1. 创建 StatefulSet​​​​2. 扩容/缩容 StatefulSet​​

​​2.1 扩容​​​​2.2 缩容​​

​​3. 更新 StatefulSet​​

​​3.1 Rolling Update 策略​​​​3.2 分段更新​​​​3.3 灰度发布​​

​​4. 删除 StatefulSet​​

​​4.1 非级联删除​​​​4.2 级联删除​​

​​5. Pod 管理策略​​

​​5.1 Parallel Pod 管理策略​​

​​6. 示例​​

0. 简介

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

StatefulSet 用来管理 Deployment 和扩展一组 Pod,并且能为这些 Pod 提供序号和唯一性保证。

StatefulSet 和其他控制器使用相同的工作模式。你在 StatefulSet 对象 中定义你期望的状态,然后 StatefulSet 的 控制器 就会通过各种更新来达到那种你想要的状态。

使用 StatefulSets

1. 创建 StatefulSet

它创建了一个 ​​Headless Service nginx​​​ 用来发布 ​​StatefulSet web​​ 中的 Pod 的 IP 地址。

apiVersion: v1kind: Servicemetadata: name: nginx labels: app: nginxspec: ports: - port: 80 name: web clusterIP: None selector: app: nginx---apiVersion: apps/v1kind: StatefulSetmetadata: name: webspec: 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: mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi

你需要使用两个终端窗口。在第一个终端中,使用 kubectl get 来查看 StatefulSet 的 Pods 的创建情况。

kubectl get pods -w -l app=nginx

在另一个终端中,使用 kubectl apply来创建定义在 web.yaml 中的 Headless Service 和 StatefulSet。

$ kubectl apply -f web.yamlservice/nginx createdstatefulset.apps/web created$ kubectl get service nginxNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEnginx ClusterIP None 80/TCP 12s$ kubectl get statefulset webNAME DESIRED CURRENT AGEweb 2 1 20s$ kubectl get pods -w -l app=nginxNAME READY STATUS RESTARTS AGEweb-0 0/1 Pending 0 0sweb-0 0/1 Pending 0 0sweb-0 0/1 ContainerCreating 0 0sweb-0 1/1 Running 0 19sweb-1 0/1 Pending 0 0sweb-1 0/1 Pending 0 0sweb-1 0/1 ContainerCreating 0 0sweb-1 1/1 Running 0 18s

StatefulSet 中的 Pod 拥有一个具有黏性的、独一无二的身份标志。这个标志基于 StatefulSet 控制器分配给每个 Pod 的唯一顺序索引。Pod 的名称的形式为​​-​​。webStatefulSet 拥有两个副本,所以它创建了两个 Pod:web-0和web-1

$ for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; doneweb-0web-1$ kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm$ nslookup web-0.nginxServer: 10.0.0.10Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.localName: web-0.nginxAddress 1: 10.244.1.6$ nslookup web-1.nginxServer: 10.0.0.10Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.localName: web-1.nginxAddress 1: 10.244.2.6

headless service 的 CNAME 指向 SRV 记录(记录每个 Running 和 Ready 状态的 Pod)。SRV 记录指向一个包含 Pod IP 地址的记录表项。

kubectl get pod -w -l app=nginxkubectl delete pod -l app=nginxpod "web-0" deletedpod "web-1" deleted等待 StatefulSet 重启它们,并且两个 Pod 都变成 Running 和 Ready 状态。kubectl get pod -w -l app=nginxNAME READY STATUS RESTARTS AGEweb-0 0/1 ContainerCreating 0 0sNAME READY STATUS RESTARTS AGEweb-0 1/1 Running 0 2sweb-1 0/1 Pending 0 0sweb-1 0/1 Pending 0 0sweb-1 0/1 ContainerCreating 0 0sweb-1 1/1 Running 0 34s使用 kubectl exec 和 kubectl run 查看 Pod 的主机名和集群内部的 DNS 表项。for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; doneweb-0web-1kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/shnslookup web-0.nginxServer: 10.0.0.10Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.localName: web-0.nginxAddress 1: 10.244.1.7nslookup web-1.nginxServer: 10.0.0.10Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.localName: web-1.nginxAddress 1: 10.244.2.8

Pod 的序号、主机名、SRV 条目和记录名称没有改变,但和 Pod 相关联的 IP 地址可能发生了改变。在本教程中使用的集群中它们就改变了。这就是为什么不要在其他应用中使用 StatefulSet 中的 Pod 的 IP 地址进行连接,这点很重要。

如果你需要查找并连接一个 StatefulSet 的活动成员,你应该查询 ​​Headless Service​​​ 的 CNAME。和 CNAME 相关联的 SRV 记录只会包含 StatefulSet 中处于 ​​Running​​​ 和 ​​Ready​​ 状态的 Pod。

如果你的应用已经实现了用于测试 ​​liveness​​​ 和 ​​readiness​​​ 的连接逻辑,你可以使用 Pod 的 SRV 记录(​​web-0.nginx.default.svc.cluster.local​​​, ​​web-1.nginx.default.svc.cluster.local​​)。因为他们是稳定的,并且当你的 Pod 的状态变为 Running 和 Ready 时,你的应用就能够发现它们的地址。

2. 扩容/缩容 StatefulSet

2.1 扩容

$ kubectl scale sts web --replicas=5 #扩展副本数为 5$ kubectl get pods -w -l app=nginxNAME READY STATUS RESTARTS AGEweb-0 1/1 Running 0 2hweb-1 1/1 Running 0 2hNAME READY STATUS RESTARTS AGEweb-2 0/1 Pending 0 0sweb-2 0/1 Pending 0 0sweb-2 0/1 ContainerCreating 0 0sweb-2 1/1 Running 0 19sweb-3 0/1 Pending 0 0sweb-3 0/1 Pending 0 0sweb-3 0/1 ContainerCreating 0 0sweb-3 1/1 Running 0 18sweb-4 0/1 Pending 0 0sweb-4 0/1 Pending 0 0sweb-4 0/1 ContainerCreating 0 0sweb-4 1/1 Running 0 19s

2.2 缩容

$ kubectl patch sts web -p '{"spec":{"replicas":3}}'$ kubectl get pods -w -l app=nginxNAME READY STATUS RESTARTS AGEweb-0 1/1 Running 0 3hweb-1 1/1 Running 0 3hweb-2 1/1 Running 0 55sweb-3 1/1 Running 0 36sweb-4 0/1 ContainerCreating 0 18sNAME READY STATUS RESTARTS AGEweb-4 1/1 Running 0 19sweb-4 1/1 Terminating 0 24sweb-4 1/1 Terminating 0 24sweb-3 1/1 Terminating 0 42sweb-3 1/1 Terminating 0 42s

3. 更新 StatefulSet

更新策略由 StatefulSet API Object 的spec.updateStrategy 字段决定。这个特性能够用来更新一个 StatefulSet 中的 Pod 的 container images,resource requests,以及 limits,labels 和 annotations。RollingUpdate滚动更新是 StatefulSets 默认策略。

3.1 Rolling Update 策略

$ kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'statefulset.apps/web patched$ kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]'statefulset.apps/web patched$ kubectl get po -l app=nginx -wNAME READY STATUS RESTARTS AGEweb-0 1/1 Running 0 7mweb-1 1/1 Running 0 7mweb-2 1/1 Running 0 8mweb-2 1/1 Terminating 0 8mweb-2 1/1 Terminating 0 8mweb-2 0/1 Terminating 0 8mweb-2 0/1 Terminating 0 8mweb-2 0/1 Terminating 0 8mweb-2 0/1 Terminating 0 8mweb-2 0/1 Pending 0 0sweb-2 0/1 Pending 0 0sweb-2 0/1 ContainerCreating 0 0sweb-2 1/1 Running 0 19sweb-1 1/1 Terminating 0 8mweb-1 0/1 Terminating 0 8mweb-1 0/1 Terminating 0 8mweb-1 0/1 Terminating 0 8mweb-1 0/1 Pending 0 0sweb-1 0/1 Pending 0 0sweb-1 0/1 ContainerCreating 0 0sweb-1 1/1 Running 0 6sweb-0 1/1 Terminating 0 7mweb-0 1/1 Terminating 0 7mweb-0 0/1 Terminating 0 7mweb-0 0/1 Terminating 0 7mweb-0 0/1 Terminating 0 7mweb-0 0/1 Terminating 0 7mweb-0 0/1 Pending 0 0sweb-0 0/1 Pending 0 0sweb-0 0/1 ContainerCreating 0 0sweb-0 1/1 Running 0 10s

获取 Pod 来查看他们的容器镜像。

$ for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; donek8s.gcr.io/nginx-slim:0.8k8s.gcr.io/nginx-slim:0.8k8s.gcr.io/nginx-slim:0.8

​​kubectl rollout status sts/​​ 也可以查看 rolling update 的状态。

3.2 分段更新

你可以使用 RollingUpdate 更新策略的 partition 参数来分段更新一个 StatefulSet。分段的更新将会使 StatefulSet 中的其余所有 Pod 保持当前版本的同时仅允许改变 StatefulSet 的 .spec.template。

​​Patch web StatefulSet​​​ 来对 ​​updateStrategy​​ 字段添加一个分区。

$ kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'statefulset.apps/web patched

再次 Patch StatefulSet 来改变容器镜像。

$ kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'statefulset.apps/web patched

删除 StatefulSet 中的 Pod。

$ kubectl delete po web-2pod "web-2" deleted

3.3 灰度发布

通过 patch 命令修改 StatefulSet 来减少分区。

$ kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'statefulset.apps/web patched$ kubectl get po -lapp=nginx -w #等待 web-2 变成 Running 和 Ready。

4. 删除 StatefulSet

4.1 非级联删除

–cascade=false 参数给命令。这个参数告诉 Kubernetes 只删除 StatefulSet 而不要删除它的任何 Pod。

$ kubectl delete statefulset web --cascade=falsestatefulset.apps "web" deleted$ kubectl get pods -l app=nginxNAME READY STATUS RESTARTS AGEweb-0 1/1 Running 0 6mweb-1 1/1 Running 0 7mweb-2 1/1 Running 0 5m$ kubectl delete pod web-0pod "web-0" deleted$ kubectl get pods -l app=nginxNAME READY STATUS RESTARTS AGEweb-1 1/1 Running 0 10mweb-2 1/1 Running 0 7m$ kubectl apply -f web.yamlstatefulset.apps/web createdservice/nginx unchanged$ kubectl get pods -w -l app=nginxNAME READY STATUS RESTARTS AGEweb-1 1/1 Running 0 16mweb-2 1/1 Running 0 2mNAME READY STATUS RESTARTS AGEweb-0 0/1 Pending 0 0sweb-0 0/1 Pending 0 0sweb-0 0/1 ContainerCreating 0 0sweb-0 1/1 Running 0 18sweb-2 1/1 Terminating 0 3mweb-2 0/1 Terminating 0 3mweb-2 0/1 Terminating 0 3mweb-2 0/1 Terminating 0 3m

当重新创建 web StatefulSet 时,web-0被第一个重新启动。由于 web-1 已经处于 Running 和 Ready 状态,当 web-0 变成 Running 和 Ready 时,StatefulSet 会直接接收这个 Pod。由于你重新创建的 StatefulSet 的 replicas 等于 2,一旦 web-0 被重新创建并且 web-1 被认为已经处于 Running 和 Ready 状态时,web-2将会被终止。

4.2 级联删除

$ kubectl delete statefulset web$ kubectl get pods -w -l app=nginxNAME READY STATUS RESTARTS AGEweb-0 1/1 Running 0 11mweb-1 1/1 Running 0 27mNAME READY STATUS RESTARTS AGEweb-0 1/1 Terminating 0 12mweb-1 1/1 Terminating 0 29mweb-0 0/1 Terminating 0 12mweb-0 0/1 Terminating 0 12mweb-0 0/1 Terminating 0 12mweb-1 0/1 Terminating 0 29mweb-1 0/1 Terminating 0 29mweb-1 0/1 Terminating 0 29m

虽然级联删除会删除 StatefulSet 和它的 Pod,但它并不会删除和 StatefulSet 关联的 Headless Service。你必须手动删除nginx Service。

$ kubectl delete service nginxservice "nginx" deleted

5. Pod 管理策略

5.1 Parallel Pod 管理策略

Parallel pod 管理策略告诉 StatefulSet 控制器并行的终止所有 Pod,在启动或终止另一个 Pod 前,不必等待这些 Pod 变成 Running 和 Ready 或者完全终止状态.

apiVersion: v1kind: Servicemetadata: name: nginx labels: app: nginxspec: ports: - port: 80 name: web clusterIP: None selector: app: nginx---apiVersion: apps/v1kind: StatefulSetmetadata: name: webspec: serviceName: "nginx" podManagementPolicy: "Parallel" 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: mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi

执行:效果并行执行

kubectl get po -lapp=nginx -wkubectl apply -f web-parallel.yamlkubectl apply -f web-parallel.yamlkubectl delete sts webkubectl delete svc nginx

6. 示例

创建service

apiVersion: v1kind: Servicemetadata: labels: app: cassandra name: cassandraspec: clusterIP: None ports: - port: 9042 selector: app: cassandra

kubectl apply -f apps/v1kind: StatefulSetmetadata: name: cassandra labels: app: cassandraspec: serviceName: cassandra replicas: 3 selector: matchLabels: app: cassandra template: metadata: labels: app: cassandra spec: terminationGracePeriodSeconds: 1800 containers: - name: cassandra image: gcr.io/google-samples/cassandra:v13 imagePullPolicy: Always ports: - containerPort: 7000 name: intra-node - containerPort: 7001 name: tls-intra-node - containerPort: 7199 name: jmx - containerPort: 9042 name: cql resources: limits: cpu: "500m" memory: 1Gi requests: cpu: "500m" memory: 1Gi securityContext: capabilities: add: - IPC_LOCK lifecycle: preStop: exec: command: - /bin/sh - -c - nodetool drain env: - name: MAX_HEAP_SIZE value: 512M - name: HEAP_NEWSIZE value: 100M - name: CASSANDRA_SEEDS value: "cassandra-0.cassandra.default.svc.cluster.local" - name: CASSANDRA_CLUSTER_NAME value: "K8Demo" - name: CASSANDRA_DC value: "DC1-K8Demo" - name: CASSANDRA_RACK value: "Rack1-K8Demo" - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP readinessProbe: exec: command: - /bin/bash - -c - /ready-probe.sh initialDelaySeconds: 15 timeoutSeconds: 5 # These volume mounts are persistent. They are like inline claims, # but not exactly because the names need to match exactly one of # the stateful pod volumes. volumeMounts: - name: cassandra-data mountPath: /cassandra_data # These are converted to volume claims by the controller # and mounted at the paths mentioned above. # do not use these in production until ssd GCEPersistentDisk or other ssd pd volumeClaimTemplates: - metadata: name: cassandra-data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: fast resources: requests: storage: 1Gi---kind: StorageClassapiVersion: storage.k8s.io/v1metadata: name: fastprovisioner: k8s.io/minikube-hostpathparameters: type: pd-ssd

# 创建 statefulsetkubectl apply -f https://k8s.io/examples/application/cassandra/cassandra-statefulset.yaml

参考资料:​​​https://kubernetes.io/zh/docs/tutorials/stateful-application/basic-stateful-set/​​​​https://kubernetes.io/zh/docs/tutorials/stateful-application/cassandra/​​

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:k8s 删除命令空间namespace卡住解决方法
下一篇:kubernetes Pod Lifecycle生命周期与livenessProbe、 readinessProbe探测方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~