刚开始用 Docker 的时候,我写了一大串 docker run 命令,参数又多又乱,后来想改个端口或者加个环境变量,得翻半天历史记录。自从换成 Docker Compose 之后,部署和管理容器变得舒服多了。

Docker Compose 的核心思想是把一个应用的多个服务写在一个 YAML 文件里,一条命令就能启动整个应用栈。这篇文章总结我用 Compose 部署过的一些常用服务,给想入门的人做个参考。

为什么用 Docker Compose

相比 docker run,Compose 有几个明显优势:

  1. 配置集中管理:所有服务的镜像、端口、环境变量、挂载都写在一个文件里。
  2. 一键启停docker-compose up -d 启动所有服务,docker-compose down 停止。
  3. 服务自动组网:同一个 compose 项目里的服务自动在同一个网络里,可以通过服务名互相访问。
  4. 便于迁移:换服务器的时候把 docker-compose.yml 和数据目录复制过去就行。

基础写法

一个最简单的 docker-compose.yml 长这样:

 1version: '3.8'
 2
 3services:
 4  web:
 5    image: nginx:alpine
 6    ports:
 7      - "80:80"
 8    volumes:
 9      - ./html:/usr/share/nginx/html
10    restart: unless-stopped

启动:

1docker-compose up -d

-d 表示后台运行。

部署一个静态博客

我的博客前端是 Hugo 生成的静态文件,后端用 Nginx 提供服务。Compose 文件很简单:

 1version: '3.8'
 2
 3services:
 4  blog:
 5    image: nginx:alpine
 6    container_name: blog
 7    ports:
 8      - "80:80"
 9      - "443:443"
10    volumes:
11      - ./public:/usr/share/nginx/html
12      - ./nginx.conf:/etc/nginx/conf.d/default.conf
13      - ./ssl:/etc/nginx/ssl
14    restart: unless-stopped

./public 是 Hugo 构建出来的静态文件目录。每次更新博客后,重新构建并替换这个目录里的文件即可。

部署 WordPress + MySQL

很多老项目还是 WordPress,用 Compose 部署 WordPress 和数据库非常方便:

 1version: '3.8'
 2
 3services:
 4  db:
 5    image: mysql:8.0
 6    container_name: wp_db
 7    environment:
 8      MYSQL_ROOT_PASSWORD: root_password
 9      MYSQL_DATABASE: wordpress
10      MYSQL_USER: wordpress
11      MYSQL_PASSWORD: wordpress_password
12    volumes:
13      - db_data:/var/lib/mysql
14    restart: unless-stopped
15
16  wordpress:
17    image: wordpress:latest
18    container_name: wp_app
19    ports:
20      - "8080:80"
21    environment:
22      WORDPRESS_DB_HOST: db:3306
23      WORDPRESS_DB_USER: wordpress
24      WORDPRESS_DB_PASSWORD: wordpress_password
25      WORDPRESS_DB_NAME: wordpress
26    volumes:
27      - wp_data:/var/www/html
28    depends_on:
29      - db
30    restart: unless-stopped
31
32volumes:
33  db_data:
34  wp_data:

注意 WORDPRESS_DB_HOST 直接写 db:3306,因为 Compose 会自动把服务名解析成 IP。

部署 Uptime Kuma 监控

Uptime Kuma 是个很好用的监控工具,我自己也在用:

 1version: '3.8'
 2
 3services:
 4  uptime-kuma:
 5    image: louislam/uptime-kuma:1
 6    container_name: uptime-kuma
 7    ports:
 8      - "3001:3001"
 9    volumes:
10      - ./data:/app/data
11    restart: unless-stopped

启动后访问 http://服务器IP:3001 进行初始化配置。

部署 Vaultwarden 密码管理器

Vaultwarden 是 Bitwarden 的 Rust 轻量实现,适合个人或小团队自建:

 1version: '3.8'
 2
 3services:
 4  vaultwarden:
 5    image: vaultwarden/server:latest
 6    container_name: vaultwarden
 7    environment:
 8      WEBSOCKET_ENABLED: "true"
 9      SIGNUPS_ALLOWED: "false"
10    volumes:
11      - ./vw-data:/data
12    ports:
13      - "8080:80"
14    restart: unless-stopped

SIGNUPS_ALLOWED: "false" 表示关闭公开注册,只允许管理员手动邀请用户。自建密码管理器一定要注意安全。

部署 Nginx 反向代理

如果一台服务器上跑了多个服务,前面加一个 Nginx 做反向代理是标准做法:

 1version: '3.8'
 2
 3services:
 4  nginx:
 5    image: nginx:alpine
 6    container_name: nginx
 7    ports:
 8      - "80:80"
 9      - "443:443"
10    volumes:
11      - ./nginx.conf:/etc/nginx/nginx.conf
12      - ./ssl:/etc/nginx/ssl
13    restart: unless-stopped
14
15  app1:
16    image: myapp1:latest
17    container_name: app1
18    restart: unless-stopped
19
20  app2:
21    image: myapp2:latest
22    container_name: app2
23    restart: unless-stopped

对应的 nginx.conf 里可以用服务名做 upstream:

 1server {
 2    listen 80;
 3    server_name app1.example.com;
 4
 5    location / {
 6        proxy_pass http://app1:8080;
 7    }
 8}
 9
10server {
11    listen 80;
12    server_name app2.example.com;
13
14    location / {
15        proxy_pass http://app2:8080;
16    }
17}

几个使用技巧

1. 使用 .env 文件管理敏感信息

不要把密码直接写在 docker-compose.yml 里,可以用 .env 文件:

1MYSQL_ROOT_PASSWORD=your_password

然后在 compose 文件里引用:

1environment:
2  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}

2. 合理设置 restart 策略

一般服务用 unless-stopped,表示除非手动停止,否则 always 重启。测试环境可以用 no

3. 限制容器资源

生产环境建议限制 CPU 和内存,防止某个容器把资源吃光:

1deploy:
2  resources:
3    limits:
4      cpus: '0.5'
5      memory: 512M
6    reservations:
7      cpus: '0.25'
8      memory: 256M

4. 使用 networks 隔离不同项目

如果一台服务器上跑了多个项目,最好给每个项目单独的网络,避免服务名冲突:

1networks:
2  project_a:
3    driver: bridge

常用命令

 1# 启动所有服务(后台)
 2docker-compose up -d
 3
 4# 查看日志
 5docker-compose logs -f
 6
 7# 重启某个服务
 8docker-compose restart 服务名
 9
10# 停止并删除容器
11docker-compose down
12
13# 停止并删除容器和数据卷(慎用)
14docker-compose down -v
15
16# 拉取最新镜像
17docker-compose pull
18
19# 重新构建
20docker-compose up -d --build

总结

Docker Compose 是我目前最喜欢的小型项目部署方式。它不像 Kubernetes 那么重,又比纯 docker run 好管理得多。

这篇文章给的几个模板都是我自己实际在用的,你可以根据需求改一改端口、路径和密码就能跑起来。如果刚开始接触 Docker,建议先从一个简单的静态博客或者 Uptime Kuma 入手,熟练之后再挑战多服务组合。