docker-compose.yml是核心配置文件,需指定version(如"3.8")、同自定义网络、服务名作主机名;depends_on仅控启动顺序,须配healthcheck+condition或应用重试才能确保就绪;build用于开发,生产用image;down默认不删卷,清理需加-v。

docker-compose.yml 是你唯一需要写的核心配置文件,其余操作基本靠 docker compose up 和 docker compose down 两条命令闭环完成。不需要手动建网络、记容器名、反复敲 docker run。
怎么写一个能跑通的 docker-compose.yml
关键不是语法多全,而是先让服务之间能互相访问。常见错误是 Web 容器连不上 mysql 或 redis,报 Connection refused 或 getaddrinfo ENOTFOUND。
必须满足三个条件:
-
version字段不能省,推荐用"3.8"(兼容性好,支持deploy和健康检查) - 所有服务必须在同一个自定义网络里,不依赖默认
bridge;显式声明networks并在每个service下挂载 - 服务间调用用服务名当 host 名,比如
redis服务启动后,其他容器里直接连redis:6379,不是localhost:6379
示例最小可用结构:
version: "3.8"
services:
web:
build: .
ports: ["8000:80"]
environment:
- REDIS_URL=redis://redis:6379/0
- DB_HOST=postgres
depends_on:
- redis
- postgres
<p>redis:
image: redis:7-alpine
networks: ["app-network"]</p><p>postgres:
image: postgres:15
environment:
POSTGRES_DB: myapp
POSTGRES_PASSWORD: devpass
volumes: ["pgdata:/var/lib/postgresql/data"]
networks: ["app-network"]</p><p>networks:
app-network:</p><p>volumes:
pgdata:</p>
depends_on 不等于“等它 ready”,只是控制启动顺序
很多人以为加了 depends_on 就能确保 Web 启动时数据库已初始化完毕,实际不是。Docker 只等容器进程起来(postgres 进程 PID 存在),不等它完成建库、执行 init script 或监听端口。结果 Web 应用一上来就连失败,然后崩溃退出。
解决办法只有两个:
- 在应用代码里加重试逻辑(推荐,更健壮)
- 用
healthcheck+condition: service_healthy(Compose v2.1+ 支持)
例如给 postgres 加健康检查:
postgres:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d myapp"]
interval: 30s
timeout: 10s
retries: 5
# … 其他配置
再改 web 的 depends_on:
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
depends_on:
postgres:
condition: service_healthy
本地开发 vs 生产部署,build 和 image 别混用
开发阶段习惯用 build: . 直接构建成镜像,但上线时应避免现场构建——没缓存、耗时长、环境不可控。生产应固定使用 image: myorg/web:v1.2.3。
容易踩的坑:
- 误把
build和image同时写在一个 service 下:Compose 会优先用build,忽略image值 - CI 流水线里没推镜像就直接
docker compose up,报pull access denied - 本地
build用了.dockerignore,但 CI 构建时没同步该文件,导致打包进大量无用文件
建议做法:用 profiles 隔离环境配置,例如:
services:
web:
build: .
image: myorg/web:dev
profiles: ["dev"]
# …
web-prod:
image: myorg/web:${IMAGE_TAG:-latest}
profiles: ["prod"]
启动时指定:docker compose --profile prod up -d
docker compose down 默认不删 volume,数据可能“意外残留”
这是最常被忽略的行为。执行 docker compose down 后,volumes(如上面的 pgdata)不会被删除,下次 up 会复用旧数据。对开发调试方便,但测试环境或 CI 中可能导致状态污染。
如果要彻底清理(比如每次测试都从干净 DB 开始):
- 加
-v参数:docker compose down -v(删关联 volume) - 或者单独删:
docker volume rm $(docker volume ls -q | grep myproject) - 注意:加了
-v会删所有声明的 named volume,包括你本意想保留的日志卷或上传目录,务必确认
真正复杂的点不在语法,而在于你是否清楚每个 service 的生命周期边界、健康就绪条件,以及 volume 数据的归属和清理时机。这些地方一旦模糊,docker compose up 就会变成“看起来启动了,其实一半服务根本没活”。










