StatefulSet 控制器流程
概述
StatefulSet 用于管理有状态应用,提供有序部署、稳定网络标识和持久化存储。与 Deployment 不同,StatefulSet 保证 Pod 的顺序性和唯一性。
核心架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ StatefulSetController │ │ pkg/controller/statefulset/stateful_set.go │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ kubeClient │ │ setLister │ │ podLister │ │ queue │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ StatefulSetControlInterface │ │ pkg/controller/statefulset/stateful_set_control.go │ │ │ │ - sync() 协调 StatefulSet │ │ - updateStatefulSet() 更新状态 │ │ - adoptOrphanRevisions() 采纳孤儿 Revision │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ StatefulPodControl │ │ pkg/controller/statefulset/stateful_pod_control.go │ │ │ │ - createPod() 创建 Pod │ │ - deletePod() 删除 Pod │ │ - updatePod() 更新 Pod │ │ - createPersistentVolumeClaims() 创建 PVC │ └──────────────────────────────────────────────────────────────────────────────┘
|
核心数据结构
StatefulSet API 类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
type StatefulSetSpec struct { Replicas *int32 Selector *metav1.LabelSelector Template v1.PodTemplateSpec VolumeClaimTemplates []v1.PersistentVolumeClaim ServiceName string PodManagementPolicy PodManagementPolicyType UpdateStrategy StatefulSetUpdateStrategy RevisionHistoryLimit *int32 MinReadySeconds int32 }
type StatefulSetUpdateStrategy struct { Type StatefulSetUpdateStrategyType RollingUpdate *RollingUpdateStatefulSetStrategy }
type RollingUpdateStatefulSetStrategy struct { Partition *int32 MaxUnavailable *intstr.IntOrString }
|
Pod 管理策略
1 2 3 4 5 6 7 8 9
| type PodManagementPolicyType string
const ( OrderedReady PodManagementPolicyType = "OrderedReady"
Parallel PodManagementPolicyType = "Parallel" )
|
控制器工作流程
主循环
- 文件:
pkg/controller/statefulset/stateful_set.go
- 函数:
StatefulSetController.Run() (第 152 行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ 控制器启动 │ │ StatefulSetController.Run(ctx, workers) │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 等待缓存同步 │ │ WaitForCacheSync(podListerSynced, setListerSynced, │ │ pvcListerSynced, revListerSynced) │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 启动 Worker │ │ for i := 0; i < workers; i++ │ │ go wait.Until(worker, time.Second) │ └──────────────────────────────────────────────────────────────────────────────┘
|
单次调谐流程
- 函数:
StatefulSetController.sync() -> defaultStatefulSetControl.sync()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ 从队列获取 StatefulSet │ │ queue.Get() -> key │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 获取 StatefulSet 和关联资源 │ │ │ │ 1. 获取 StatefulSet 对象 │ │ 2. 获取关联的 Pod (通过 selector) │ │ 3. 获取关联的 PVC │ │ 4. 获取 ControllerRevisions │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 检查并创建 Headless Service │ │ │ │ - StatefulSet 必须关联一个 Headless Service │ │ - Service 提供 Pod 的网络标识 │ │ - 格式: <statefulset-name>-<ordinal>.<service-name>.<namespace>.svc │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 更新状态 │ │ │ │ - 计算当前副本数 │ │ - 计算就绪副本数 │ │ - 计算当前版本 │ │ - 更新 StatefulSetStatus │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 执行协调逻辑 │ │ │ │ 根据当前状态选择操作: │ │ ├── 缩容 -> 删除多余的 Pod (逆序) │ │ ├── 扩容 -> 创建新的 Pod (顺序) │ │ └── 更新 -> 滚动更新 Pod │ └──────────────────────────────────────────────────────────────────────────────┘
|
有序部署/删除流程
OrderedReady 策略 (默认)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ 创建 Pod (扩容) │ │ │ │ StatefulSet: web, Replicas: 3 │ │ │ │ 步骤 1: 创建 web-0 │ │ ├── 创建 PVC: www-web-0 │ │ ├── 创建 Pod: web-0 │ │ └── 等待 web-0 Running && Ready │ │ │ │ 步骤 2: 创建 web-1 │ │ ├── 创建 PVC: www-web-1 │ │ ├── 创建 Pod: web-1 │ │ └── 等待 web-1 Running && Ready │ │ │ │ 步骤 3: 创建 web-2 │ │ ├── 创建 PVC: www-web-2 │ │ ├── 创建 Pod: web-2 │ │ └── 等待 web-2 Running && Ready │ └──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐ │ 删除 Pod (缩容) │ │ │ │ StatefulSet: web, Replicas: 1 (从 3 缩容) │ │ │ │ 步骤 1: 删除 web-2 │ │ └── 等待 web-2 完全终止 │ │ │ │ 步骤 2: 删除 web-1 │ │ └── 等待 web-1 完全终止 │ │ │ │ 结果: 只保留 web-0 │ │ 注意: PVC 不会被删除 │ └──────────────────────────────────────────────────────────────────────────────┘
|
Parallel 策略
1 2 3 4 5 6 7 8 9 10 11 12
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ 并行创建/删除 │ │ │ │ StatefulSet: web, Replicas: 3, PodManagementPolicy: Parallel │ │ │ │ 同时创建: │ │ ├── web-0 (创建 PVC: www-web-0, 创建 Pod) │ │ ├── web-1 (创建 PVC: www-web-1, 创建 Pod) │ │ └── web-2 (创建 PVC: www-web-2, 创建 Pod) │ │ │ │ 不等待前一个 Pod 就绪 │ └──────────────────────────────────────────────────────────────────────────────┘
|
滚动更新流程
RollingUpdate 策略
- 文件:
pkg/controller/statefulset/stateful_set_control.go
- 函数:
rollingUpdate()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ 滚动更新触发 │ │ StatefulSet Spec 变更 (Pod 模板更新) │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 创建新的 ControllerRevision │ │ │ │ - 记录新的 Pod 模板 │ │ - 更新 StatefulSet 的 currentRevision │ │ - 保留历史版本 (受 revisionHistoryLimit 限制) │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 逆序更新 Pod │ │ │ │ StatefulSet: web, Replicas: 3, Partition: 0 │ │ │ │ 步骤 1: 更新 web-2 │ │ ├── 删除旧 Pod web-2 │ │ ├── 等待 PVC 就绪 (如果更新了) │ │ ├── 使用新模板创建 web-2 │ │ └── 等待 web-2 Running && Ready │ │ │ │ 步骤 2: 更新 web-1 │ │ ├── 删除旧 Pod web-1 │ │ ├── 等待 PVC 就绪 │ │ ├── 使用新模板创建 web-1 │ │ └── 等待 web-1 Running && Ready │ │ │ │ 步骤 3: 更新 web-0 │ │ ├── 删除旧 Pod web-0 │ │ ├── 等待 PVC 就绪 │ │ ├── 使用新模板创建 web-0 │ │ └── 等待 web-0 Running && Ready │ └──────────────────────────────────────────────────────────────────────────────┘
|
Partition 分区更新
1 2 3 4 5
| spec: updateStrategy: type: RollingUpdate rollingUpdate: partition: 2
|
1 2 3 4 5 6 7 8 9
| StatefulSet: web, Replicas: 4, Partition: 2
更新前: web-0 (v1), web-1 (v1), web-2 (v1), web-3 (v1)
更新后 (新版本 v2): web-0 (v1), web-1 (v1), web-2 (v2), web-3 (v2)
只有 ordinal >= 2 的 Pod 被更新
|
稳定网络标识
Pod 域名格式
1 2 3 4 5
| <pod-name>.<service-name>.<namespace>.svc.cluster.local
示例: web-0.headless-service.default.svc.cluster.local web-1.headless-service.default.svc.cluster.local
|
Headless Service 配置
1 2 3 4 5 6 7 8 9 10
| apiVersion: v1 kind: Service metadata: name: headless-service spec: clusterIP: None selector: app: web ports: - port: 80
|
DNS 记录
1 2 3 4 5 6 7
| # 每个 Pod 获得一个 A 记录 web-0.headless-service.default.svc.cluster.local -> 10.244.1.5 web-1.headless-service.default.svc.cluster.local -> 10.244.1.6 web-2.headless-service.default.svc.cluster.local -> 10.244.1.7
# Service 本身也有记录 (指向所有 Pod) headless-service.default.svc.cluster.local -> 10.244.1.5, 10.244.1.6, 10.244.1.7
|
PVC 管理
PVC 创建
- 文件:
pkg/controller/statefulset/stateful_pod_control.go
- 函数:
createPersistentVolumeClaims()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ PVC 命名规则 │ │ │ │ <volumeclaim-name>-<statefulset-name>-<ordinal> │ │ │ │ 示例: www-web-0, www-web-1, www-web-2 │ └──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐ │ PVC 生命周期 │ │ │ │ 创建 Pod 前: │ │ 1. 检查 PVC 是否存在 │ │ 2. 如果不存在,从 VolumeClaimTemplate 创建 │ │ 3. 等待 PVC 绑定 (Bound) │ │ 4. 创建 Pod │ │ │ │ 删除 Pod 时: │ │ - PVC 不会被删除 │ │ - 数据被保留 │ │ - Pod 重新创建时绑定同一个 PVC │ │ │ │ 删除 StatefulSet 时: │ │ - PVC 不会被删除 │ │ - 需要手动清理 │ └──────────────────────────────────────────────────────────────────────────────┘
|
VolumeClaimTemplate 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: headless-service replicas: 3 volumeClaimTemplates: - metadata: name: www spec: accessModes: ["ReadWriteOnce"] storageClassName: "standard" resources: requests: storage: 1Gi template: spec: containers: - name: nginx image: nginx volumeMounts: - name: www mountPath: /usr/share/nginx/html
|
关键代码路径
| 文件 |
说明 |
pkg/controller/statefulset/stateful_set.go |
StatefulSet 控制器 |
pkg/controller/statefulset/stateful_set_control.go |
协调逻辑 |
pkg/controller/statefulset/stateful_pod_control.go |
Pod 操作 |
pkg/controller/statefulset/stateful_pod_status_updater.go |
状态更新 |
staging/src/k8s.io/api/apps/v1/types.go |
API 类型 |
常见问题排查
1. Pod 卡在 Pending
1 2 3 4 5 6 7 8 9 10
| kubectl get pvc
kubectl describe pod <pod-name>
|
2. 滚动更新卡住
1 2 3 4 5 6 7 8
| kubectl describe statefulset <name>
kubectl get statefulset <name> -o yaml | grep partition -A 2
|
3. PVC 数据丢失
1 2 3 4 5 6 7 8
| kubectl get pvc
kubectl get pv
|
4. 网络标识问题
1 2 3 4 5 6 7 8
| kubectl get svc <service-name>
kubectl exec -it <pod> -- nslookup web-0.headless-service
kubectl get endpoints <service-name>
|
配置示例
完整 StatefulSet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| apiVersion: v1 kind: Service metadata: name: nginx-headless spec: clusterIP: None selector: app: nginx ports: - port: 80 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: nginx-headless replicas: 3 selector: matchLabels: app: nginx podManagementPolicy: OrderedReady updateStrategy: type: RollingUpdate rollingUpdate: partition: 0 volumeClaimTemplates: - metadata: name: www spec: accessModes: ["ReadWriteOnce"] storageClassName: standard resources: requests: storage: 1Gi template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.20 ports: - containerPort: 80 volumeMounts: - name: www mountPath: /usr/share/nginx/html
|
面试题
基础题
1. StatefulSet 与 Deployment 有什么区别?
参考答案:
| 特性 |
StatefulSet |
Deployment |
| Pod 标识 |
稳定(web-0, web-1) |
随机(web-7f8b9c-x5k2) |
| 启动顺序 |
有序(0→1→2) |
并行 |
| 存储 |
每个Pod独立PVC |
共享或无 |
| 网络标识 |
稳定域名 |
无 |
| 扩缩容 |
有序 |
并行 |
| 适用场景 |
有状态应用 |
无状态应用 |
2. StatefulSet 的典型应用场景有哪些?
参考答案:
- 数据库:MySQL、PostgreSQL、MongoDB
- 消息队列:Kafka、RabbitMQ、Pulsar
- 缓存:Redis Cluster、Memcached
- 分布式存储:Elasticsearch、Cassandra、Ceph
- 协调服务:ZooKeeper、etcd
3. StatefulSet Pod 的命名规则是什么?
参考答案:
1 2 3 4 5 6
| <statefulset-name>-<ordinal>
示例: web-0, web-1, web-2 mysql-0, mysql-1, mysql-2 kafka-0, kafka-1, kafka-2
|
特点:
- ordinal 从 0 开始
- 连续递增
- 删除后重建保留原名称
中级题
4. 解释 StatefulSet 的有序部署流程。
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| StatefulSet: web, Replicas: 3
步骤 1: 创建 web-0 ├── 创建 PVC www-web-0 ├── 创建 Pod web-0 └── 等待 web-0 Running && Ready
步骤 2: 创建 web-1 ├── 创建 PVC www-web-1 ├── 创建 Pod web-1 └── 等待 web-1 Running && Ready
步骤 3: 创建 web-2 ├── 创建 PVC www-web-2 ├── 创建 Pod web-2 └── 等待 web-2 Running && Ready
|
关键代码:pkg/controller/statefulset/stateful_set_control.go:365 - processReplica()
5. StatefulSet 的 Headless Service 有什么作用?
参考答案:
1. DNS 记录:
1 2 3
| web-0.headless-service.default.svc.cluster.local -> 10.244.1.5 web-1.headless-service.default.svc.cluster.local -> 10.244.1.6 web-2.headless-service.default.svc.cluster.local -> 10.244.1.7
|
2. 网络标识:
1 2 3 4 5 6 7 8 9 10 11
| apiVersion: v1 kind: Service metadata: name: headless-service spec: clusterIP: None selector: app: web ports: - port: 80
|
6. StatefulSet 的 PVC 管理机制是怎样的?
参考答案:
PVC 命名规则:
1 2 3 4 5
| <volumeclaim-name>-<statefulset-name>-<ordinal>
示例: www-web-0, www-web-1, www-web-2 data-mysql-0, data-mysql-1
|
生命周期:
1 2 3 4 5 6 7
| 创建 Pod -> 创建 PVC -> 绑定 PV -> 创建 Pod ↑ 独立生命周期
删除 Pod -> PVC 保留 删除 StatefulSet -> PVC 保留 手动删除 PVC -> PV 回收
|
7. StatefulSet 的两种 Pod 管理策略有什么区别?
参考答案:
| 策略 |
OrderedReady |
Parallel |
| 启动 |
顺序,等待前一个就绪 |
并行 |
| 终止 |
逆序,等待前一个终止 |
并行 |
| 扩缩 |
有序 |
并行 |
| 适用场景 |
需要严格顺序 |
可并行初始化 |
配置示例:
1 2
| spec: podManagementPolicy: Parallel
|
高级题
8. StatefulSet 滚动更新的流程是怎样的?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| StatefulSet: web, Replicas: 3
步骤 1: 更新 web-2(最高 ordinal) ├── 删除 Pod web-2 ├── 使用新模板创建 web-2 └── 等待 Running && Ready
步骤 2: 更新 web-1 ├── 删除 Pod web-1 ├── 使用新模板创建 web-1 └── 等待 Running && Ready
步骤 3: 更新 web-0(最低 ordinal) ├── 删除 Pod web-0 ├── 使用新模板创建 web-0 └── 等待 Running && Ready
|
关键点:
- 逆序更新:从最高 ordinal 开始
- 一次一个:等待前一个就绪后才更新下一个
- 保留存储:删除 Pod 不会删除 PVC
9. 解释 Partition 参数的作用。
参考答案:
Partition 用于金丝雀发布,只更新 ordinal >= partition 的 Pod。
1 2 3 4 5 6
| spec: replicas: 5 updateStrategy: type: RollingUpdate rollingUpdate: partition: 3
|
示例:
1 2 3 4
| Partition: 3, Replicas: 5
更新前: web-0(v1), web-1(v1), web-2(v1), web-3(v1), web-4(v1) 更新后: web-0(v1), web-1(v1), web-2(v1), web-3(v2), web-4(v2)
|
10. 如何实现 StatefulSet 的零停机更新?
参考答案:
1. 使用 OnDelete 策略:
1 2 3
| spec: updateStrategy: type: OnDelete
|
2. 使用 PreStop Hook:
1 2 3 4
| lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 15; graceful-shutdown.sh"]
|
3. 使用 PodDisruptionBudget:
1 2 3 4 5 6 7 8 9
| apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: web-pdb spec: minAvailable: 2 selector: matchLabels: app: web
|
11. StatefulSet 缩容时 PVC 会怎样?如何实现自动清理?
参考答案:
默认行为:PVC 不会被删除,数据保留。
自动清理配置(Kubernetes 1.23+):
1 2 3 4 5 6 7 8
| apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: persistentVolumeClaimRetentionPolicy: whenDeleted: Retain whenScaled: Delete
|
场景题
12. 如何部署一个高可用的 MySQL 集群?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql-headless replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: initContainers: - name: init-mysql image: mysql:8.0 command: - bash - "-c" - | # 设置 server-id [[ $(hostname) =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf # 主从配置 if [[ $ordinal -eq 0 ]]; then cp /mnt/config-map/master.cnf /mnt/conf.d/ else cp /mnt/config-map/slave.cnf /mnt/conf.d/ fi volumeMounts: - name: conf mountPath: /mnt/conf.d - name: config-map mountPath: /mnt/config-map containers: - name: mysql image: mysql:8.0 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password ports: - containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql - name: conf mountPath: /etc/mysql/conf.d volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: standard resources: requests: storage: 10Gi --- apiVersion: v1 kind: Service metadata: name: mysql-headless spec: clusterIP: None selector: app: mysql ports: - port: 3306 --- apiVersion: v1 kind: Service metadata: name: mysql-read spec: selector: app: mysql ports: - port: 3306
|
关键设计点:
- 使用 Init Container 动态配置 server-id
- ordinal=0 为主节点,其他为从节点
- 读写分离通过不同 Service 实现
13. StatefulSet 更新卡住如何排查?
参考答案:
1. 检查 StatefulSet 状态:
1
| kubectl describe statefulset <name>
|
2. 检查 Pod 状态:
1 2
| kubectl get pods -l app=<app> -o wide kubectl describe pod <pod-name>
|
3. 常见卡住原因:
- 镜像拉取失败:检查 imagePullPolicy 和 secret
- PVC 未绑定:检查 storageClass 和 PV
- 健康检查失败:检查 liveness/readiness probe
- 前一个 Pod 未就绪:OrderedReady 策略会等待
14. 如何实现 StatefulSet 的蓝绿部署?
参考答案:
方案 1:使用 Partition 分阶段:
1 2 3 4 5 6 7
| kubectl patch statefulset web --type='json' \ -p='[{"op":"replace","path":"/spec/updateStrategy/rollingUpdate/partition","value":2}]'
kubectl patch statefulset web --type='json' \ -p='[{"op":"replace","path":"/spec/updateStrategy/rollingUpdate/partition","value":0}]'
|
15. 如何处理 StatefulSet 节点故障?
参考答案:
手动处理:
1 2 3 4 5 6 7
| kubectl get nodes
kubectl delete pod <pod-name> --force --grace-period=0
|
最佳实践:
1 2 3 4 5 6 7 8 9
| spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: mysql topologyKey: kubernetes.io/hostname
|