容器起来就退出,docker ps 空空如也,别急着重跑
新同事在测试机上部署我们的 order-api, 一条 run 下去没报错,他以为成了。
$ docker run -d --name order-api -p 8080:8080 order-api:1.0
a91c0d2e4f7b
接着 docker ps 一敲,傻眼了:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
表头一个字段都没配上,等于零个容器在跑。
他第一反应是镜像坏了,准备重新 pull 一个 1.7G 的。 我拦住了,这机器上跑不起来基本跟镜像没关系。 测试机是 CentOS 7.9,Docker 20.10.7,同一个镜像在同事笔记本上是能起来的。
排障第一步是 docker ps -a
docker ps 只列在跑的,退出过的它根本不说。 加个 -a 就全出来了:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a91c0d2e4f7b order-api:1.0 "java -jar app.jar" 5 seconds ago Exited (1) 4 seconds ago order-api
STATUS 那列已经告诉我们两件事: 它起来过,四秒后就死了,退出码 1。
退出码 1 是「应用自己抛异常退的」,不是 docker 的问题。 要是那行显示的是 126、127,方向完全不一样,得先去查启动命令本身,那是另一篇的事。
确认是应用自己挂的,就不用再折腾 docker 了,直接看它的日志:
$ docker logs order-api
2026-09-17 14:31:02.470 INFO 1 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2026-09-17 14:31:03.512 ERROR 1 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization.
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago.
The driver has not received any packets from the server.
Caused by: java.net.ConnectException: Connection refused (Connection refused)
中间那四十多行 at 我删了,抄过来也没人看,留头尾就够了。
这一段是 Spring Boot 连不上 MySQL 的标准长相。 HikariPool 初始化炸了,底下 Cause 一层层套到 ConnectException。
看到 ConnectException 就说明应用起来了、配置也读到了,是连不出去, 方向立刻从代码转到网络和环境上。
docker logs 后面加 -f 可以跟着看,加 --tail 200 只看最后两百行。 build 的日志不在这里,那得回 docker build 的输出里翻。
这次的根因是 127.0.0.1
日志里那行 url 是 jdbc:mysql://127.0.0.1:3306/order, 配置是打在 jar 包里带进来的。
他本地一直用 127.0.0.1 连自己的 MySQL, 打成镜像上了容器,这个地址就变味了。
容器里的 127.0.0.1 指的是容器自己,不是宿主机。 MySQL 跑在宿主机的 3306 上,容器里连 127.0.0.1, 等于连了一个自己家里根本没开门的进程,所以是 refused。
这两个报错别混。 refused 是「到是到了,没人听」; timeout 大概率是网络不通,或者被防火墙拦了。 我那台报的是 refused,所以压根没去查安全组。
改法有两条路,我当时给他的是先让服务起来:
$ docker run -d --name order-api -p 8080:8080 \
-e SPRING_DATASOURCE_URL="jdbc:mysql://10.18.18.21:3306/order" \
order-api:1.0
Spring Boot 认环境变量,同名 key 会盖掉 application.yml 里的值,不用重新打镜像。 内网 IP 那台就是宿主机自己,走局域网地址,容器摸得到。
再确认一次它这次是真活着,别只看有没有返回容器 id:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b41f8e19c207 order-api:1.0 "java -jar app.jar" 12 seconds ago Up 8 seconds 0.0.0.0:8080->8080/tcp order-api
STATUS 是 Up 8 seconds,等了 8 秒还没退,才算起来。 我一般多等十几秒再看一次, 有些应用是跑到一半连不上 Redis 才退的,头五秒看着一切正常。
另一种「起来就退」跟这个不一样
上面这种日志里有满屏报错,好查。 麻烦的是 CMD 里那个脚本自己后台化了:
#!/bin/bash
nohup java -jar /app/app.jar &
容器的 1 号进程就是这个脚本,它把 java 扔到后台,自己立刻退出。 脚本一退,容器认为「主进程结束了」,直接收摊, 而 java 进程可能才刚起来,还没打印任何东西。
这种 docker logs 里干干净净,一行错都没有,最容易把人耗住。 要么脚本最后加一行 wait,要么干脆把 CMD 写成前台执行的 java 命令。
我这台的 8080 起来了,接口也通了,就先这么交付。 但 docker ps -a 里那一堆 Exited 的僵尸容器我还得清, 而且退出码不止 1 这一种,125、126、127、137 分别指什么, 我拿几个容器一个个试出来了。

浙公网安备 33010602011771号