容器起不来,多数情况下不是Docker本身的问题,而是镜像配置、资源限制、端口冲突和应用启动命令四类原因在作怪,下面按优先级逐步拆解。
docker容器启动失败原因:镜像与配置层面的隐患
镜像名或标签写错,容器自然拉不起来
排查一个容器为什么不启动,第一步先看镜像是否存在,常见的低级错误是把镜像标签写错,比如把nginx:1.25写成nginx:1.25.1,又或者直接写latest而在私有仓库里根本没有这个标签,执行docker pull会直接报错,这种错误通常一眼能看出来。
平台架构不匹配,镜像能拉下来却跑不动
不少开发者遇到过这样的情况:在Mac上构建的镜像,部署到云服务器上却起不来,行业共识认为,绝大多数镜像需要和宿主机CPU架构一致,ARM架构的镜像跑在x86服务器上,Docker会提示exec format error,先用uname -m确认架构,再用docker inspect查看镜像的架构字段,基本能定位。
环境变量缺失,应用启动前就崩溃
很多容器需要读取环境变量才能正常工作,比如数据库连接串、Redis地址、密钥等,如果启动时漏传-e参数,应用可能在初始化阶段直接退出,容器状态会显示Exited(0)或Exited(1),这类问题靠肉眼看不出来,必须进容器里看实际报错。
挂载目录权限不够,容器启动时报权限错误
把宿主机目录挂载进容器是常见操作,但宿主机目录的属主和权限如果不对,容器内进程可能没有写权限,例如用-v /data:/app挂载后,应用尝试写/app/logs却无权限,直接抛异常退出,解决办法是调整宿主机目录权限,或者用Z标签(适用于SELinux环境)重新挂载。
容器起不来怎么办:先查资源限制与竞态冲突
内存超限触发OOM,容器反复重启
一个典型场景:应用在本地跑得好好的,打包成容器后放到服务器上就不断重启,打开docker inspect看OOMKilled字段,如果为true,说明容器被内核标记为OOM被杀。多数情况下,使用-m 512m这类硬限制时,JVM或Node进程的堆内存设置过大会直接撞墙,排查时用docker stats观察内存曲线,再调整-m参数。
磁盘空间被日志占满,容器无法写入
容器起不来还有一类容易被忽略的原因:宿主机的overlay2分区满了。df -h看一眼使用率,如果超过90%,镜像层或日志文件会写不进去,清理方法很直接:
- 用
docker system prune -a清理无用镜像和悬空镜像 - 检查
/var/lib/docker/containers下的json日志文件大小 - 为Docker配置
log rotation限制单容器日志上限
端口被占用,绑定直接失败
启动容器时如果指定了-p 8080:80,而宿主机8080端口已经被别的进程占用,Docker会返回bind: address already in use,这个问题很常见,特别是同一个服务器上部署了多个项目时,用netstat -tlnp | grep 8080找到占用进程,把冲突端口让出来,或者换一个宿主机端口。
应用自身的问题,才是很多人排查不到位的死角
依赖服务没就绪,容器先于依赖启动
不少业务容器启动时需要连数据库、Redis或注册中心,如果依赖的服务还没就绪,应用会报连接超时然后退出,这种现象看着像应用崩溃,实际上是指挥顺序不对,业界常用两种办法:
- 启动命令里加等待脚本,轮询依赖端口
- 在Docker Compose中配置
depends_on和healthcheck
退出码才是真相,先学会读它
看到容器退出,别急着删掉重来,执行docker inspect <容器名> --format='{{.State.ExitCode}}',退出码的含义能告诉你力气该往哪里使:
0:应用正常退出,多半是配置或启动参数导致应用自行结束1:应用初始化失败,看日志找具体异常137:被SIGKILL杀死,大概率是OOM或手动kill143:被SIGTERM终止,常见于优雅退出流程没走完
有经验的工程师会第一时间取日志,命令是docker logs <容器名> --tail 200,多数启动失败的原因都写在日志前几行里。
容器进来就退出是什么原因,用交互模式确认
如果镜像能跑但进程立刻退出,手动起一个临时容器进去验证是最高效的方式,以mysql为例,执行:
docker run -it --rm mysql:8.0 bash
进去后看配置文件、校验启动命令、手动启动进程,观察报错输出,这样比反复修改镜像重新构建快得多。
两个容易忽略的综合场景
docker compose编排时相互依赖导致的连锁失败
在docker compose场景中,多个服务一起启动时,如果一个基础服务(如网关)没起来,下游服务会连环失败,这类问题排查时先看整体状态:
docker compose ps查看各服务状态- 按依赖顺序逐个
docker compose up - 利用
healthcheck让依赖服务的探针通过后再拉起下游
云服务器docker容器启动失败,优先看安全组和系统参数
在云服务器上部署容器,多了两道额外的关卡:安全组规则和内核参数,安全组没放行宿主机端口,容器听不到外网请求,表现为端口不通;sysctl参数受限会导致应用创建线程失败,表现为不明原因的崩溃,遇到这类情况,去云控制台检查安全组入方向规则,再用
cat /proc/sys/kernel/threads-max确认系统线程配额是否够用。
容器启动失败排查步骤,按这个顺序做不会错
- 第一步:看状态。
docker ps -a确认容器是Exited还是Restarting - 第二步:看日志。
docker logs取最近200行,找异常堆栈 - 第三步:看退出码。
docker inspect读ExitCode和OOMKilled - 第四步:看资源。
df -h和free -m确认磁盘与内存 - 第五步:看冲突。
netstat确认端口未被占用
按照这个流程走下来,相当一部分容器起不来的问题都能在十分钟内定位,如果所有步骤都查过仍无头绪,那就是启动命令本身的问题,老老实实进容器手动跑一遍,找到缺失的那个细节,比反复猜要快得多。
常见问题解答
容器状态一直显示Restarting是什么意思
Restarting表示容器内的主进程不断崩溃,Docker按照重启策略不断拉起它,原因是主进程退出,不是Docker服务本身的问题,先docker logs看崩溃原因,再看docker inspect确认重启策略是否设置为always或unless-stopped,如果没有明确的崩溃日志,大概率是OOM,检查OOMKilled字段。
容器启动后立即退出,退出码为0是什么原因
退出码为0说明应用正常返回,主动结束了进程,常见场景:启动命令里执行了前台脚本,但脚本最后调用了exit或return;或者应用读取不到配置直接走了正常退出分支,用docker logs看最后几行输出,通常能找到退出的触发点,如果在等待外部信号,检查CMD是否忘了加-daemon或前台运行参数。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/639126.html





