当节点磁盘打满时如何优雅迁移容器
解读
国内生产环境常见“磁盘打满”场景:
- 镜像层堆积(旧版本未清理)
- 未挂载外部卷的容器写入大量日志
- 私有 Registry 与节点混部,镜像同步占满系统盘
- 云主机只给 20~40 GiB 系统盘,未单独挂数据盘
面试官想验证:
- 能否在不中断业务的前提下把容器漂到空闲节点
- 是否熟悉 Docker 存储驱动、日志驱动、卷管理
- 对“优雅”二字的理解:服务发现、连接保持、数据一致性、回滚预案
知识点
- Docker 存储驱动差异:overlay2 需 inode 与磁盘空间双重余量,devicemapper 直接-vg 打满即拒绝写入
- 容器可写层与卷(volume、bind mount)生命周期解耦
- docker inspect 查看 GraphDriver.Data 确认占用来源
- 日志驱动 json-file 的 max-size、max-file 轮转参数
- Swarm 模式下的 drain 节点与 rolling update 机制
- CRIU 技术边界:Docker 默认不开启 checkpoint/restore,国内多数公司用滚动重启代替热迁移
- 国内云厂商 ESSD、云盘快照、在线扩容 特性,可在 OS 不重启情况下扩容系统盘
- 强制清理命令:docker system prune -a、docker volume prune,但风险高,需先确认无未挂载数据库卷
答案
回答时分“应急止血”与“优雅迁移”两步,给出可落地的 SOP,并强调风险控制。
-
应急止血(30 秒内决策)
a. 立即 du -h /var/lib/docker 定位最大子目录
b. 若是日志,执行 echo "" > $(docker inspect --format='{{.LogPath}}' 容器ID) 快速截断,业务无损
c. 若是镜像层,执行 docker image prune -a --filter "until=24h" 释放空间,保留最近一天镜像防回滚失败
d. 若系统盘剩余 <5%,临时挂载云盘扩容或做软链接 /var/lib/docker → /data/docker,扩容后必须重启 Docker 守护进程 -
优雅迁移(保证 SLA)
前提:业务已用 Swarm 或 Kubernetes,容器无状态,持久卷放在 NAS/云盘
a. 在 Swarm 管理节点执行
docker node update --availability drain 目标节点
该节点上的副本会被平滑驱逐,新实例在空闲节点拉起,旧容器等待 stop-grace-period(默认 10s) 自然退出
b. 若容器挂载了本地 volume,需提前
docker run --rm -v 源卷:/from -v 远程NAS:/to alpine cp -a /from /to/$(hostname)
然后 docker service update --mount-add type=volume,source=新卷,target=/data 服务名
c. 迁移后做 三次健康检查:- docker service ps 服务名 观察 NEW 任务状态 Running
- 业务探活接口 200 OK
- 监控告警恢复
d. 原节点磁盘清理完毕,再 docker node update --availability active 重新上线
-
回滚预案
若新实例启动失败,立即
docker service scale 服务名=原副本数+1
并在原节点 docker start 旧容器(日志已截断,可临时复活),保证业务不断 -
后续根治
- 把 /var/lib/docker 和 /var/log 挂到独立云盘,系统盘只放 OS
- 在 /etc/docker/daemon.json 统一日志驱动:
{"log-driver":"json-file","log-opts":{"max-size":"50m","max-file":"3"}} - 在 CI 阶段加 docker-slim 或 多阶段构建,镜像体积下降 60%
- 用 crontab+Prometheus 监控磁盘余量 <15% 就报警,并自动触发 prune
拓展思考
-
如果业务容器有状态且未用外部卷,能否直接打 tar 包把可写层拷走?
答:overlay2 下可写层位于 /var/lib/docker/overlay2/容器ID/diff,可 tar + rsync 到目标节点,再用 docker create + docker cp 导入,但需保证存储驱动一致,且容器停写,否则文件句柄不一致导致数据损坏。生产环境不推荐,应强制用外部卷或 StatefulSet。 -
国内金融合规要求审计日志不能截断,如何既释放空间又保留日志?
答:把 json-file 改为 local 驱动并开启压缩,或 sidecar 方式用 filebeat 实时采到 Kafka,本地保留 2 小时后自动轮转,满足《银行业信息系统灾难恢复规范》中“日志不可缺失、本地可短暂清理”条款。 -
当集群所有节点磁盘同时告急,Swarm 无法调度,如何兜底?
答:- 立即在镜像仓库做 GC:registry garbage-collect config.yml,删除未引用的 blob
- 启用 镜像预热策略:只保留最近两个版本,CI 自动打标签并触发清理脚本
- 临时把副本数缩为 0 的非核心服务下线,为核心服务腾出空间,保证黄金交易链路不断
通过以上结构化回答,既展示了快速止血的实战能力,也体现了对高可用、合规、长期治理的深度思考,符合国内中大型企业对 Docker 岗位的技术期待。