1. 问题现象与初步排查
最近在Ubuntu 20.04服务器上安装Docker后,遇到了一个奇怪的问题:系统运行一段时间后,SSH连接突然中断且无法重新连接。作为运维人员,这种情况着实让人头疼。通过监控系统发现,问题通常出现在Docker容器运行约2-3小时后,此时不仅SSH连接失败,连本地控制台登录也会出现延迟。
首先检查了最基本的网络连通性:
bash复制ping 服务器IP
发现网络层通信正常,排除了防火墙和网络设备的问题。接着尝试通过控制台直接登录服务器,发现虽然能登录但响应极慢,这提示我们可能是系统资源出现了问题。
重要提示:当SSH连接不上时,首先应该确认是连接拒绝(Connection refused)还是连接超时(Connection timed out),这两种现象指向不同的故障方向。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Docker与系统资源冲突分析
2.1 内存泄漏嫌疑
通过查看系统日志(/var/log/syslog)发现,在SSH断开前,内核频繁输出OOM(Out Of Memory)相关消息。使用以下命令确认内存使用情况:
bash复制free -h
cat /proc/meminfo
发现可用内存确实在不断减少,最终耗尽。进一步使用top命令观察进程内存占用,发现dockerd进程的内存使用量异常增长。
2.2 容器资源限制缺失
检查运行的Docker容器配置,发现没有设置内存限制:
bash复制docker stats --no-stream
结果显示某些容器内存使用量持续增长。这是典型的内存泄漏症状,特别是一些Java应用容器,如果没有正确配置JVM内存参数,很容易吃光主机内存。
2.3 系统关键服务被挤占
当系统内存不足时,Linux内核的OOM Killer会开始终止进程。通过以下命令可以查看最近的OOM事件:
bash复制dmesg | grep -i oom
发现sshd进程多次被杀死,这就是SSH连接不上的直接原因。因为SSH服务需要保持长连接,对系统稳定性要求较高。
3. 问题解决方案实施
3.1 为容器设置资源限制
对所有运行中的容器添加内存限制:
bash复制docker update --memory 512m --memory-swap 1g <容器名>
对于新创建的容器,应该在运行时就直接指定:
bash复制docker run -d --name myapp --memory 512m --memory-swap 1g myimage
3.2 调整系统OOM优先级
通过修改sshd的OOM分数调整,降低其被杀死的概率:
bash复制echo -1000 > /proc/$(pgrep sshd)/oom_score_adj
为了使设置永久生效,可以创建systemd服务配置:
ini复制# /etc/systemd/system/sshd.service.d/override.conf
[Service]
OOMScoreAdjust=-1000
3.3 监控与告警设置
安装监控工具如Prometheus+Grafana,设置内存使用告警。也可以使用简单的cronjob定期检查:
bash复制*/5 * * * * root [ $(free -m | awk '/Mem:/ {print $4}') -lt 100 ] && wall "内存不足警告!"
4. 深入排查与优化建议
4.1 容器内存泄漏定位
对于疑似内存泄漏的容器,可以使用以下命令深入分析:
bash复制docker exec -it <容器名> bash
top -o %MEM
或者使用更专业的工具:
bash复制docker stats --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
4.2 系统参数调优
调整内核参数,优化内存管理:
bash复制# 增加overcommit比例
sysctl -w vm.overcommit_memory=1
sysctl -w vm.overcommit_ratio=95
# 调整swappiness
sysctl -w vm.swappiness=10
4.3 替代方案考虑
如果问题持续,可以考虑:
- 使用轻量级容器运行时如containerd替代Docker
- 迁移到Kubernetes集群,利用其更完善的资源管理
- 对关键业务系统使用独立物理服务器
5. 预防措施与最佳实践
5.1 容器资源管理规范
建议建立容器资源使用规范:
- 所有容器必须设置内存限制
- 生产环境容器必须设置CPU限制
- 定期审计容器资源使用情况
5.2 系统监控方案
实施全面的监控方案应该包括:
- 基础资源监控(CPU/内存/磁盘/网络)
- 容器层面监控
- 应用层面监控
- 日志集中收集与分析
5.3 应急响应流程
制定SSH连接失败的应急流程:
- 通过控制台或带外管理登录
- 检查系统日志和Docker日志
- 必要时重启Docker服务
- 优先恢复关键业务
经过上述调整和优化后,我们的服务器已经稳定运行超过两周,没有再出现SSH连接不上的情况。这个案例让我深刻体会到,在容器化环境中,资源隔离和限制配置绝不是可有可无的选项,而是必须严格执行的生产规范。特别是在共享主机环境下,一个失控的容器就可能影响整个系统的稳定性。
