Docker Compose解决什么问题
用Docker跑单个容器很简单,但实际项目往往需要多个服务配合:Web应用 + 数据库 + 缓存 + 反向代理。如果每个都手动docker run,参数一大堆,管理起来非常痛苦。
Docker Compose就是来解决这个问题的——用一个YAML文件定义所有服务,一条命令启动全部。
安装Docker Compose
Docker Desktop自带Compose。如果是Linux服务器:
1
2
3
4
5
6
7
8
| # 新版Docker已经自带compose插件
$ docker compose version
Docker Compose version v2.21.0
# 如果没有,手动安装
$ sudo apt install -y docker-compose-plugin
$ docker compose version
Docker Compose version v2.21.0
|
注意:新版用docker compose(空格),老版用docker-compose(连字符)。本文使用新版语法。
基本语法
一个docker-compose.yml文件的基本结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| version: "3.8"
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
restart: always
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: mypassword
volumes:
- db_data:/var/lib/mysql
restart: always
volumes:
db_data:
|
| 配置项 | 作用 | 示例 |
|---|
image | 使用的镜像 | nginx:latest |
build | 从Dockerfile构建 | build: ./app |
ports | 端口映射 | "8080:80" |
volumes | 数据卷挂载 | ./data:/app/data |
environment | 环境变量 | MYSQL_ROOT_PASSWORD: xxx |
depends_on | 依赖关系 | 先启动依赖的服务 |
restart | 重启策略 | always/unless-stopped |
networks | 网络配置 | 自定义网络 |
常用命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| # 启动所有服务(后台运行)
$ docker compose up -d
[+] Running 3/3
✔ Network myapp_default Created
✔ Container myapp-db-1 Started
✔ Container myapp-web-1 Started
# 查看运行状态
$ docker compose ps
NAME IMAGE STATUS PORTS
myapp-web-1 nginx:latest Up 30 seconds 0.0.0.0:80->80/tcp
myapp-db-1 mysql:8.0 Up 30 seconds 3306/tcp
# 查看日志
$ docker compose logs
$ docker compose logs -f web # 跟踪指定服务的日志
# 停止所有服务
$ docker compose down
# 停止并删除数据卷(谨慎!)
$ docker compose down -v
# 重新构建并启动
$ docker compose up -d --build
# 只启动某个服务
$ docker compose up -d web
# 进入某个容器
$ docker compose exec web bash
|
实战一:Nginx + PHP + MySQL
典型的LNMP环境:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| # docker-compose.yml
version: "3.8"
services:
nginx:
image: nginx:1.24
ports:
- "80:80"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./www:/var/www/html
depends_on:
- php
restart: always
php:
image: php:8.2-fpm
volumes:
- ./www:/var/www/html
restart: always
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
restart: always
volumes:
mysql_data:
|
Nginx配置文件 nginx/conf.d/default.conf:
1
2
3
4
5
6
7
8
9
10
11
12
13
| server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php index.html;
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 创建测试文件
$ mkdir -p www nginx/conf.d
$ echo '<?php phpinfo(); ?>' > www/index.php
# 启动
$ docker compose up -d
[+] Running 4/4
✔ Network lnmp_default Created
✔ Container lnmp-mysql-1 Started
✔ Container lnmp-php-1 Started
✔ Container lnmp-nginx-1 Started
# 访问 http://服务器IP 就能看到phpinfo页面了
|
实战二:Node.js + Redis + MongoDB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| version: "3.8"
services:
app:
build: ./app
ports:
- "3000:3000"
environment:
- REDIS_URL=redis://redis:6379
- MONGO_URL=mongodb://mongo:27017/myapp
depends_on:
- redis
- mongo
restart: always
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
restart: always
mongo:
image: mongo:7
volumes:
- mongo_data:/data/db
environment:
MONGO_INITDB_DATABASE: myapp
restart: always
volumes:
redis_data:
mongo_data:
|
使用.env文件管理配置
不要把密码硬编码在docker-compose.yml里:
1
2
3
4
5
| # .env 文件
MYSQL_ROOT_PASSWORD=your_secure_password
MYSQL_DATABASE=production_db
MYSQL_USER=produser
MYSQL_PASSWORD=prodpassword
|
1
2
3
4
5
6
7
8
9
| # docker-compose.yml
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
1
2
| # 验证变量替换是否正确
$ docker compose config
|
多环境配置
1
2
3
4
5
6
7
8
9
| # docker-compose.yml - 基础配置
# docker-compose.dev.yml - 开发环境覆盖
# docker-compose.prod.yml - 生产环境覆盖
# 开发环境启动
$ docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# 生产环境启动
$ docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
常见问题
服务启动顺序
depends_on只保证启动顺序,不保证服务就绪。数据库可能还没初始化完,应用就开始连了:
1
2
3
4
5
6
7
8
9
10
11
12
| services:
app:
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
|
容器间通信
同一个docker-compose.yml里的服务可以用服务名直接通信:
1
2
3
4
| # 在app容器里可以直接用 "db" 作为主机名
$ docker compose exec app ping db
PING db (172.18.0.3) 56(84) bytes of data.
64 bytes from lnmp-db-1.lnmp_default (172.18.0.3): icmp_seq=1 ttl=64
|
总结
Docker Compose是管理多容器应用的利器。掌握它之后,部署一个完整的Web应用只需要一个YAML文件和一条命令。
Docker基础操作可以看Docker入门教程。如果想用Docker快速搭建WordPress,可以看Docker一键部署WordPress。