k8smysql 启动即 OOM 排查复盘
一句话:
-1/-2节点的containerd.service设了LimitNOFILE=infinity,容器内nofile被拉到 ~2³⁰,mysqld 启动按 nofile 预分配 fd 结构 ≈ 16 GiB,撑爆 4Gi limit → 启动 1 秒即 OOMKilled。与镜像、MySQL 配置、PVC 全无关。
现象
k8smysql/mysql-*podCrashLoopBackOff,OOMKilled,startedAt → finishedAt仅 1 秒- 死在 entrypoint 的
mysqld --verbose --help自检步 - 同镜像、同配置(4Gi limit)在
irr-yfl-mysql、shuiku-work(均跑在-10)上1/1 Running
根因
| 节点 | containerd LimitNOFILE |
容器内 nofile |
mysqld --help |
|---|---|---|---|
-1 / -2 |
infinity | 1,073,741,816 (≈2³⁰) | 吃 16GiB,被杀 |
-10 |
524288 | 1024 | 28MB,正常 |
/usr/lib/systemd/system/containerd.service:LimitNOFILE=infinity- 内核按
fs.nr_open上限给容器 ~2³⁰ 的 nofile - mysqld 多线程,启动按 nofile 预分配 fd 相关结构:
1,073,741,816 × 16B ≈ 16 GiB - 该 16GiB 为匿名映射,随运行逐页 touch,RSS 一路涨到撑爆 limit
决定性证据
# 容器内
ulimit -n → 1073741816 # 罪魁
# /proc/<pid>/maps 里的"幽灵映射"
16777216 kB 0 # 精确 16 GiB 匿名映射 (= 1073741816 × 16B)
# mysqld 默认下
mysqld --verbose --help → exit=137, peak RSS ~14GB, 被OOM
# 设 ulimit -n 1048576 后(=docker-compose 那段 ulimits)
mysqld --verbose --help → exit=0, peak 28MB ← 修复验证
# 节点
systemctl show containerd | grep LimitNOFILE → -1: infinity / -10: 524288
线索最初来自旧 docker-compose:
|
|
走过的弯路(教训)
按时间顺序的错误假设,每一个都被证据推翻:
- ❌ 「limit 被改小 / LimitRange / 配额」 ——
kubectl get pod -o jsonpath resources= 4Gi 实打实,LimitRange/ResourceQuota 全空 - ❌ 「节点内存不足」 ——
-116GB,requests 才用 10% - ❌ 「镜像损坏」 —— mysqld md5 在
-1/-10完全一致(6eccb50f3cf4f6afb8cdfcbcbb36298e);且-10上mysqld --help仅 2MB - ❌ 「MySQL 参数(innodb_buffer_pool_size)设大」 ——
/etc/mysql/*配置全空;强制--innodb-buffer-pool-size=128M后 16G 映射照常出现 - ❌ 「PV 钉坏节点」 —— PV nodeAffinity 确实把 pod 锁在
-1,但那是间接因素(锁在问题节点),非 OOM 直接原因
核心教训:容器「启动即 OOM」且多节点表现不同时,第一步该看 容器内 ulimit -n 和节点 containerd 的 LimitNOFILE,而不是怀疑应用/镜像/MySQL 参数。ulimit -n 达 2³⁰ 级就是这类泄漏的指纹。
修复
治本(节点侧,推荐)
|
|
影响该节点所有 pod。-10 已正常(524288),无需改;只改 -1/-2。
临时(单 pod,不动节点)
k8s securityContext 不能直接设 nofile 数值,需在 entrypoint 包一层:
|
|
实测加上后容器已正常运行。 ✅
验证
- ✅ deployment 加
ulimit -n 1048576后,k8smysql pod 正常 Running - ✅ 对照实验:
-1上ulimit -n 1048576后 mysqld--helpexit=0、peak=28MB
影响范围 & 待办
-1/-2上所有容器都受这个LimitNOFILE=infinity影响;钉在-1的k8sminio/k8sredis/k8stdengine若启动期也按 nofile 预分配,理论上同样有风险 → 建议治理本(改 containerd)- 节点
-1/-2改 containerd LimitNOFILE(治本) - 通知集群管理员,统一各节点 containerd 配置
排查工具箱(下次复用)
|
|
相关
- 最佳实践 deployment 模板(含 ulimit 修复):
/home/nysiem/mysql-deployment.yaml - 排查记忆:
~/.claude/projects/-home-nysiem/memory/k8szhslzhyy-bad-node-mysql-oom.md