1. 从单容器到容器编排

在前面的课程中,我们学习了如何使用 Docker 容器来运行单个服务。
通过 docker run 命令,我们可以快速启动一个数据库、一个 Web 服务器或者一个缓存服务。
这种方式在开发简单应用时非常有效。然而,随着应用架构的演进,微服务的理念逐渐流行,一个应用可能由多个相互依赖的服务组成。
如果继续使用单容器管理方式,我们需要手动管理容器间的网络连接、存储卷映射、环境变量配置等,这不仅增加了运维的复杂度,还容易因手动操作而出错。

这就是为什么我们需要一个更高层次的工具来管理多容器应用。
Docker Compose 应运而生,它通过一个声明式的 YAML 配置文件,帮助我们定义和管理多容器应用。
通过 Docker Compose,我们可以用一个命令就完成整个应用的部署,而不需要手动管理每个容器。

2. Docker Compose 核心概念

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。使用 Compose,你可以通过一个 YAML 文件来配置应用程序的所有服务,然后使用一个命令来创建和启动所有服务。

2.1 主要概念

  • 服务 (Services): 容器的定义,包括使用哪个镜像、端口映射、环境变量等
  • 网络 (Networks): 定义容器之间如何通信
  • 卷 (Volumes): 定义数据的持久化存储
  • 依赖关系 (Dependencies): 定义服务之间的启动顺序
  • 环境变量 (Environment Variables): 管理不同环境的配置

2.2 核心命令

  • docker compose up: 创建和启动所有服务
  • docker compose down: 停止和删除所有服务
  • docker compose ps: 查看服务状态
  • docker compose logs: 查看服务日志

3. 实践项目:使用 docker compose 构建 Todo 应用

在本章节中,我们将创建一个完整的 Todo 应用,包含以下组件:

  • Nginx: 路由转发
  • 前端: React 应用
  • 后端: Node.js API 服务
  • 数据库: MongoDB

项目结构

1
2
3
4
5
6
5_compose/
├── docker-compose.yml # Compose 配置文件
├── nginx/ # nginx
├── frontend/ # React 前端应用
├── backend/ # Node.js 后端服务
└── INSTRUCTIONS.md # 项目说明

架构图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
            ┌─────────────┐
│ Nginx │
│ :8080 │
└─────┬───────┘

┌────────┴────────┐
│ │
┌───────▼─────┐ ┌──────▼──────┐
│ Frontend │ │ Backend │
│ (React) │ │ (Node.js) │
│ :3000 │ │ :3001 │
└─────────────┘ └──────┬───────┘

┌───────▼───────┐
│ MongoDB │
│ Database │
│ :27017 │
└───────────────┘

Docker Compose 配置解析

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# docker-compose.yml
version: '3.8'

services:
# Nginx 反向代理
nginx:
build: ./nginx
# 添加端口映射, 将容器的 80 端口映射为宿主机的 8080
ports:
- "8080:80"
# 依赖关系, 先启动后端和前端, 再启动nginx
depends_on:
- frontend
- backend

# 前端服务
frontend:
build: ./frontend
# 暴露端口, 仅容器网络可见
expose:
- "3000"
environment:
- REACT_APP_API_URL=/api
depends_on:
- backend
volumes:
- ./frontend:/app
- /app/node_modules

# 后端服务
backend:
build: ./backend
expose:
- "3001"
environment:
- MONGODB_URI=mongodb://mongodb:27017/todos
depends_on:
- mongodb
volumes:
- ./backend:/app
- /app/node_modules

# MongoDB 数据库
mongodb:
image: mongo:6
expose:
- "27017"
volumes:
- mongodb_data:/data/db

# 定义持久化存储卷
volumes:
mongodb_data:

服务定义

  1. nginx 服务

    • 使用官方 nginx 镜像
    • 映射端口 8080,作为应用的访问入口
    • 将 nginx.conf 配置文件打包进镜像
  2. frontend 服务

    • 使用本地 Dockerfile 构建
    • 暴露端口 3000,仅容器网络访问
    • 设置 API URL 环境变量
    • 依赖于 backend 服务
    • 使用卷挂载实现热重载
  3. backend 服务

    • 使用本地 Dockerfile 构建
    • 映射端口 3001,仅容器网络访问
    • 设置 MongoDB 连接环境变量
    • 依赖于 mongodb 服务
    • 使用卷挂载实现热重载
  4. mongodb 服务

    • 使用官方 MongoDB 镜像
    • 映射端口 27017,仅容器网络访问
    • 使用命名卷持久化数据

网络配置

  • Docker Compose 会自动创建一个默认网络 (bridge模式)
  • 所有服务都在同一网络中
  • 服务可以通过服务名互相访问

数据持久化

  • 使用命名卷 mongodb_data 持久化数据库数据
  • 使用绑定挂载实现开发时的代码热重载

使用说明

  1. 在后台启动服务

    1
    docker compose up -d
  2. 查看服务状态

    1
    docker compose ps

    image-20250626024603919

  3. 查看服务日志

    1
    2
    3
    docker compose logs frontend
    docker compose logs backend
    docker compose logs mongodb

    image-20250626024653709

  4. 停止所有服务

    1
    docker compose down

    image-20250626024809294

  5. 重新构建服务

    1
    docker compose build

    image-20250626024821912

  6. 重启单个服务

    1
    docker compose restart frontend

    image-20250626024828987

访问应用

我们使用了在 nginx 这里配置了 8080 端口作为 todo 应用的整体入口,
在 cnb 上我们可以通过添加一个8080 的端口映射来实现外网访问, 可以按照如下步骤来配置。

image-20250626024837153

点击这个浏览器图标,就可以访问 todo 应用了。