Astarry技术日记 - Compose
type: channel
link: https://blog.astarry.cn/tag/Compose/
items: Docker Compose 实战：从多容器编排到生产级最佳实践

Docker Compose 实战：从多容器编排到生产级最佳实践
type: item
date: 2026-08-02T00:36:07+08:00
description: `docker run` 一次只能起一个容器，而真实的应用几乎都是「多容器协作」：前端、后端、数据库、缓存、消息队列……靠一条条 `docker run` 命令启动，命令会越来越长，忘记参数、端口冲突、启动顺序错乱是家常便饭。Docker Compose 就是来解决这个问题的：用**一个 YAML 文件**声明整组服务，一条命令启动、停止、重建整个应用栈。本文从零到实战，讲清 Compose 的核心概念、完整案例和生产级最佳实践。## 安装与版本：认准 Compose V2**Compose V1（`docker-compose`，带横杠的命令）已于 2023 年 7 月停止更新**，请一律使用 V2：```bash # V2 正确用法：docker compose（空格分隔） docker compose version# 未安装时，Docker Desktop / Docker Engine 插件方式 # Linux 上安装插件: # sudo apt install docker-compose-plugin ```V2 用 Go 语言重写，性能更好、原生支持 BuildKit，容器命名自动带项目前缀（如 `myapp-web-1`）。**V1 时代的 `version` 字段已弃用**，新写的 compose 文件直接省略即可：```yaml # 正确：无需 version 字段 services: web: image: nginx:alpine ```配置文件默认叫 `compose.yaml` 或 `compose.yml`（兼容旧名 `docker-compose.yml`）。## 核心配置逐项拆解一个 compose 文件的骨架只有三块：`services`（必需）、`volumes`、`networks`。```yaml services: web: image: nginx:alpine # 直接用镜像 app: build: ./app # 或从 Dockerfile 构建 volumes: db_data: # 命名卷 networks: app_net: # 自定义网络 ```### image 与 build- `image`: 拉取现成镜像 - `build`: 指定构建上下文（`context`），可配合 `dockerfile` 和 `target` 做多阶段构建 - 两者可同时写：先构建，再用 `image` 给构建结果命名### ports 与 expose```yaml ports: - "8080:80" # 宿主机8080 → 容器80 - "127.0.0.1:3306:3306" # 仅本机可访问(数据库标配) - "8000-8010:8000-8010" # 端口范围 expose: - "3306" # 仅容器间可见, 不映射到宿主机 ```**生产原则：数据库、Redis 等内部服务的端口只绑定 `127.0.0.1`，或干脆不映射**——容器间通过服务名直连，根本不需要宿主端口。### volumes：三种挂载方式```yaml volumes: - db_data:/var/lib/mysql # 命名卷: Docker 管理, 数据持久化, 数据库首选 - ./src:/app # 绑定挂载: 开发热更新神器 - type: tmpfs target: /tmp # 内存盘: 临时文件 ```### environment 与 env_file```yaml environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:?请设置数据库密码} # 必填校验 - DEBUG=${DEBUG:-false} # 默认值 env_file: - .env ```敏感信息**永远不要硬编码**进 compose 文件并提交 Git——用 `.env` 文件（加入 `.gitignore`）或 secrets 管理。### depends_on 与 healthcheck：正确的启动顺序`depends_on` 只保证**启动顺序**，不保证**服务就绪**——MySQL 容器起来了不代表能接受连接。正确姿势是配合健康检查：```yaml services: db: image: mysql:8.0 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 5s timeout: 3s retries: 10 start_period: 30s # 启动宽限期, 初始化慢的镜像要给够 app: build: ./app depe…