Docker Compose多服务编排与自动化部署配置详解

Docker Compose用于定义和运行多容器Docker应用。在Web项目中,前端、后端API、数据库、缓存等服务需要协同工作,手动逐个启动容器效率低且容易出错。通过docker-compose.yml文件声明式定义服务拓扑,一条命令完成所有服务的构建、启动和依赖编排。本文以典型的LNMP+Redis架构为例,讲解Compose文件编写、网络隔离、数据持久化和部署自动化。

docker-compose.yml文件结构与基础配置

一个包含Nginx、PHP-FPM、MySQL、Redis的Web应用编排文件示例:

version: "3.8"

services:
  nginx:
    image: nginx:1.25-alpine
    container_name: web-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - ./app/public:/var/www/html/public:ro
      - nginx-logs:/var/log/nginx
    depends_on:
      - php-fpm
    networks:
      - frontend
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://localhost/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  php-fpm:
    build:
      context: ./php
      dockerfile: Dockerfile
    container_name: web-php
    volumes:
      - ./app:/var/www/html
      - ./php/php.ini:/usr/local/etc/php/php.ini:ro
    networks:
      - frontend
      - backend
    restart: unless-stopped
    environment:
      - DB_HOST=mysql
      - DB_NAME=appdb
      - REDIS_HOST=redis

  mysql:
    image: mysql:8.0
    container_name: web-mysql
    volumes:
      - mysql-data:/var/lib/mysql
      - ./mysql/init:/docker-entrypoint-initdb.d:ro
      - ./mysql/conf.d:/etc/mysql/conf.d:ro
    networks:
      - backend
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD: ${MYSQL_APP_PASSWORD}
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

  redis:
    image: redis:7-alpine
    container_name: web-redis
    volumes:
      - redis-data:/data
      - ./redis/redis.conf:/etc/redis/redis.conf:ro
    networks:
      - backend
    restart: unless-stopped
    command: redis-server /etc/redis/redis.conf --requirepass ${REDIS_PASSWORD}

volumes:
  mysql-data:
  redis-data:
  nginx-logs:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true

网络隔离策略与容器间通信

上面的配置定义了两个网络:frontend和backend。Nginx同时接入两个网络,作为反向代理连接外部请求与内部服务。PHP-FPM跨接两个网络,接收Nginx转发的FastCGI请求,同时访问后端数据库和缓存。MySQL和Redis只接入backend网络。

backend网络设置internal: true,该网络不与宿主机网络连通,容器在该网络中无法访问外部互联网,外部也无法直接访问该网络中的容器。这意味着MySQL和Redis完全不可能被外部直接访问,只能通过同一网络内的PHP-FPM容器连接。

# 验证网络隔离效果
# 从宿主机直接连接MySQL——应失败
mysql -h 127.0.0.1 -P 3306 -u root -p
# ERROR: Connection refused(端口未映射到宿主机)

# 从PHP容器内部连接MySQL——应成功
docker exec web-php mysql -h mysql -u appuser -p

# 查看容器的网络连接
docker inspect web-php --format='{{json .NetworkSettings.Networks}}' | python -m json.tool

容器间通过服务名互访是Docker Compose的内置功能。DNS解析由Docker内嵌的DNS服务器自动处理,mysqlredis这些服务名直接作为主机名使用,无需配置hosts文件。服务扩容后新容器自动注册到DNS,其他容器能立即发现新实例。

数据持久化与Volume管理

容器本身是无状态且临时的,容器删除后内部数据丢失。需要持久化的数据通过Volume挂载到宿主机。上面的配置中使用了三种Volume策略:

# 命名Volume:由Docker管理,适合数据库等需要高性能IO的场景
volumes:
  - mysql-data:/var/lib/mysql

# 绑定挂载:直接映射宿主机目录,适合配置文件和代码热更新
volumes:
  - ./app:/var/www/html
  - ./nginx/conf.d:/etc/nginx/conf.d:ro

# tmpfs挂载:内存中的临时文件系统,适合敏感数据和临时文件
volumes:
  - tmpfs:/tmp

命名Volume存储在Docker管理的目录中(默认/var/lib/docker/volumes/),性能优于绑定挂载,因为Docker可以使用overlay2等优化的存储驱动。MySQL的数据目录使用命名Volume,避免宿主机文件系统权限问题。代码目录使用绑定挂载,开发环境下修改代码立即生效,无需重建镜像。

Volume的备份与迁移:

# 备份MySQL数据Volume
docker run --rm \
  -v mysql-data:/data:ro \
  -v $(pwd)/backup:/backup \
  alpine tar czf /backup/mysql-$(date +%Y%m%d).tar.gz -C /data .

# 恢复MySQL数据Volume
docker run --rm \
  -v mysql-data:/data \
  -v $(pwd)/backup:/backup:ro \
  alpine sh -c "rm -rf /data/* && tar xzf /backup/mysql-20260805.tar.gz -C /data"

# 清理未使用的Volume(谨慎操作)
docker volume prune

Health Check与服务依赖编排

depends_on只保证容器启动顺序,不等待依赖服务就绪。MySQL容器启动后需要数秒完成初始化,如果PHP-FPM在MySQL就绪前连接数据库会报错。通过Health Check解决此问题:

  mysql:
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p${MYSQL_ROOT_PASSWORD} --silent"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

  php-fpm:
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_started

condition: service_healthy表示PHP-FPM等待MySQL的healthcheck通过后才启动。start_period: 30s给MySQL 30秒的初始化窗口,在此期间healthcheck失败不计入重试次数。retries设为10次、每次间隔10秒,最长等待100秒,覆盖大多数数据库初始化场景。

多环境配置与CI/CD集成

开发、测试、生产环境使用不同的Compose配置文件。通过docker-compose.override.yml机制实现环境差异覆盖:

# 开发环境override示例
version: "3.8"
services:
  php-fpm:
    build:
      target: dev
    volumes:
      - ./app:/var/www/html
    environment:
      - PHP_DEBUG=1
      - XDEBUG_MODE=develop,debug

# 生产环境prod示例
version: "3.8"
services:
  php-fpm:
    build:
      target: prod
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '2'
          memory: 1G
    environment:
      - PHP_DEBUG=0

# 启动命令
# 开发环境(自动加载override)
docker compose up -d

# 生产环境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

CI/CD流水线中的自动化部署脚本:

#!/bin/bash
set -e

IMAGE_TAG=$(git rev-parse --short HEAD)

git pull origin main

docker compose -f docker-compose.yml -f docker-compose.prod.yml build \
  --build-arg BUILD_TAG=$IMAGE_TAG

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d \
  --no-deps --build php-fpm

docker image prune -f --filter "until=168h"

sleep 10
curl -f http://localhost/health || {
    echo "Health check failed, rolling back"
    docker compose -f docker-compose.yml -f docker-compose.prod.yml \
        up -d --no-deps php-fpm:previous
    exit 1
}

echo "Deployment successful: $IMAGE_TAG"

滚动更新通过--no-deps只重建PHP-FPM容器而不影响数据库和缓存服务。部署后的健康检查失败时回滚到上一个镜像版本。通过Git commit hash作为镜像标签,每次部署都可追溯到具体的代码版本。

日志收集与容器监控

多容器环境中日志分散在各容器内部,集中收集是运维的基础。使用Docker的json-file日志驱动配合日志轮转:

# docker-compose.yml中为每个服务配置日志驱动
services:
  php-fpm:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    
  nginx:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

max-size限制单个日志文件大小,max-file限制保留的日志文件数量。超出后自动轮转删除最旧文件。避免容器日志无限增长导致磁盘满。

# 查看所有服务的实时日志
docker compose logs -f

# 只看特定服务最近100行
docker compose logs --tail 100 php-fpm

# 查看特定时间段的日志
docker compose logs --since "2026-08-05T10:00:00" --until "2026-08-05T12:00:00"

生产环境建议将日志驱动改为syslog或fluentd,将日志发送到集中式日志系统。配合Prometheus + Grafana监控容器CPU、内存、网络指标,构建完整的可观测性体系。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/dockercompose-duo-fu-wu-bian-pai-yu-zi-dong-hua-bu-shu-pei/

(0)
小编小编
上一篇 21小时前
下一篇 21小时前

相关推荐