2. Kubernetes 核心概念回顾:Pod、Deployment、StatefulSet、Service、ConfigMap、Secret 在数据库场景下的作用
在将数据库迁移至 Kubernetes 之前,必须深刻理解几个核心原语在数据库工作负载下的特殊行为。数据库是有状态、高敏感、对网络和存储有严格要求的应用,与无状态微服务有着本质区别。本节将逐一剖析这些资源对象,并聚焦于它们在数据库场景中的关键作用与配置陷阱。
2.1 Pod:数据库的最小运行单元
Pod 是 Kubernetes 中可调度的最小单元,通常包含一个或多个容器。在数据库场景下,强烈建议采用单容器模式,即一个 Pod 内只运行一个数据库主进程(如 mysqld、postgres、mongod),辅助进程(如备份 Agent、监控 Exporter)应作为 Sidecar 容器注入。
| 特性 | 无状态应用(Web) | 有状态数据库(MySQL/PostgreSQL) |
|---|---|---|
| 容器模式 | 多容器 Sidecar 常见 | 主进程单容器,Sidecar 仅用于日志/备份 |
| 存储 | 临时卷(emptyDir) | 持久卷(PVC),需 ReadWriteOnce |
| 生命周期 | 可随意重启、漂移 | 重启需优雅关闭,避免脑裂 |
| 资源预留 | requests 可低于 limits | requests 应等于 limits,避免 CPU 节流 |
| 健康检查 | HTTP 探针 | TCP 探针 + 自定义 SQL 探针 |
- 必须设置
terminationGracePeriodSeconds为 60-120 秒,确保数据库完成事务回滚和 WAL 刷新。 - 使用
preStop钩子执行pg_ctl stop -m fast或mysqladmin shutdown,而非直接发送 SIGTERM。 - 避免使用
hostNetwork,除非对网络延迟有极致要求(如 Redis)。
2.2 Deployment vs StatefulSet:有状态应用的抉择
Deployment 适用于无状态应用,所有 Pod 副本完全对等,可以随机替换。而数据库集群(主从、分片)要求稳定的网络标识和有序的启停顺序,因此 StatefulSet 是数据库在 Kubernetes 上的唯一正确选择。
- serviceName:必须指向一个 Headless Service,用于稳定的 DNS 解析(如 mysql-0.mysql-svc.namespace.svc.cluster.local)。
- volumeClaimTemplates:自动为每个副本创建独立的 PVC,存储类应选择
WaitForFirstConsumer以绑定本地节点。 - podManagementPolicy:数据库主从场景建议使用
OrderedReady(默认),确保从节点先就绪,主节点最后升级。
2.3 Service:数据库流量的稳定入口
数据库客户端需要稳定的网络端点,而 Pod 的 IP 会随重启变化。Service 提供了抽象层。在数据库场景下,两种 Service 类型至关重要:
| Service 类型 | ClusterIP | Headless Service |
|---|---|---|
| DNS 解析 | 返回 VIP,负载均衡到所有 Pod | 返回所有 Pod IP 列表(A/AAAA 记录) |
| 适用场景 | 读写分离代理、应用层连接池 | StatefulSet 节点间通信、主从复制 |
| 数据库用例 | 应用通过 ClusterIP 访问数据库主服务 | 从节点通过 mysql-0.mysql-svc 找到主节点 |
| 注意事项 | 避免使用 externalTrafficPolicy: Local 导致连接分布不均 |
客户端需自行处理节点选择逻辑 |
不要将数据库 Service 的 sessionAffinity 设置为 ClientIP,除非你明确知道自己在做什么。这会导致连接长时间绑定到同一个 Pod,在滚动更新或故障转移时造成连接中断。数据库连接池本身已经具备重连机制,无需 Kubernetes 层面的会话保持。
2.4 ConfigMap 与 Secret:配置与凭证的分离
数据库配置(my.cnf、postgresql.conf)和敏感凭证(密码、TLS 证书)必须与容器镜像解耦。Kubernetes 提供了 ConfigMap 和 Secret 来实现配置与镜像的分离。
- ConfigMap 不可变:设置
immutable: true可避免配置被意外修改,同时减轻 API Server 压力。 - Secret 自动轮换:使用
reload注解或外部工具(如 External Secrets Operator)实现密码自动轮换,无需重启 Pod。 - 挂载方式:优先使用
subPath挂载单个文件,而非整个卷,避免覆盖容器内的其他配置文件。 - 大小限制:ConfigMap 和 Secret 的单个条目大小限制为 1MB,数据库配置文件通常远小于此值,但需注意 TLS 证书链可能较大。
2.5 核心概念在数据库迁移中的协同关系
在数据库迁移项目中,上述资源并非孤立使用,而是形成一个完整的部署拓扑。以下是一个典型 MySQL 主从集群在 Kubernetes 上的资源依赖关系:
| 资源类型 | 实例名称 | 作用 | 数据库场景关键属性 |
|---|---|---|---|
| StatefulSet | mysql-cluster | 管理 3 个 MySQL Pod(1 主 2 从) | serviceName: mysql-hl; volumeClaimTemplates: 100Gi SSD |
| Headless Service | mysql-hl | 提供稳定 DNS:mysql-0.mysql-hl.svc.cluster.local | clusterIP: None; publishNotReadyAddresses: true |
| ClusterIP Service | mysql-rw | 应用写入流量入口,指向主节点 | selector: role=master; 端口 3306 |
| ClusterIP Service | mysql-ro | 应用只读流量入口,指向从节点 | selector: role=replica; 端口 3306 |
| ConfigMap | mysql-config | 存储 my.cnf 公共配置 | immutable: true; data: max_connections, binlog 配置 |
| Secret | mysql-secret | 存储 root 密码、复制账号、TLS 证书 | type: Opaque; 使用 base64 编码 |
| PersistentVolumeClaim | data-mysql-cluster-0 | 每个 Pod 独立的数据卷 | storageClassName: local-ssd; accessModes: ReadWriteOnce |
- 是否所有数据库 Pod 都使用 StatefulSet 而非 Deployment?
- Headless Service 是否已配置
publishNotReadyAddresses: true以支持滚动更新期间的节点发现? - ConfigMap 中是否误放了数据库密码或证书私钥?
- Secret 是否设置了
stringData字段以便于人类可读的 YAML 管理? - 每个 StatefulSet 副本是否绑定了独立的 PVC,且存储类支持所需的 IOPS?