mysql健康探针必须用exec或tcpsocket而非httpget,因无http接口;readinessprobe需设initialdelayseconds≥30秒防启动未完成,livenessprobe应仅检查mysqld进程存活,避免业务查询;密码含特殊字符时须用脚本转义或改用tcpsocket。

livenessProbe 和 readinessProbe 必须分开配置,且不能共用同一个健康端点——MySQL 本身不提供 HTTP 接口,直接套用 /healthz 会失败。
MySQL 容器没有 /healthz 路径,别硬套 HTTP 探针
很多初学者照搬 Web 应用的配置,在 MySQL 的 Deployment 里写 httpGet: path: /healthz port: 3306,结果 Pod 一直卡在 CrashLoopBackOff 或反复重启。MySQL 默认不监听 HTTP,3306 是 MySQL 协议端口,不是 HTTP 端口,httpGet 在这里完全无效。
正确做法是:对 MySQL 使用 exec 或 tcpSocket 探针。前者更可靠,能验证数据库是否真能响应查询;后者只确认端口通,无法判断 mysqld 是否已初始化完成或账号权限是否就绪。
-
exec方式:在容器内执行mysqladmin ping -u root -p$MYSQL_ROOT_PASSWORD -h 127.0.0.1 --silent - 必须确保
MYSQL_ROOT_PASSWORD已通过环境变量或 Secret 注入,且密码中不含特殊字符(否则 shell 解析失败) - 若使用非 root 用户,需提前建好该用户并赋予权限:
SELECT或USAGE就够用
readinessProbe 要等 MySQL 初始化完成再开始探测
MySQL 启动后需要时间加载系统表、恢复 InnoDB 缓冲池、执行 initdb 脚本等。如果 initialDelaySeconds 设太小(比如 5 秒),探针会在 mysqld 还没 ready 时就开始执行 mysqladmin ping,返回 Access denied 或 Can't connect to local MySQL server,导致 Pod 永远进不了 Ready 状态。
- 建议
initialDelaySeconds: 30(安全起见可设到 60) - 配合
failureThreshold: 5和periodSeconds: 10,允许最多 50 秒的启动容忍窗口 - 避免把
readinessProbe和livenessProbe的initialDelaySeconds设成一样——就绪探针理应比存活探针更早介入流量控制
livenessProbe 不该检查业务表,但要防进程假死
有人在 livenessProbe.exec.command 里写 mysql -u app -p$PASS -e "SELECT COUNT(*) FROM app.users",这很危险:一旦业务表被误删或锁住,探针失败 → 重启 MySQL → 数据目录被重新初始化(如果用了 emptyDir)→ 全量丢失。
存活探针的目标只有一个:确认 mysqld 进程还在跑、能响应基础管理命令。
- 推荐命令:
mysqladmin ping -u root -p$MYSQL_ROOT_PASSWORD --silent - 加
--silent是为了屏蔽成功时的输出(kubelet 只看 exit code) - 不要加
-h localhost—— 它会走 socket 连接,而容器内默认无 socket 文件;用-h 127.0.0.1强制走 TCP -
timeoutSeconds建议设为 3~5 秒:网络延迟 + MySQL 响应慢时留出余量,避免因瞬时抖动误判
Secret 中密码含 $、\、' 等字符时 exec 命令会解析失败
这是线上最隐蔽的坑之一。Kubernetes 会把 Secret 的值原样注入环境变量,但 exec 探针运行在 shell 中,$MYSQL_ROOT_PASSWORD 若含 $PATH、\n 或单引号,会导致命令截断或语法错误,探针永远返回 2(command not found)。
解决办法只有两个:
- 改用
tcpSocket探针(仅验证端口可达,安全性较低但稳定) - 改用自定义脚本:把检查逻辑写进容器内的
/health.sh,用exec: command: ["/bin/sh", "/health.sh"]调用,并在脚本里用printf %q安全转义密码
多数生产环境选择后者——多几行脚本,换来的是探针行为可预测、错误可调试。











