1. 问题现象:Docker安装过程中的离奇卡死
那天下午三点十七分,我正在给新采购的六台阿里云ECS服务器部署K8s集群。按照标准流程,首先需要通过Ansible批量安装Docker作为容器运行时环境。当执行到apt-get install docker-ce时,第三台服务器突然卡在了"Setting up docker-ce (5:20.10.14~3-0~ubuntu-focal)..."这个步骤,进度条完全静止,SSH会话也没有任何响应。
我下意识做了以下检查:
- 通过阿里云控制台查看实例监控,CPU利用率仅3%,内存剩余12GB
- 使用
ps aux | grep docker确认安装进程仍在运行 - 尝试新建SSH连接失败(端口22无响应)
1.1 环境背景说明
- 操作系统:Ubuntu 20.04.4 LTS
- 硬件配置:8核16G云服务器
- 网络环境:阿里云内网互通
- 部署工具:Ansible 2.9.27
- 目标版本:Docker 20.10.14
关键现象:服务器完全无响应,但云监控显示资源使用率极低,这种矛盾现象特别值得注意
2. 排查过程:从绝望到意外的解决
2.1 第一阶段:常规问题排查
我首先按照Docker安装失败的常见原因进行排查:
检查apt源配置:
grep -r "download.docker.com" /etc/apt/确认使用的是阿里云镜像源,且其他节点安装正常
验证依赖完整性:
dpkg --configure -a apt-get -f install在仍能连接的节点执行正常,但卡死的节点无法操作
查看系统日志: 通过阿里云控制台获取串行控制台输出,发现关键日志:
systemd[1]: Starting Docker Application Container Engine... containerd[18956]: time="2023-05-18T07:23:12.123456789Z" level=info msg="starting containerd" revision=v1.5.11
2.2 第二阶段:深入系统层分析
当常规手段无效后,我通过阿里云控制台的VNC功能连接到服务器:
- 发现系统响应极其缓慢,但并非完全死机
- 使用
top命令观察到systemd-journald进程占用异常高的IO等待 - 执行
journalctl -f -u docker.service看到日志停止在:May 18 07:25:03 node3 systemd[1]: Starting Docker Application Container Engine...
2.3 第三阶段:神奇的自动恢复
在准备强制重启前,我决定再等待10分钟。约8分钟后:
- 突然收到Ansible任务完成的邮件通知
- 检查发现Docker服务已正常启动
docker version显示客户端和服务端版本均为20.10.14
3. 根因分析:journald与OverlayFS的隐秘战争
3.1 核心问题定位
通过对比正常节点和问题节点的系统日志,发现关键差异:
| 检查项 | 正常节点 | 问题节点 |
|---|---|---|
| 文件系统类型 | ext4 | overlayfs |
| journald配置 | Storage=auto | Storage=persistent |
| 磁盘IOPS | 3000 | 突发限制500 |
根本原因是:OverlayFS与systemd-journald的持久化日志模式存在兼容性问题,在IO性能受限时会导致进程假死。
3.2 技术细节解析
OverlayFS特性:
- Docker默认使用overlay2存储驱动
- 在Ubuntu上会挂载为/var/lib/docker/overlay2
- 对元数据操作有额外开销
systemd-journald行为:
# /etc/systemd/journald.conf [Journal] Storage=persistent # 默认值,会导致大量小文件IO Compress=yes # 压缩会增加CPU负载阿里云磁盘特性:
- 突发性能实例的基准IOPS仅500
- 当credits耗尽时IO延迟会急剧上升
3.3 问题复现实验
为验证结论,我特意在测试环境复现:
# 模拟低IOPS环境 echo 8 > /sys/fs/cgroup/blkio/blkio.throttle.read_iops_device echo 8 > /sys/fs/cgroup/blkio/blkio.throttle.write_iops_device # 修改journald配置 sed -i 's/Storage=auto/Storage=persistent/' /etc/systemd/journald.conf systemctl restart systemd-journald # 安装docker apt-get install -y docker-ce成功复现了安装卡死现象,平均卡顿时长7分32秒。
4. 解决方案与优化建议
4.1 立即缓解措施
对于已经出现问题的节点:
# 临时解决方案(等待期间执行) journalctl --vacuum-size=50M systemctl restart systemd-journald4.2 长期解决方案
修改journald配置:
# /etc/systemd/journald.conf [Journal] Storage=volatile RuntimeMaxUse=30MAnsible playbook优化:
- name: Configure journald for Docker hosts: k8s_nodes tasks: - lineinfile: path: /etc/systemd/journald.conf regexp: '^Storage=' line: 'Storage=volatile' - lineinfile: path: /etc/systemd/journald.conf regexp: '^RuntimeMaxUse=' line: 'RuntimeMaxUse=30M' - service: name: systemd-journald state: restarted
4.3 预防性措施
云服务器选型:
- 避免使用突发性能实例部署K8s
- 建议选择ESSD云盘,保证稳定IOPS
部署前检查清单:
# 检查文件系统 df -Th /var/lib/docker # 检查IO性能 fio --name=test --filename=/tmp/test \ --size=100M --runtime=60s \ --ioengine=libaio --rw=randrw \ --bs=4k --iodepth=64 --numjobs=4
5. 深度优化:Docker安装的最佳实践
5.1 生产环境推荐配置
# 预配置内核参数 cat <<EOF | tee /etc/sysctl.d/99-docker.conf net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 vm.swappiness = 0 EOF sysctl --system # 使用国内镜像源 curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add - add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" # 安装指定版本 apt-get update && apt-get install -y \ docker-ce=5:20.10.14~3-0~ubuntu-focal \ docker-ce-cli=5:20.10.14~3-0~ubuntu-focal \ containerd.io=1.5.11-15.2 存储驱动选择建议
根据文件系统类型选择最佳驱动:
| 文件系统 | 推荐驱动 | 性能特点 |
|---|---|---|
| ext4 | overlay2 | 稳定性最好 |
| xfs | overlay2 | 适合大规模部署 |
| btrfs | btrfs | 需要专门配置 |
| zfs | zfs | 内存消耗较大 |
5.3 系统调优参数
# 限制Docker日志大小 mkdir -p /etc/docker cat <<EOF | tee /etc/docker/daemon.json { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] } EOF6. 经验总结与避坑指南
6.1 关键教训
- 假死≠真死:现代Linux系统很少真正死机,更多是某个子系统(如IO)的阻塞
- 监控盲区:云监控显示资源利用率低时,可能忽略了IO等待等关键指标
- 默认配置陷阱:Ubuntu的systemd-journald默认配置不适合容器环境
6.2 推荐排查工具
- IO监控:
iostat -x 1 # 查看await指标 - 进程阻塞分析:
strace -p <PID> -T -tt - 内核事件追踪:
perf trace -e block:*
6.3 我的检查清单
现在每次部署前都会执行:
#!/bin/bash # 检查项1:文件系统类型 df -Th | grep -q overlay && echo "警告:根目录使用overlayfs" # 检查项2:IO性能 fio --name=quicktest --filename=/tmp/fiotest \ --size=100M --runtime=10s --ioengine=libaio \ --rw=randrw --bs=4k --iodepth=64 --numjobs=4 \ | grep -A5 "Run status" # 检查项3:journald配置 grep -E "^Storage=|^RuntimeMaxUse=" /etc/systemd/journald.conf这次经历让我深刻体会到:在云环境下,看似简单的Docker安装可能隐藏着各种"环境特异性"问题。现在我的Ansible playbook里永远多了journald的预配置步骤,这大概就是成长的代价吧。