3. 数据库容器化基础:Dockerfile编写最佳实践、数据库镜像优化、健康检查与就绪探针配置
数据库容器化是Kubernetes迁移的基石。与无状态应用不同,数据库镜像对稳定性、数据持久性、启动顺序和资源效率有极高要求。本章聚焦Dockerfile编写规范、镜像瘦身策略以及Kubernetes原生健康检查机制,确保数据库Pod在集群中可靠运行。
3.1 Dockerfile编写最佳实践
数据库Dockerfile的核心原则:可重复构建、最小攻击面、明确的启动契约。以下为生产级MySQL 8.0 Dockerfile示例:
# 1. 使用官方镜像作为基础,锁定精确版本
FROM mysql:8.0.32-oracle AS base
# 2. 设置元数据
LABEL maintainer="dba-team@company.com" \
description="Production MySQL 8.0 with custom config"
# 3. 注入自定义配置文件(覆盖默认my.cnf)
COPY my-custom.cnf /etc/mysql/conf.d/my-custom.cnf
# 4. 设置数据目录权限(非root用户运行)
RUN chown -R mysql:mysql /var/lib/mysql
# 5. 暴露端口
EXPOSE 3306
# 6. 定义数据卷
VOLUME ["/var/lib/mysql"]
# 7. 使用官方entrypoint(包含初始化逻辑)
ENTRYPOINT ["docker-entrypoint.sh"]
# 8. 默认启动命令
CMD ["mysqld"]
最佳实践要点:
- 固定基础镜像标签:使用
8.0.32-oracle而非8.0或latest,避免意外升级导致兼容性问题。 - 分层优化:将频繁变更的配置放在Dockerfile末尾,利用构建缓存加速CI/CD。
- 非root运行:数据库进程默认以
mysql用户运行,避免容器逃逸风险。 - 避免安装额外工具:生产镜像不应包含
curl、vim、netcat等调试工具,减少攻击面。
3.2 数据库镜像优化:从1.2GB到280MB
官方MySQL镜像体积约1.2GB,包含大量调试符号、文档和语言包。对于Kubernetes集群,大镜像拖慢调度和扩缩容速度。以下为镜像瘦身策略对比:
| 优化策略 | 操作方式 | 体积缩减 | 风险等级 |
|---|---|---|---|
| 多阶段构建 | 编译阶段使用完整镜像,运行阶段复制二进制到slim基础镜像 | 60%–70% | 低 |
| 删除缓存和文档 | rm -rf /usr/share/doc /usr/share/man /var/lib/apt/lists/* |
10%–15% | 低 |
| 使用distroless基础镜像 | 基于 gcr.io/distroless/base,仅包含运行时依赖 |
75%–85% | 中(需验证glibc兼容性) |
| 剥离调试符号 | strip --strip-debug /usr/sbin/mysqld |
5%–10% | 低 |
| 合并RUN指令 | 将多个 RUN 合并为一行,减少镜像层数 |
层数减少,体积影响小 | 低 |
生产推荐方案: 使用
mysql:8.0.32-oracle 作为基础,配合多阶段构建将自定义二进制或插件复制到 gcr.io/distroless/base 上。最终镜像体积可控制在280MB–350MB,且通过CVE扫描无高危漏洞。
以下为多阶段构建Dockerfile示例:
# 阶段1:编译或准备阶段
FROM mysql:8.0.32-oracle AS builder
COPY custom-plugin.so /tmp/
RUN strip --strip-debug /usr/sbin/mysqld
# 阶段2:运行阶段
FROM gcr.io/distroless/base-debian11
COPY --from=builder /usr/sbin/mysqld /usr/sbin/
COPY --from=builder /usr/lib/mysql /usr/lib/mysql
COPY --from=builder /etc/mysql /etc/mysql
COPY --from=builder /tmp/custom-plugin.so /usr/lib/mysql/plugin/
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["mysqld"]
注意: distroless镜像不包含shell、包管理器或调试工具。如果数据库初始化脚本依赖
bash、sed 或 awk,则必须保留基础镜像中的这些工具,或改用静态编译的entrypoint。
3.3 健康检查与就绪探针配置
Kubernetes通过三种探针管理数据库Pod生命周期:
- livenessProbe(存活探针):检测数据库进程是否存活。失败则重启Pod。
- readinessProbe(就绪探针):检测数据库是否可接受流量。失败则从Service端点移除。
- startupProbe(启动探针):检测数据库是否完成初始化。用于慢启动应用,避免liveness误杀。
数据库探针配置的核心差异:
| 探针类型 | 检测命令 | 典型阈值 | 失败后果 |
|---|---|---|---|
| livenessProbe | mysqladmin ping 或 pg_isready |
initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 3 |
Pod重启 |
| readinessProbe | 自定义SQL查询(如 SELECT 1) |
initialDelaySeconds: 10 periodSeconds: 5 failureThreshold: 2 |
从Service摘除 |
| startupProbe | 与liveness相同,但容忍更长时间 | initialDelaySeconds: 5 periodSeconds: 10 failureThreshold: 30 |
Pod重启(仅启动阶段) |
生产配置建议:
- readinessProbe使用
SELECT 1而非mysqladmin ping,因为ping只验证进程存活,不验证SQL层是否就绪。 - 为慢启动数据库(如Galera集群、PostgreSQL大恢复)设置
startupProbe,避免启动阶段被liveness反复重启。 - 探针超时时间
timeoutSeconds建议设为5秒,避免慢查询阻塞探针导致误判。
以下为MySQL在Kubernetes中的完整探针配置YAML片段:
apiVersion: v1
kind: Pod
metadata:
name: mysql-db
spec:
containers:
- name: mysql
image: my-registry/mysql:8.0-slim
ports:
- containerPort: 3306
startupProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 30
livenessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- sh
- -c
- "mysql -u root -p$MYSQL_ROOT_PASSWORD -e 'SELECT 1'"
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 2
3.4 数据库容器化探针与启动流程
下图展示了数据库Pod从启动到对外提供服务的完整生命周期,以及三种探针的介入时机:
3.5 数据库探针配置参数速查表
以下为生产环境推荐的探针参数组合,适用于MySQL、PostgreSQL和MongoDB:
| 参数 | MySQL | PostgreSQL | MongoDB |
|---|---|---|---|
| startupProbe命令 | mysqladmin ping |
pg_isready -U postgres |
mongo --eval "db.adminCommand('ping')" |
| startupProbe failureThreshold | 30 | 30 | 20 |
| livenessProbe命令 | mysqladmin ping |
pg_isready -q |
mongo --quiet --eval "db.adminCommand('ping')" |
| livenessProbe periodSeconds | 15 | 15 | 10 |
| readinessProbe命令 | SELECT 1 |
SELECT 1 |
db.runCommand({isMaster:1}) |
| readinessProbe periodSeconds | 5 | 5 | 5 |
| timeoutSeconds | 5 | 5 | 5 |
常见陷阱:
- 不要对readinessProbe使用
mysqladmin ping,该命令仅验证TCP连接和进程存活,不验证InnoDB是否完成崩溃恢复或复制线程是否就绪。 - 探针命令中避免使用交互式密码输入。MySQL应通过
-p$MYSQL_ROOT_PASSWORD环境变量传递密码,PostgreSQL应配置.pgpass文件或使用peer认证。 - 对于Galera集群或MongoDB副本集,readinessProbe应检测节点状态是否为
Synced或PRIMARY,而非简单ping。
3.6 数据库容器化架构总览
下图总结了数据库容器化的核心组件及其关系:
3.7 本章小结
数据库容器化并非简单地将传统数据库打包成镜像。通过本章学习,应掌握以下核心能力:
- 编写符合生产标准的Dockerfile,锁定版本、分层优化、非root运行。
- 使用多阶段构建和distroless基础镜像将数据库镜像体积缩减70%以上。
- 配置Kubernetes三种探针(startup/liveness/readiness),确保数据库Pod在启动、运行和故障恢复阶段的行为可预测。
- 根据数据库类型(MySQL/PostgreSQL/MongoDB)选择正确的探针命令和阈值参数。