别再手动一个个启动容器了!用Docker Compose编排一个Web+MySQL+Redis的完整项目(附yml文件详解)

每次部署多容器项目时,最头疼的就是手动启动每个服务、配置网络、挂载数据卷。想象一下:先启动MySQL容器,设置root密码和存储卷;再启动Redis,配置持久化;最后部署Web应用,确保能连接到数据库和缓存。这种重复劳动不仅低效,还容易出错。而Docker Compose正是解决这一痛点的利器——它允许你用一份YAML文件定义整个应用栈,然后通过一条命令启动所有服务。

1. 为什么需要Docker Compose?

在真实开发场景中,几乎没有应用是单一容器能支撑的。以典型的Web项目为例:

  • 核心服务:应用服务器(如Spring Boot)、数据库(MySQL)、缓存(Redis)
  • 辅助服务:消息队列(RabbitMQ)、搜索引擎(Elasticsearch)
  • 基础设施:负载均衡(Nginx)、监控(Prometheus)

手动管理这些容器的痛点包括:

  1. 启动顺序依赖:数据库必须先于应用启动
  2. 网络配置复杂:容器间需要互通但又要隔离外部访问
  3. 环境变量传递:数据库连接字符串需要注入到Web容器
  4. 数据持久化:数据库文件、缓存数据需要挂载到宿主机

Docker Compose通过声明式配置解决这些问题。下面是一个对比传统方式和Compose方式的典型流程:

操作步骤手动操作命令示例Compose方式
创建网络docker network create app_net在yml中定义networks块
启动MySQLdocker run --name mysql -e MYSQL_ROOT_PASSWORD=123456...services.mysql.environment
启动Redisdocker run --name redis -v redis_data:/data...services.redis.volumes
启动Web应用docker run --name web --link mysql --link redis...services.web.depends_on

提示:Compose的depends_on只能控制启动顺序,不能确保服务已就绪。对于数据库这类需要等待初始化完成的服务,建议结合健康检查使用。

2. 实战:编写docker-compose.yml

让我们构建一个Spring Boot + MySQL + Redis的完整项目。假设项目结构如下:

myapp/
├── docker-compose.yml
├── backend/
│   ├── Dockerfile
│   └── target/app.jar  # Spring Boot打包结果
├── mysql/
│   └── init.sql       # 数据库初始化脚本
└── redis/
    └── redis.conf     # Redis自定义配置

2.1 基础结构解析

每个Compose文件包含三个核心部分:

version: "3.8"  # 指定Compose语法版本

services:  # 定义所有服务容器
  web:
    build: ./backend
    ports:
      - "8080:8080"

volumes:  # 声明数据卷
  db_data:

networks:  # 定义网络
  app_net:
    driver: bridge

关键版本选择建议:

  • 3.x版本支持Swarm模式扩展
  • 生产环境建议使用3.8+以获得最新功能
  • 不同Docker Engine版本有兼容性要求

2.2 完整配置详解

以下是带详细注释的yml文件:

version: "3.8"

services:
  # Spring Boot应用服务
  webapp:
    build: 
      context: ./backend
      dockerfile: Dockerfile  # 指定Dockerfile路径
    container_name: myapp_web
    ports:
      - "8080:8080"
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/mydb
      - SPRING_REDIS_HOST=redis
    depends_on:
      - mysql
      - redis
    networks:
      - app_net
    restart: unless-stopped  # 异常退出时自动重启

  # MySQL数据库服务
  mysql:
    image: mysql:8.0
    container_name: myapp_mysql
    environment:
      - MYSQL_ROOT_PASSWORD=mysecret
      - MYSQL_DATABASE=mydb
    volumes:
      - db_data:/var/lib/mysql
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql  # 初始化脚本
    ports:
      - "3306:3306"
    networks:
      - app_net
    healthcheck:  # 健康检查
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s
      timeout: 3s
      retries: 5

  # Redis缓存服务
  redis:
    image: redis:6
    container_name: myapp_redis
    command: redis-server --requirepass mypassword  # 设置密码
    volumes:
      - redis_data:/data
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf  # 挂载自定义配置
    ports:
      - "6379:6379"
    networks:
      - app_net

volumes:
  db_data:
  redis_data:

networks:
  app_net:
    driver: bridge

2.3 关键配置项解析

服务依赖与启动顺序
depends_on:
  - mysql
  - redis

虽然depends_on定义了启动顺序,但更好的实践是:

  1. 为MySQL添加健康检查
  2. 在应用启动命令中添加等待脚本,例如:
# 在Dockerfile中添加健康检查等待脚本
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/actuator/health || exit 1
数据持久化方案对比
方式优点缺点适用场景
匿名卷自动创建,简单难以维护,删除容器会丢失开发环境临时数据
命名卷(推荐)生命周期独立于容器需要显式声明生产环境数据库存储
宿主机目录绑定直接访问宿主机文件路径依赖宿主机环境配置文件、初始化脚本
网络隔离策略

默认创建的app_net具有以下特性:

  • 所有服务通过服务名(如mysql)互相访问
  • 对外暴露的只有webapp服务的8080端口
  • 可通过networks定义多个网络实现更细粒度隔离

3. 高效开发技巧

3.1 常用操作命令

启动并构建所有服务(开发环境):

docker-compose up -d --build

仅重建并启动特定服务:

docker-compose up -d --no-deps --build webapp

查看服务日志:

docker-compose logs -f webapp

执行数据库迁移:

docker-compose exec webapp ./migrate.sh

3.2 性能优化配置

对于生产环境,建议添加以下配置:

services:
  mysql:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
    ulimits:
      nproc: 65535
      nofile:
        soft: 20000
        hard: 40000

3.3 多环境配置方案

通过环境变量和多个Compose文件实现:

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

启动时指定配置:

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

4. 常见问题排查

4.1 容器启动失败排查步骤

  1. 查看日志:docker-compose logs service_name
  2. 检查配置:docker-compose config
  3. 进入容器:docker-compose exec service_name sh
  4. 验证网络:docker network inspect myapp_app_net

4.2 典型错误解决方案

问题1:MySQL连接被拒绝
解决:确保depends_on配合健康检查使用,或在应用启动脚本中添加等待逻辑

问题2:端口冲突
解决:检查ports配置或使用docker-compose ps查看运行状态

问题3:卷权限问题
解决:在Dockerfile中正确设置用户权限,例如:

RUN mkdir -p /var/lib/mysql && chown -R mysql:mysql /var/lib/mysql

问题4:环境变量未生效
解决:使用docker-compose exec service_name env验证环境变量

注意:修改docker-compose.yml后,需要重新运行docker-compose up -d使更改生效。对于某些配置(如环境变量),可能需要先执行docker-compose down再重新启动。

更多推荐