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从启动到对外提供服务的完整生命周期,以及三种探针的介入时机:

数据库Pod启动与探针生命周期 容器创建 startupProbe 初始化完成 livenessProbe readinessProbe Service端点就绪 探针失败 Pod重启/摘除 关键说明: • startupProbe仅在启动阶段运行,成功后自动停止,避免慢启动被liveness误杀。 • livenessProbe持续运行,失败3次(默认)触发Pod重启,适用于检测死锁或进程挂起。 • readinessProbe失败时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 数据库容器化架构总览

下图总结了数据库容器化的核心组件及其关系:

数据库容器化核心架构 Dockerfile 多阶段构建 / 最小基础镜像 数据库镜像 MySQL / PostgreSQL / MongoDB Kubernetes Pod 容器编排 / 资源限制 探针配置:startupProbe → livenessProbe → readinessProbe 持久化存储 PVC / HostPath / CSI 网络与Service ClusterIP / Headless / DNS 监控与日志 Prometheus / Fluentd / Grafana 架构要点: Dockerfile定义镜像构建规则 → 镜像包含数据库二进制和配置 → Pod通过探针确保服务可用性 → 存储/网络/监控层提供基础设施支撑。

3.7 本章小结

数据库容器化并非简单地将传统数据库打包成镜像。通过本章学习,应掌握以下核心能力:

  • 编写符合生产标准的Dockerfile,锁定版本、分层优化、非root运行。
  • 使用多阶段构建和distroless基础镜像将数据库镜像体积缩减70%以上。
  • 配置Kubernetes三种探针(startup/liveness/readiness),确保数据库Pod在启动、运行和故障恢复阶段的行为可预测。
  • 根据数据库类型(MySQL/PostgreSQL/MongoDB)选择正确的探针命令和阈值参数。