1. 为什么你需要Docker Compose

第一次接触微服务开发时,我最头疼的就是要同时启动五六个服务。每个服务都要单独运行docker run命令,还得记住各种端口映射和环境变量。直到发现了Docker Compose这个神器,才明白原来容器编排可以这么简单。

Docker Compose就像是个智能管家,你只需要在一个YAML文件里写好所有服务的配置,它就能帮你一键启动整个应用栈。比如一个典型的电商系统可能包含:

  • 前端Web服务
  • 用户服务
  • 商品服务
  • 订单服务
  • Redis缓存
  • MySQL数据库

手动管理这些容器不仅容易出错,还特别浪费时间。而用Docker Compose,你只需要定义一次配置,就能在任何环境快速复现完整的服务集群。我去年负责的一个物流项目,从开发到上线全程使用Compose编排,部署时间从原来的2小时缩短到5分钟。

2. 环境准备与安装

2.1 安装Docker引擎

在开始之前,我们需要先安装Docker引擎。以Ubuntu系统为例:

# 更新软件包索引
sudo apt-get update

# 安装依赖包
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 添加Docker官方GPG密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 设置稳定版仓库
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装Docker引擎
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

安装完成后,运行docker version检查是否安装成功。建议将当前用户加入docker组,避免每次都要sudo:

sudo usermod -aG docker $USER
newgrp docker  # 刷新用户组

2.2 安装Docker Compose

现在Docker Compose已经作为插件集成到Docker CLI中,安装更简单:

# 安装最新稳定版
sudo apt-get update
sudo apt-get install docker-compose-plugin

# 验证安装
docker compose version

如果系统不支持插件方式,也可以用传统方法安装:

# 下载二进制文件
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 创建软链接(可选)
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

3. 第一个微服务栈实战

3.1 项目结构设计

我们来构建一个简单的博客系统,包含以下服务:

  • 前端:React应用
  • 后端:Node.js API服务
  • 数据库:MongoDB
  • 缓存:Redis

创建项目目录结构:

mkdir blog-system && cd blog-system
mkdir frontend backend
touch docker-compose.yml

3.2 编写docker-compose.yml

打开编辑器,输入以下配置:

version: '3.8'

services:
  mongodb:
    image: mongo:6
    container_name: blog_db
    ports:
      - "27017:27017"
    volumes:
      - mongodb_data:/data/db
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example

  redis:
    image: redis:7
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

  backend:
    build: ./backend
    ports:
      - "3001:3001"
    depends_on:
      - mongodb
      - redis
    environment:
      DB_URL: "mongodb://root:example@mongodb:27017"
      REDIS_URL: "redis://redis:6379"

  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    depends_on:
      - backend

volumes:
  mongodb_data:
  redis_data:

这个配置做了几件重要的事:

  1. 定义了两个数据服务(MongoDB和Redis)
  2. 声明了前后端服务
  3. 设置了服务间的依赖关系
  4. 配置了数据持久化卷
  5. 暴露了必要的服务端口

3.3 编写Dockerfile

在backend目录创建Dockerfile:

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3001
CMD ["npm", "start"]

在frontend目录创建类似的Dockerfile:

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000
CMD ["npm", "start"]

4. 运行与调试技巧

4.1 启动服务栈

在项目根目录运行:

docker compose up -d

这个命令会:

  1. 构建自定义镜像(frontend和backend)
  2. 拉取公共镜像(mongo和redis)
  3. 按依赖顺序启动所有容器
  4. -d参数表示后台运行

查看运行状态:

docker compose ps

4.2 常见问题排查

问题1:服务启动顺序导致连接失败

虽然我们用了depends_on,但它只保证容器启动顺序,不保证服务就绪。可以在backend服务中添加健康检查:

healthcheck:
  test: ["CMD", "curl", "-f", "http://mongodb:27017"]
  interval: 10s
  timeout: 5s
  retries: 5

问题2:端口冲突

如果端口被占用,可以:

  1. 修改docker-compose.yml中的端口映射
  2. 停止占用端口的服务
  3. 使用netstat -tulnp | grep <端口号>查找冲突进程

问题3:容器间网络不通

确保:

  1. 所有服务在同一个网络(默认会自动创建)
  2. 使用服务名而非IP进行通信
  3. 检查防火墙设置

4.3 常用操作命令

# 查看日志
docker compose logs -f backend

# 执行命令
docker compose exec backend sh

# 重建服务
docker compose up -d --build frontend

# 停止服务
docker compose down

# 清理无用资源
docker system prune -f

5. 进阶配置技巧

5.1 多环境配置

可以创建多个Compose文件实现环境隔离:

docker-compose.yml          # 基础配置
docker-compose.override.yml # 开发环境(默认加载)
docker-compose.prod.yml     # 生产环境

开发环境配置示例:

# docker-compose.override.yml
version: '3.8'

services:
  backend:
    volumes:
      - ./backend:/app
    environment:
      NODE_ENV: development

生产环境配置示例:

# docker-compose.prod.yml
version: '3.8'

services:
  backend:
    environment:
      NODE_ENV: production
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

启动时指定配置文件:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

5.2 资源限制与扩展

services:
  backend:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          memory: 256M

5.3 使用环境变量文件

创建.env文件:

DB_USER=admin
DB_PASS=secret

在compose文件中引用:

environment:
  DB_USER: ${DB_USER}
  DB_PASS: ${DB_PASS}

6. 真实项目经验分享

去年我在一个电商项目中使用了Docker Compose编排了12个微服务。最大的收获是学会了如何合理设计服务依赖关系。比如支付服务依赖订单服务,而订单服务又依赖商品服务,这种复杂依赖如果处理不好就会导致启动失败。

我的经验是:

  1. 将基础服务(数据库、消息队列等)放在独立的compose文件中
  2. 为每个业务域创建单独的compose文件
  3. 使用depends_on结合健康检查确保启动顺序
  4. 为关键服务配置重启策略
restart: unless-stopped

另一个实用技巧是使用docker compose config命令验证配置文件语法,这个命令会合并所有配置并输出最终结果,非常适合调试复杂的多文件配置。

更多推荐