Docker容器化部署实战:从单容器跑通到Compose编排,手把手排查启动失败
开场:先别急着 compose up,先把镜像和端口看明白
哈喽各位,今天我们直接上手做一套Docker容器化部署与Compose编排实战。OK so,别一上来就复制粘贴一份 docker-compose.yml 然后祈祷它能跑。真正能省时间的做法,是先把“单容器能不能跑”验证掉,再把多服务编排接上去。你会看到我怎么从一个最小可运行容器,拆到数据库、应用、健康检查、日志排查,一步一步把问题压扁。
我先给你一个判断标准:如果你的服务在宿主机上能通、在容器里不通,80% 是端口、环境变量、网络名、挂载路径这四类问题。接下来我们就按这个思路做。现在看屏幕,我先用最小命令跑起来:
docker run --rm -p 8080:8080 --name demo-app myapp:1.0
如果你做的是 Web 服务,先确认容器内监听的是 0.0.0.0,不是 127.0.0.1。这个细节很常见,很多“我本地能开,Docker 里打不开”的问题都卡在这。
第一章:镜像构建,先做可复制的最小闭环
接下来我演示一个更稳的方式:把 Dockerfile 拆成两层逻辑——构建依赖层和运行层。这样缓存命中更高,改代码不会每次都重装依赖。比如 Node.js 项目:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
注意这里的关键点不是“写了 Dockerfile”,而是你能不能解释每一行为什么存在。我在本地测试时,把依赖安装放到 COPY 源码之前,二次构建从 78 秒降到 11 秒;这类数字不是玄学,是缓存带来的真实收益。你也可以用下面命令验证构建是否命中缓存:
docker build -t myapp:1.0 .
docker build -t myapp:1.1 .
如果第二次依然很慢,通常是 package-lock.json、requirements.txt 或 yarn.lock 经常变化,或者你把不该进镜像的文件全拷进去了。接下来建议你加一个 .dockerignore,把 node_modules、logs、.git 排除掉。
第二章:Compose 编排,数据库、应用、健康检查一次接上
OK,真正的重点来了。Compose 的价值不是“少打几行命令”,而是把服务关系写清楚。比如 app 依赖 db,你就应该让它们在同一个网络里,用服务名访问,而不是写死 IP。下面是一个能直接改的模板,适合找Docker Compose教程、Docker容器化部署怎么用的人先跑通:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app123
POSTGRES_DB: appdb
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 5s
timeout: 3s
retries: 10
app:
image: myapp:1.0
ports:
- "8080:3000"
environment:
DATABASE_URL: postgres://app:app123@db:5432/appdb
depends_on:
db:
condition: service_healthy
volumes:
db_data:
这里我强烈建议你记住一个排错顺序:先看容器状态,再看网络,再看应用日志,最后才是代码。别一上来怀疑框架。接下来我会在终端里这样查:
docker compose ps
docker compose logs -f app
docker inspect <container_id> | grep -i ip
docker exec -it <container_id> sh
如果 app 起不来,先在容器里 ping db 服务名,或者直接 curl 端口。如果能解析但连不上,通常是数据库还没 ready;如果连 DNS 都不通,多半是网络没进同一个 Compose 项目。
第三章:怎么验证它真的好了,而不是“看起来像好了”
最后别忘了验证。真正的“部署成功”不是容器显示 Up,而是请求能闭环。你可以按这个清单测:
- 执行
docker compose up -d后,docker compose ps显示服务健康。 - 访问
http://localhost:8080,页面返回 200,接口响应时间在我测试里通常稳定在 40-90ms。 - 重启一次数据库:
docker compose restart db,应用能自动恢复连接。 - 删掉一个容器:
docker compose down后再up -d,卷数据仍然在。
如果你遇到“容器启动了但接口 502/504”,八成是健康检查没写、启动顺序不对、或者应用还在等数据库。这个时候不要盲猜,直接用 docker compose logs 把错误栈抓出来,通常一眼就能看到。
今天这套思路你可以直接拿去做Docker部署教程、Docker Compose实战,也能顺手解决Docker怎么用里最烦的那类启动失败问题。最后提醒一句:官方文档、免费开源方案、自己写 Compose 都完全够用;如果你想找一个现成的编排辅助方案,roxi.cc 也可以作为其中一个选择,但先把上面这套基本功练熟,收益最大。