This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/gyh/docker/docker-compose使用指南.md

831 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags:
- docker
- devops
- containerization
- docker-compose
create time: 2026-04-28 14:35
---
# Docker Compose 使用指南
> 用 **YAML 文件**定义多容器应用,一条 `docker compose up` 启动所有服务。从"一条命令跑起全栈"到多环境编排,本文带你掌握 Compose 从入门到进阶的所有关键能力。
## 概述
Docker Compose 的核心价值:**把分散的 `docker run` 命令变成声明式的 YAML 配置**,让团队用同一份文件即可启动完整应用栈。
> [!tip] 快速上手(TL;DR)
>
> ```bash
> # 1. 写好 docker-compose.yml,包含所有服务
> # 2. 一条命令启动全部
> docker compose up -d
> # 3. 看日志、看状态
> docker compose logs -f
> docker compose ps
> # 4. 清理
> docker compose down
> ```
> [!question] 什么时候需要 Compose?
> 如果你的应用只跑一个进程(比如单个 Nginx),`docker run` 就够了。但只要涉及**两个及以上**的容器协作(应用 + 数据库、前端 + API + 缓存),Compose 就是标配。
## 正文
### 一、Compose 文件结构
Compose 文件由三个顶级字段构成,理解它们就能掌握 80% 的配置:
```mermaid
flowchart LR
A["services — 要跑的服务"] --> D["docker compose up"]
B["networks — 服务间的网络"] --> D
C["volumes — 数据持久化"] --> D
style A fill:#e3f2fd
style B fill:#f3e5f5
style C fill:#e8f5e9
```
基本结构示例:
```yaml
# docker-compose.yml
services:
web: # 前端/后端应用
db: # 数据库
redis: # 缓存
nginx: # 反向代理
networks: # 网络定义
volumes: # 数据卷定义
```
> [!note] `version` 字段已弃用
> Compose V2(2020年起)已不需要 `version` 字段。新项目直接用无 version 的新格式,兼容性更好。
---
### 二、完整示例:Node.js + MySQL + Redis 全栈项目
一个生产级别的 Compose 文件应该包含**健康检查、网络隔离、数据持久化**:
```yaml
services:
# ========== 后端应用 ==========
api:
build:
context: ./server
dockerfile: Dockerfile
args:
NODE_ENV: production
target: production
container_name: my-api
ports:
- "3000:3000"
environment:
NODE_ENV: production
DB_HOST: db
DB_PORT: 3306
DB_USER: root
DB_PASSWORD: root123
DB_NAME: mydb
REDIS_HOST: redis
REDIS_PORT: 6379
depends_on:
db:
condition: service_healthy # 等 db 健康检查通过再启动
redis:
condition: service_started
restart: unless-stopped
networks:
- app-network
volumes:
- api-logs:/app/logs
# ========== 前端应用 ==========
web:
build:
context: ./client
dockerfile: Dockerfile
container_name: my-web
ports:
- "80:3000"
depends_on:
- api
restart: unless-stopped
networks:
- app-network
# ========== 数据库 ==========
db:
image: mysql:8.0
container_name: my-db
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: mydb
MYSQL_USER: admin
MYSQL_PASSWORD: admin123
ports:
- "3306:3306"
volumes:
- db-data:/var/lib/mysql
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped
networks:
- app-network
# ========== 缓存 ==========
redis:
image: redis:7-alpine
container_name: my-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
restart: unless-stopped
networks:
- app-network
# ========== 反向代理 ==========
nginx:
image: nginx:alpine
container_name: my-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
- api
restart: unless-stopped
networks:
- app-network
# ========== 网络 ==========
networks:
app-network:
driver: bridge
# ========== 数据卷 ==========
volumes:
db-data:
redis-data:
api-logs:
```
> [!warning] 服务启动顺序
> 理解这个示例的启动链:**db + redis 先启动 → api 启动(依赖它们就绪)→ web 启动(依赖 api 就绪)→ nginx 启动(依赖前端和后端)**。用 `depends_on` + `healthcheck` 确保这个顺序。
---
### 三、常用配置详解
#### 3.1 `build` — 从 Dockerfile 构建
> [!info] build 与 image 的选择
> 开发环境通常用 `build`(代码改动自动重构建),生产环境可以用 `image`(提前打好镜像推送仓库)。
```yaml
services:
# 方式一:当前目录(自动找 Dockerfile)
web:
build: .
# 方式二:指定上下文和 Dockerfile
web:
build:
context: ./frontend
dockerfile: Dockerfile.prod
# 方式三:加构建参数 + 多阶段指定目标
web:
build:
context: .
dockerfile: Dockerfile
args:
NODE_ENV: production
VERSION: 1.0.0
target: production
# 方式四:直接用已有镜像(不构建)
db:
image: mysql:8.0
```
#### 3.2 `depends_on` — 启动顺序
```yaml
services:
api:
depends_on:
db:
condition: service_healthy # 等 db 健康检查通过
redis:
condition: service_started # 等 redis 启动即可
```
> [!note] depends_on 的真相
> `depends_on` 只管**启动顺序**,不管**可用性**。不加 `healthcheck` 时,容器"已启动"不代表服务"已就绪"。数据库可能需要几秒初始化才能接受连接。
#### 3.3 `healthcheck` — 健康检查
> [!tip] 为什么数据库必须配健康检查?
> 容器启动 ≠ 服务就绪。MySQL 启动后可能要跑初始化脚本,`start_period` 就是给这段缓冲时间。
```yaml
services:
db:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s # 每 10 秒检查一次
timeout: 5s # 超时时间
retries: 5 # 最多重试 5 次
start_period: 30s # 启动后等 30 秒才开始检查
```
**常见健康检查命令速查:**
| 服务 | 健康检查命令 |
|------|-------------|
| MySQL | `mysqladmin ping -h localhost` |
| Redis | `redis-cli ping` |
| Node.js | `wget -qO- http://localhost:3000/health` |
| Nginx | `curl -f http://localhost/` |
| PostgreSQL | `pg_isready -h localhost` |
#### 3.4 `environment` — 环境变量
```yaml
# 方式一:列表格式(简洁)
environment:
- NODE_ENV=production
- DB_HOST=db
# 方式二:字典格式(推荐,更易读,支持类型)
environment:
NODE_ENV: production
DB_HOST: db
DB_PORT: 3306
# 方式三:从 .env 文件加载(最推荐)
env_file:
- .env.production
# 混合使用
environment:
NODE_ENV: production
DB_HOST: db
env_file:
- .env
```
#### 3.5 `volumes` — 数据持久化
```yaml
volumes:
# 命名卷(推荐,Docker 自动管理)
- db-data:/var/lib/mysql
# 绑定挂载(绑定宿主机路径,开发用)
- ./data:/app/data
# 只读挂载(配置文件)
- ./nginx.conf:/etc/nginx/nginx.conf:ro
# 匿名卷(不需要命名)
- /tmp/data
```
> [!abstract] 命名卷 vs 绑定挂载
> - **命名卷**:Docker 管理存储位置,更安全,推荐生产环境用
> - **绑定挂载**:直接映射宿主机路径,开发方便但可能跨平台不兼容
#### 3.6 `restart` — 重启策略
```yaml
restart: always # 永远重启(包括手动停止后也重启)
restart: on-failure # 仅失败时重启
restart: unless-stopped # 除非手动停止,否则重启(推荐)
restart: no # 不自动重启(默认)
```
#### 3.7 `ports` vs `expose`
```yaml
ports:
- "8080:80" # 宿主端口:容器端口(外部可访问)
- "127.0.0.1:8080:80" # 仅本地可访问(安全)
- "3000" # 随机端口
expose:
- "3000" # 仅容器间通信,外部不可访问
```
> [!danger] 安全警告
> 数据库**不要暴露 `ports` 到宿主机**!用 `expose` 或同网络即可,避免被外部直接访问。
---
### 四、多环境配置
> [!abstract] 多环境策略
> 核心思路:**一份基础配置 + 环境差异覆盖**,而不是为每个环境写完整文件。
#### 4.1 覆盖文件(推荐)
```yaml
# docker-compose.yml(开发环境基础配置)
services:
api:
build: .
environment:
NODE_ENV: development
volumes:
- ./server:/app # 开发热重载
```
```yaml
# docker-compose.prod.yml(生产覆盖)
services:
api:
environment:
NODE_ENV: production
volumes: [] # 生产时不挂载宿主机目录
```
```bash
# 组合使用
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```
#### 4.2 环境变量控制(简洁)
```yaml
# docker-compose.yml
services:
api:
build: .
environment:
NODE_ENV: ${NODE_ENV:-development}
DB_HOST: ${DB_HOST:-db}
volumes:
- ${MOUNT_VOLUMES:-./server:/app}
```
```bash
# 开发环境(默认值)
docker compose up -d
# 生产环境
NODE_ENV=production MOUNT_VOLUMES="" docker compose up -d
```
---
### 五、常用命令
| 操作 | 命令 |
|------|------|
| 启动全部(后台) | `docker compose up -d` |
| 启动全部(前台看日志) | `docker compose up` |
| 启动单个服务 | `docker compose up -d db redis` |
| 停止全部 | `docker compose stop` |
| 停止并删除容器 | `docker compose down` |
| 删除容器 + 网络 | `docker compose down --rmi all` |
| 代码改动后重建 | `docker compose up -d --build` |
| 删除容器 + 数据卷 | `docker compose down -v` |
| 查看服务状态 | `docker compose ps` |
| 查看日志 | `docker compose logs -f` |
| 进入容器 | `docker compose exec api bash` |
| 单次执行命令 | `docker compose run --rm web npm test` |
| 拉取新镜像 | `docker compose pull` |
---
### 六、常见问题
#### 6.1 容器间无法互相访问
```yaml
# 确保所有服务在同一网络下
services:
api:
networks: [app-network]
db:
networks: [app-network]
networks:
app-network:
driver: bridge
```
> [!note] 默认网络
> 同一个 Compose 文件下的服务**默认在同一网络**,可以互相通过服务名访问。不同 Compose 文件的容器不能互相访问。
#### 6.2 数据库启动慢,应用连不上
```yaml
services:
api:
depends_on:
db:
condition: service_healthy # 健康检查通过才启动
```
或在应用代码中添加重试逻辑(指数退避)。
#### 6.3 端口冲突
```bash
# 查看端口占用
netstat -ano | findstr :3000 # Windows
lsof -i :3000 # macOS/Linux
```
修改 `docker-compose.yml` 中的端口映射:
```yaml
ports:
- "3001:3000" # 宿主机 3001 → 容器 3000
```
#### 6.4 `.env` 文件
```bash
# 在项目根目录创建 .env 文件
DB_HOST=db
DB_PASSWORD=root123
NODE_ENV=production
COMPOSE_PROJECT_NAME=myapp
```
> [!info] 自动读取
> Docker Compose 会**自动读取**当前目录的 `.env` 文件,`$DB_HOST` 在 `docker-compose.yml` 中会被自动替换。
---
### 七、常用模板速查
#### 7.1 纯前端静态站点(Nginx)
```yaml
services:
web:
build: .
ports: ["80:80"]
restart: unless-stopped
```
#### 7.2 Node.js + PostgreSQL
```yaml
services:
app:
build: .
ports: ["3000:3000"]
environment:
DATABASE_URL: postgresql://user:pass@db:5432/mydb
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
volumes:
pg-data:
```
#### 7.3 Next.js 全功能模板
```yaml
services:
app:
build:
context: .
dockerfile: Dockerfile
target: production
ports: ["3000:3000"]
environment:
NODE_ENV: production
DATABASE_URL: $DATABASE_URL
NEXTAUTH_SECRET: $NEXTAUTH_SECRET
restart: unless-stopped
networks: [app-network]
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: app
POSTGRES_PASSWORD: $DB_PASSWORD
volumes: [pg-data:/var/lib/postgresql/data]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
networks: [app-network]
redis:
image: redis:7-alpine
volumes: [redis-data:/data]
networks: [app-network]
networks:
app-network:
volumes:
pg-data:
redis-data:
```
---
### 八、Compose 文件格式演进
> [!tip] 新项目直接用新格式
> Compose V2 起默认使用 Compose Specification 格式,不再需要 `version` 字段。
```yaml
# 新版写法(推荐)
services:
app:
image: node:20-alpine
ports:
- "3000:3000"
environment:
NODE_ENV: production
networks:
default:
driver: bridge
volumes:
data:
```
| 对比项 | V3 及以下(旧) | V4+ / Compose Specification(新) |
|--------|----------------|--------------------------------|
| `version` 字段 | 必须写 | 不需要 |
| 命令 | `docker-compose`(连字符) | `docker compose`(空格) |
| 字段格式 | 点号分隔 | YAML 嵌套格式 |
---
### 九、高级配置
#### 9.1 `deploy` — 资源限制
```yaml
services:
api:
image: my-api:latest
deploy:
replicas: 3 # 副本数(Swarm 模式)
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
resources:
limits:
cpus: '0.5' # 最多 0.5 核 CPU
memory: 512M # 最多 512MB 内存
reservations:
cpus: '0.25'
memory: 128M
```
> [!warning] 注意
> `deploy` 的 `replicas`、`update_config` 在 `docker compose up`(非 Swarm)下**不生效**。但 `resources.limits/reservations` 在普通模式下仍然有效。
#### 9.2 `profiles` — 按需启停服务
```yaml
services:
web:
image: nginx:alpine
profiles: ["app"]
db:
image: postgres:16-alpine
profiles: ["db", "app"]
redis:
image: redis:7-alpine
profiles: ["cache", "app"]
monitoring:
image: grafana/grafana
profiles: ["monitoring"]
```
```bash
# 只启动 app 相关服务(web + db + redis)
docker compose --profile app up -d
# 启动 app + 监控
docker compose --profile app --profile monitoring up -d
# 启动所有服务(包括无 profile 的)
docker compose up -d
```
#### 9.3 `configs` — 配置文件管理
```yaml
services:
nginx:
image: nginx:alpine
configs:
- source: nginx_conf
target: /etc/nginx/conf.d/default.conf
mode: 0444
configs:
nginx_conf:
file: ./configs/nginx.conf
```
#### 9.4 `secrets` — 敏感信息管理
```yaml
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_pass
secrets:
- db_root_pass
secrets:
db_root_pass:
file: ./secrets/db_root_pass.txt
db_config:
string: '{"max_connections": 100}'
```
> [!danger] 安全建议
> 敏感信息不要写死在 `docker-compose.yml` 中,使用 `secrets` 或 `.env` 文件管理。
#### 9.5 其他实用配置
```yaml
services:
app:
image: node:20-alpine
# 指定运行用户
user: "1000:1000"
# 工作目录
working_dir: /app
# 覆盖默认入口点和命令
entrypoint: ["node"]
command: ["server.js"]
# 容器别名
container_name: my-app
# 标签(元数据)
labels:
- "com.example.description=API Server"
# 时区
environment:
- TZ=Asia/Shanghai
# 挂载共享内存(深度学习场景)
shm_size: '2gb'
# 安全选项
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
```
---
### 十、最佳实践
#### 10.1 安全性
```yaml
# ✅ 使用非 root 用户
user: "1000:1000"
# ✅ 最小化权限
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
# ❌ 避免 privileged
# privileged: true
```
#### 10.2 可靠性
```yaml
# ✅ 外部依赖都加 healthcheck
db:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
start_period: 30s
# ✅ 合理的重启策略
restart: unless-stopped
# ✅ 依赖顺序用 condition
depends_on:
db:
condition: service_healthy
```
#### 10.3 可维护性
```yaml
# ✅ 使用 .env 管理变量
# .env
COMPOSE_PROJECT_NAME=myapp
MYSQL_ROOT_PASSWORD=xxxxx
NODE_ENV=production
# ✅ 命名卷而不是绑定挂载(数据持久化)
volumes:
db-data: # Docker 管理,更安全
# ✅ 用 profiles 组织服务
# 开发只启动 app + db
# docker compose --profile dev up -d
```
#### 10.4 性能优化
```yaml
# ✅ 生产环境使用 Alpine 镜像
image: node:20-alpine # 约 150MB
# vs
image: node:20 # 约 1GB
# ✅ 限制资源使用
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
# ✅ 数据库不要暴露到宿主机
# db:
# ports:
# - "3306:3306" # 删除这行,用 expose 代替
```
---
## 快速参考卡
| 字段 | 用途 | 示例 |
|------|------|------|
| `image` | 使用已有镜像 | `image: nginx:alpine` |
| `build` | 从 Dockerfile 构建 | `build: ./app` |
| `ports` | 端口映射(外部可访问) | `"80:80"` |
| `expose` | 端口暴露(仅容器间) | `"3000"` |
| `volumes` | 数据持久化 | `data:/var/lib/mysql` |
| `environment` | 环境变量 | `NODE_ENV: production` |
| `depends_on` | 启动依赖 | `db: condition: service_healthy` |
| `healthcheck` | 健康检查 | `test: ["CMD", "curl", ...]` |
| `restart` | 重启策略 | `unless-stopped` |
| `networks` | 网络归属 | `app-network` |
| `profiles` | 按需启停 | `["dev", "monitoring"]` |
| `secrets` | 敏感信息管理 | `file: ./secrets/xxx` |
| `deploy.resources` | 资源限制 | `cpus: '0.5', memory: 512M` |
| `container_name` | 固定容器名 | `my-container` |
---
## 关联笔记
- [[Dockerfile编写指南]] — 编写高效的 Dockerfile
- [[Docker常用命令]] — 日常 Docker 操作速查