做后端开发和运维的朋友,对 Docker 应该都不陌生。但笔者发现,很多人第一次接触 Docker 时,会把“容器运行环境”简单理解成“装个 Docker 就能跑”。结果一上手就各种报错:镜像拉不下来、容器启动秒退、端口死活访问不通……
其实,Docker 容器的运行环境并不是单一的东西,它由 宿主机内核、存储驱动、网络栈、资源限制 这几层共同支撑。任何一层出了问题,容器都跑不起来。下面站长就结合自己踩过的坑,挑几个高频疑问来拆解,希望能帮你少走弯路。
Q1:为什么我的容器启动后立刻退出,docker ps 都看不到?
💡 推荐阅读:Docker 容器一跑就报错?聊聊我踩过的 4 个坑,附排查思路
这是新手最常见的报错之一。你执行了 docker run,看着命令返回了一串容器 ID,结果 docker ps 里空空如也,加上 -a 才看到状态是 Exited (0) 或 Exited (1)。
根因剖析:Docker 容器的生命周期依赖于其主进程(PID 1)。如果主进程执行完就退出了,容器自然跟着结束。比如你跑一个 ubuntu 镜像但没给任何命令,它会启动一个 bash,但没有交互终端,bash 发现没有输入就直接退出。这不是 Docker 坏了,而是你对“容器是一个进程”这个本质理解不够。
另一个常见原因是启动命令本身报错,比如配置文件路径不对、依赖的服务没启动,导致主进程崩溃退出。
解决方案:
# 查看退出容器的日志,这是排查第一步
docker logs <容器ID>
# 以交互模式启动,手动调试
docker run -it --rm ubuntu:22.04 /bin/bash
# 如果你的服务需要常驻,确保启动命令是前台运行的
# 错误示范:CMD service nginx start
# 正确示范:CMD ["nginx", "-g", "daemon off;"]
记住一个原则:容器里的主进程必须以前台方式运行,不能自己 daemon 化。很多官方镜像已经处理好了,但自己写 Dockerfile 时特别容易犯这个错。
Q2:镜像拉取失败,提示 no space left on device,是磁盘满了吗?
💡 延伸阅读:Linux服务器安全防护到底怎么做?别等被挖矿了才后悔没看这篇
这个报错很直白,但背后的原因可能不止一种。笔者有一次在云服务器上部署,磁盘明明还有几十 G,却一直报这个错,折腾了半天才发现是 inode 耗尽 了。
根因剖析:Docker 默认使用 /var/lib/docker 作为数据目录,镜像层、容器层、日志都堆在这里。如果这个分区容量小,或者小文件太多导致 inode 用完,就会触发这个错误。另外,Docker 的存储驱动(如 overlay2)对文件系统有要求,某些老旧的 ext4 或 xfs 配置可能不支持。
解决方案:
# 查看磁盘和 inode 使用情况
df -h
df -i
# 清理无用镜像、容器、卷,这是最安全的做法
docker system prune -a --volumes
# 如果数据目录分区太小,可以迁移到更大的分区
# 编辑 /etc/docker/daemon.json
{
"data-root": "/new/path/docker"
}
# 然后重启 Docker
systemctl restart docker
这里站长多说一句:如果你打算长期跑容器,买云服务器时一定要选 系统盘足够大 的配置,或者单独挂一块数据盘给 Docker 用。别为了省几十块钱选个 20G 系统盘的入门款,后面清理镜像能把你逼疯。
Q3:容器内访问不了外网,ping 域名提示 unknown host,怎么破?
💡 深度技术指南:别再对着价格表瞎蒙了:从架构视角拆解云服务器选型,这套避坑SOP能省下你一半的冤枉钱
这个问题在自建服务器上特别常见,尤其是你手动装过防火墙或者改过网卡配置之后。容器内 ping baidu.com 直接报 unknown host,但宿主机是正常的。
根因剖析:Docker 默认会创建 docker0 网桥,容器通过 NAT 转发访问外网。如果宿主机的 net.ipv4.ip_forward 没开启,或者 iptables 规则被清空、firewalld 拦截了转发流量,容器就出不去。另外,DNS 配置也是重灾区,Docker 默认用宿主机的 /etc/resolv.conf,如果里面是 127.0.0.1 或者不稳定的 DNS,容器内解析就会失败。
解决方案:
# 1. 检查并开启 IP 转发
sysctl net.ipv4.ip_forward
# 如果为 0,则执行:
sysctl -w net.ipv4.ip_forward=1
# 永久生效写入 /etc/sysctl.conf
# 2. 检查 iptables 转发链
iptables -L FORWARD -n
# 如果策略是 DROP,需要放行
iptables -P FORWARD ACCEPT
# 3. 指定可靠的 DNS 启动容器
docker run --dns 223.5.5.5 --dns 8.8.8.8 your-image
# 4. 或者全局配置 DNS,编辑 /etc/docker/daemon.json
{
"dns": ["223.5.5.5", "8.8.8.8"]
}
如果你用的是云服务器,还要检查安全组和 VPC 网络 ACL 是否放行了出方向流量。有些云厂商默认只放行内网,外网访问需要手动开。
Q4:容器内存被 OOM Kill 了,但我明明没限制内存啊?
这个坑笔者印象最深。一个 Java 应用在容器里跑着跑着就没了,docker ps -a 显示 Exited (137),日志里啥也没有。查了半天才发现是被系统 OOM Killer 干掉了。
根因剖析:Docker 容器默认可以使用宿主机的全部内存,但如果没有设置 -m 限制,容器内的进程可能因为宿主机内存不足而被内核杀掉。更隐蔽的是,Java 这类应用会根据 宿主机 的总内存来设置堆大小,而不是容器的限制。比如宿主机 16G,你给容器限了 2G,但 JVM 以为有 16G 可用,堆直接开到 4G,一跑就超,被 OOM Kill。
解决方案:
# 启动时明确限制内存和 swap
docker run -m 2g --memory-swap 2g your-image
# 对于 Java 应用,使用容器感知的参数
java -XX:MaxRAMPercentage=75.0 -jar app.jar
# 或者显式指定堆大小
java -Xmx1536m -jar app.jar
# 查看容器被 OOM 的记录
docker inspect <容器ID> | grep OOMKilled
dmesg | grep -i "killed process"
另外建议在 daemon.json 里开启 oom-score-adj 调整,或者用 --oom-kill-disable 禁用 OOM(但可能导致宿主机卡死,慎用)。更好的做法是给容器设置合理的资源限制,并监控内存使用。
预防建议:让容器运行环境更稳的几个习惯
- 选对宿主机系统:生产环境优先用 Ubuntu LTS 或 Debian,内核版本建议 5.4 以上,对 overlay2 和 cgroup v2 支持更好。
- 数据目录独立分区:把
/var/lib/docker挂到单独的数据盘,避免镜像撑爆系统盘。 - 明确资源限制:每个容器都加上
-m和--cpus,防止单个服务拖垮整台机器。 - 日志驱动配置:默认的 json-file 日志会无限增长,在
daemon.json里加上log-opts限制大小和文件数。 - 基础镜像选精简版:优先用
alpine或distroless,减少攻击面,也省磁盘。
最后提醒一句,如果你正准备买服务器来跑 Docker,别贪便宜选那种超售严重的廉价 VPS。容器对 I/O 和内存比较敏感,超售机器上跑起来各种玄学问题。选个口碑好的云厂商,配置至少 2 核 4G 起步,磁盘用 SSD,这样你的容器运行环境才有个靠谱的地基。
好了,以上就是站长在 Docker 运行环境上踩过的一些坑和对应的解法。如果你也遇到过其他奇葩报错,欢迎一起交流,咱们评论区见。
相关技术专题与延伸阅读
- Docker 容器一跑就报错?聊聊我踩过的 4 个坑,附排查思路
- Linux服务器安全防护到底怎么做?别等被挖矿了才后悔没看这篇
- 别再对着价格表瞎蒙了:从架构视角拆解云服务器选型,这套避坑SOP能省下你一半的冤枉钱
- 你的服务器真的安全吗?一套拿来就能用的Linux加固SOP,从裸机到堡垒机
📦 【资源免费领】本文全套实操配置文件与避坑手册下载
本文涉及的全套 Docker Compose 配置文件、服务器运维避坑清单及 AI 提效指令库已完整打包,可免费极速转存:
💡 提示:推荐使用手机【夸克网盘 App】打开保存,新用户首月免费赠送 1TB 超大空间与免流量极速下载特权。