04:Docker-Compose完全指南

04. Docker Compose 完全指南

4.1 Docker Compose 概述

4.1.1 为什么需要 Docker Compose?

痛点场景:

bash 复制代码
# 传统方式部署一个 Web 应用需要:
docker network create app-network

docker run -d --name db --network app-network \
  -e MYSQL_ROOT_PASSWORD=secret \
  -e MYSQL_DATABASE=myapp \
  mysql:8.0

docker run -d --name redis --network app-network \
  redis:alpine

docker run -d --name api --network app-network \
  -e DB_HOST=db \
  -e REDIS_HOST=redis \
  -p 8080:8080 \
  my-api:latest

docker run -d --name web --network app-network \
  -p 80:80 \
  my-web:latest

# 需要记住多个命令,难以管理和复制!

使用 Docker Compose:

yaml 复制代码
# docker-compose.yml
version: '3.8'

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: myapp

  redis:
    image: redis:alpine

  api:
    image: my-api:latest
    environment:
      DB_HOST: db
      REDIS_HOST: redis
    ports:
      - "8080:8080"

  web:
    image: my-web:latest
    ports:
      - "80:80"
bash 复制代码
# 一条命令启动所有服务
docker-compose up -d

4.1.2 Docker Compose 是什么?

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。

4.1.3 安装 Docker Compose

Docker Desktop(Windows/Mac):

  • 已内置 Docker Compose,无需单独安装

Linux 安装:

bash 复制代码
# 方法 1:使用 Docker 官方插件(推荐)
sudo apt-get update
sudo apt-get install docker-compose-plugin

# 验证安装
docker compose version

# 方法 2:下载二进制文件
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 验证
docker-compose --version

注意:

  • 新版本使用 docker compose(空格)
  • 旧版本使用 docker-compose(连字符)
  • 本文档使用新版语法

4.2 docker-compose.yml 文件结构

4.2.1 基本结构

yaml 复制代码
version: '3.8'              # Compose 文件版本

services:                   # 定义服务
  service-name:
    # 服务配置
    image: image-name
    ports:
      - "host:container"

networks:                   # 定义网络(可选)
  network-name:
    driver: bridge

volumes:                    # 定义数据卷(可选)
  volume-name:
    driver: local

configs:                    # 配置文件(可选)
  config-name:
    file: ./config.conf

secrets:                    # 密钥(可选)
  secret-name:
    file: ./secret.txt

4.2.2 版本对照表

版本 Docker Engine 主要特性
3.8 19.03.0+ 推荐版本
3.7 18.06.0+ 稳定版本
3.0-3.6 1.13.0+ 旧版本
2.x 1.10.0+ 已废弃

推荐使用 3.8 版本。


4.3 Service 配置详解

4.3.1 image - 指定镜像

yaml 复制代码
services:
  web:
    # 使用 Docker Hub 镜像
    image: nginx:alpine

  app:
    # 使用私有仓库镜像
    image: myregistry.com/myapp:v1.0

  db:
    # 使用特定摘要
    image: mysql@sha256:abc123...

4.3.2 build - 构建镜像

yaml 复制代码
services:
  app:
    # 简单形式:指定 Dockerfile 所在目录
    build: .

  api:
    # 完整形式
    build:
      context: ./api              # 构建上下文目录
      dockerfile: Dockerfile.prod # Dockerfile 文件名
      args:                       # 构建参数
        VERSION: 1.0
        NODE_ENV: production
      target: production          # 多阶段构建目标
      cache_from:                 # 缓存来源
        - myapp:cache

示例:

yaml 复制代码
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - NODE_VERSION=18
    image: my-web:latest  # 构建后的镜像名
    ports:
      - "3000:3000"

4.3.3 container_name - 容器名称

yaml 复制代码
services:
  web:
    image: nginx
    container_name: my-nginx  # 自定义容器名

  # 不指定则自动生成:<项目名>_<服务名>_<序号>
  # 例如:myproject_web_1

4.3.4 ports - 端口映射

yaml 复制代码
services:
  web:
    image: nginx
    ports:
      # 简写形式:"主机端口:容器端口"
      - "8080:80"
      - "8443:443"

      # 只指定容器端口(主机端口随机)
      - "80"

      # 长格式(更明确)
      - target: 80        # 容器端口
        published: 8080   # 主机端口
        protocol: tcp     # 协议
        mode: host        # 模式

      # 绑定到特定 IP
      - "127.0.0.1:8080:80"

4.3.5 environment - 环境变量

yaml 复制代码
services:
  db:
    image: mysql:8.0
    environment:
      # Map 格式
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: myapp
      MYSQL_USER: user
      MYSQL_PASSWORD: password

  app:
    image: myapp
    environment:
      # Array 格式
      - NODE_ENV=production
      - API_KEY=abc123
      - DEBUG=false

使用 .env 文件:

.env 文件:

env 复制代码
# 数据库配置
DB_PASSWORD=secret123
DB_NAME=myapp

# 应用配置
APP_PORT=8080

docker-compose.yml:

yaml 复制代码
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}

  app:
    image: myapp
    environment:
      DB_HOST: db
      DB_PASSWORD: ${DB_PASSWORD}
    ports:
      - "${APP_PORT}:8080"

4.3.6 volumes - 数据卷

yaml 复制代码
services:
  db:
    image: mysql:8.0
    volumes:
      # 命名卷
      - mysql-data:/var/lib/mysql

      # 绑定挂载(相对路径)
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

      # 绑定挂载(绝对路径)
      - /host/path:/container/path

      # 只读挂载
      - ./config:/etc/config:ro

      # 长格式
      - type: volume
        source: mysql-data
        target: /var/lib/mysql

      # tmpfs
      - type: tmpfs
        target: /tmp
        tmpfs:
          size: 100M

# 定义命名卷
volumes:
  mysql-data:
    driver: local

4.3.7 networks - 网络配置

yaml 复制代码
services:
  web:
    image: nginx
    networks:
      # 连接到单个网络
      - frontend

  api:
    image: myapi
    networks:
      # 连接到多个网络
      - frontend
      - backend

  db:
    image: mysql
    networks:
      backend:
        # 指定 IP 地址
        ipv4_address: 172.20.0.10

# 定义网络
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

4.3.8 depends_on - 依赖关系

yaml 复制代码
services:
  web:
    image: nginx
    depends_on:
      - api          # 先启动 api,再启动 web

  api:
    image: myapi
    depends_on:
      - db
      - redis

  db:
    image: mysql

  redis:
    image: redis

# 启动顺序:db, redis → api → web
# 注意:depends_on 只保证启动顺序,不保证服务就绪

高级用法(等待服务就绪):

yaml 复制代码
services:
  web:
    image: nginx
    depends_on:
      api:
        condition: service_healthy  # 等待健康检查通过

  api:
    image: myapi
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 3

4.3.9 restart - 重启策略

yaml 复制代码
services:
  web:
    image: nginx
    restart: always         # 总是重启

  api:
    image: myapi
    restart: unless-stopped # 除非手动停止,否则总是重启

  worker:
    image: worker
    restart: on-failure     # 失败时重启

  batch:
    image: batch-job
    restart: "no"           # 不重启(默认)

重启策略说明:

  • no:不自动重启
  • always:总是重启(即使手动停止)
  • on-failure:退出码非 0 时重启
  • unless-stopped:总是重启,除非手动停止

4.3.10 command - 覆盖默认命令

yaml 复制代码
services:
  app:
    image: node:18
    command: npm start                    # 简单形式

  worker:
    image: python:3.11
    command: ["python", "worker.py"]      # 数组形式

  db:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password

4.3.11 entrypoint - 覆盖入口点

yaml 复制代码
services:
  app:
    image: myapp
    entrypoint: /app/entrypoint.sh

  worker:
    image: myapp
    entrypoint: ["python", "manage.py"]
    command: ["celery", "worker"]  # 作为 entrypoint 的参数

4.3.12 healthcheck - 健康检查

yaml 复制代码
services:
  api:
    image: myapi
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s       # 检查间隔
      timeout: 10s        # 超时时间
      retries: 3          # 重试次数
      start_period: 40s   # 启动等待时间

  # 禁用健康检查
  web:
    image: nginx
    healthcheck:
      disable: true

4.3.13 labels - 标签

yaml 复制代码
services:
  web:
    image: nginx
    labels:
      com.example.description: "Web Server"
      com.example.version: "1.0"

  # 数组形式
  api:
    image: myapi
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`api.example.com`)"

4.3.14 其他常用配置

yaml 复制代码
services:
  app:
    image: myapp

    # 工作目录
    working_dir: /app

    # 用户
    user: "1000:1000"

    # 主机名
    hostname: myapp-host

    # DNS
    dns:
      - 8.8.8.8
      - 8.8.4.4

    # DNS 搜索域
    dns_search:
      - example.com

    # 额外主机映射
    extra_hosts:
      - "somehost:192.168.1.100"
      - "otherhost:192.168.1.101"

    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

    # 日志配置
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

4.4 Docker Compose 命令

4.4.1 基本命令

bash 复制代码
# 启动所有服务(后台运行)
docker compose up -d

# 启动所有服务(前台运行,查看日志)
docker compose up

# 启动特定服务
docker compose up -d web api

# 停止所有服务
docker compose down

# 停止服务但保留容器
docker compose stop

# 启动已停止的服务
docker compose start

# 重启服务
docker compose restart

# 重启特定服务
docker compose restart web

4.4.2 查看状态

bash 复制代码
# 查看服务状态
docker compose ps

# 查看所有容器(包括已停止的)
docker compose ps -a

# 查看服务日志
docker compose logs

# 实时查看日志
docker compose logs -f

# 查看特定服务的日志
docker compose logs -f web

# 查看最后 100 行日志
docker compose logs --tail=100 web

# 显示时间戳
docker compose logs -t

4.4.3 构建和拉取

bash 复制代码
# 构建服务
docker compose build

# 构建时不使用缓存
docker compose build --no-cache

# 构建特定服务
docker compose build web

# 拉取服务镜像
docker compose pull

# 拉取特定服务镜像
docker compose pull db redis

4.4.4 执行命令

bash 复制代码
# 在运行的容器中执行命令
docker compose exec web sh
docker compose exec db mysql -uroot -p

# 在新容器中执行一次性命令
docker compose run web npm install
docker compose run api python manage.py migrate

# 不启动依赖服务
docker compose run --no-deps web npm test

# 删除容器后自动清理
docker compose run --rm worker python script.py

4.4.5 扩展和伸缩

bash 复制代码
# 扩展服务实例数量
docker compose up -d --scale web=3 --scale api=2

# 查看扩展后的容器
docker compose ps

4.4.6 清理资源

bash 复制代码
# 停止并删除容器、网络
docker compose down

# 同时删除数据卷(危险!)
docker compose down -v

# 同时删除镜像
docker compose down --rmi all

# 删除孤立容器
docker compose down --remove-orphans

4.4.7 其他实用命令

bash 复制代码
# 验证 compose 文件
docker compose config

# 查看服务的配置
docker compose config --services

# 暂停服务
docker compose pause web

# 恢复服务
docker compose unpause web

# 查看容器进程
docker compose top

# 查看服务端口
docker compose port web 80

4.5 实战案例

案例 1:LAMP 架构(Apache + PHP + MySQL)

项目结构:

复制代码
lamp-app/
├── docker-compose.yml
├── www/
│   └── index.php
├── mysql/
│   └── init.sql
└── apache/
    └── apache.conf

docker-compose.yml:

yaml 复制代码
version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: lamp-mysql
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: myapp
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppass
    volumes:
      - mysql-data:/var/lib/mysql
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - lamp-network
    restart: unless-stopped

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: lamp-phpmyadmin
    environment:
      PMA_HOST: db
      PMA_PORT: 3306
    ports:
      - "8081:80"
    depends_on:
      - db
    networks:
      - lamp-network
    restart: unless-stopped

  web:
    image: php:8.2-apache
    container_name: lamp-web
    ports:
      - "8080:80"
    volumes:
      - ./www:/var/www/html
      - ./apache/apache.conf:/etc/apache2/sites-available/000-default.conf
    depends_on:
      - db
    networks:
      - lamp-network
    restart: unless-stopped

volumes:
  mysql-data:

networks:
  lamp-network:
    driver: bridge

启动:

bash 复制代码
docker compose up -d
# 访问:http://localhost:8080
# phpMyAdmin:http://localhost:8081

案例 2:MEAN 架构(MongoDB + Express + Angular + Node.js)

docker-compose.yml:

yaml 复制代码
version: '3.8'

services:
  mongodb:
    image: mongo:6
    container_name: mean-mongo
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: secret
      MONGO_INITDB_DATABASE: meandb
    volumes:
      - mongo-data:/data/db
    ports:
      - "27017:27017"
    networks:
      - mean-network
    restart: unless-stopped

  backend:
    build: ./backend
    container_name: mean-api
    environment:
      NODE_ENV: development
      MONGO_URI: mongodb://admin:secret@mongodb:27017/meandb?authSource=admin
      PORT: 3000
    ports:
      - "3000:3000"
    volumes:
      - ./backend:/app
      - /app/node_modules
    depends_on:
      - mongodb
    networks:
      - mean-network
    restart: unless-stopped
    command: npm run dev

  frontend:
    build: ./frontend
    container_name: mean-frontend
    ports:
      - "4200:4200"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    depends_on:
      - backend
    networks:
      - mean-network
    restart: unless-stopped
    command: npm start

volumes:
  mongo-data:

networks:
  mean-network:
    driver: bridge

案例 3:微服务架构(带 NGINX 反向代理)

docker-compose.yml:

yaml 复制代码
version: '3.8'

services:
  # NGINX 反向代理
  nginx:
    image: nginx:alpine
    container_name: microservices-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
    depends_on:
      - user-service
      - product-service
      - order-service
    networks:
      - frontend
    restart: unless-stopped

  # 用户服务
  user-service:
    build: ./services/user
    container_name: user-service
    environment:
      DB_HOST: postgres
      REDIS_HOST: redis
    depends_on:
      - postgres
      - redis
    networks:
      - frontend
      - backend
    restart: unless-stopped

  # 产品服务
  product-service:
    build: ./services/product
    container_name: product-service
    environment:
      DB_HOST: postgres
      REDIS_HOST: redis
    depends_on:
      - postgres
      - redis
    networks:
      - frontend
      - backend
    restart: unless-stopped

  # 订单服务
  order-service:
    build: ./services/order
    container_name: order-service
    environment:
      DB_HOST: postgres
      REDIS_HOST: redis
      RABBITMQ_HOST: rabbitmq
    depends_on:
      - postgres
      - redis
      - rabbitmq
    networks:
      - frontend
      - backend
    restart: unless-stopped

  # PostgreSQL 数据库
  postgres:
    image: postgres:15-alpine
    container_name: microservices-postgres
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: microservices
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - backend
    restart: unless-stopped

  # Redis 缓存
  redis:
    image: redis:7-alpine
    container_name: microservices-redis
    networks:
      - backend
    restart: unless-stopped

  # RabbitMQ 消息队列
  rabbitmq:
    image: rabbitmq:3-management-alpine
    container_name: microservices-rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: secret
    ports:
      - "5672:5672"
      - "15672:15672"  # 管理界面
    networks:
      - backend
    restart: unless-stopped

volumes:
  postgres-data:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

案例 4:WordPress 完整部署

docker-compose.yml:

yaml 复制代码
version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: wordpress-db
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    networks:
      - wordpress-network
    restart: unless-stopped

  wordpress:
    image: wordpress:latest
    container_name: wordpress-app
    depends_on:
      - db
    ports:
      - "8000:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress-data:/var/www/html
    networks:
      - wordpress-network
    restart: unless-stopped

  # 可选:phpMyAdmin
  phpmyadmin:
    image: phpmyadmin:latest
    container_name: wordpress-phpmyadmin
    depends_on:
      - db
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      MYSQL_ROOT_PASSWORD: somewordpress
    networks:
      - wordpress-network
    restart: unless-stopped

volumes:
  db-data:
  wordpress-data:

networks:
  wordpress-network:
    driver: bridge

启动和配置:

bash 复制代码
# 启动服务
docker compose up -d

# 访问 WordPress 安装页面
# http://localhost:8000

# 访问 phpMyAdmin
# http://localhost:8081

4.6 高级技巧

4.6.1 多环境配置

基础配置(docker-compose.yml):

yaml 复制代码
version: '3.8'

services:
  app:
    image: myapp:latest
    environment:
      NODE_ENV: ${NODE_ENV}

开发环境覆盖(docker-compose.override.yml):

yaml 复制代码
version: '3.8'

services:
  app:
    build: .
    volumes:
      - ./src:/app/src
    environment:
      DEBUG: "true"
    command: npm run dev

生产环境覆盖(docker-compose.prod.yml):

yaml 复制代码
version: '3.8'

services:
  app:
    image: myapp:prod
    restart: always
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

使用方法:

bash 复制代码
# 开发环境(自动加载 override)
docker compose up -d

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

# 测试环境
docker compose -f docker-compose.yml -f docker-compose.test.yml up -d

4.6.2 扩展和继承

yaml 复制代码
# 定义可复用的配置
x-logging: &default-logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

x-healthcheck: &default-healthcheck
  interval: 30s
  timeout: 10s
  retries: 3

services:
  web:
    image: nginx
    logging: *default-logging
    healthcheck:
      <<: *default-healthcheck
      test: ["CMD", "curl", "-f", "http://localhost"]

  api:
    image: myapi
    logging: *default-logging
    healthcheck:
      <<: *default-healthcheck
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]

4.6.3 使用 profiles 管理服务组

yaml 复制代码
version: '3.8'

services:
  # 核心服务(总是启动)
  db:
    image: postgres:15

  api:
    image: myapi
    depends_on:
      - db

  # 开发工具(仅开发时启动)
  adminer:
    image: adminer
    profiles: ["dev"]
    ports:
      - "8080:8080"

  # 测试服务(仅测试时启动)
  test-runner:
    image: test-runner
    profiles: ["test"]
    command: npm test

使用:

bash 复制代码
# 只启动核心服务
docker compose up -d

# 启动核心服务 + 开发工具
docker compose --profile dev up -d

# 启动核心服务 + 测试服务
docker compose --profile test up -d

4.7 关键命令

bash 复制代码
docker compose up -d          # 启动服务
docker compose down           # 停止服务
docker compose ps             # 查看状态
docker compose logs -f        # 查看日志
docker compose exec           # 执行命令
docker compose build          # 构建镜像
docker compose restart        # 重启服务
相关推荐
我可以将你更新哟2 小时前
【docker】Dockerfile的编写
docker·容器
❀͜͡傀儡师3 小时前
docker部署orion-ops一站式智能运维管理平台
运维·docker·容器·orion-ops
DarkAthena4 小时前
【DOCKER+ORACLE】使用docker-compose一键拉起一个ORACLE-ADG一主一备环境
docker·oracle·容器
❀͜͡傀儡师4 小时前
docker部署Portracker 实现局域网实时端口监控
docker·容器·portracker
我可以将你更新哟4 小时前
【docker测试】在Ubuntu 22.04.3中部署docker
ubuntu·adb·docker
方也_arkling4 小时前
【Docker】Docker的安装和使用
docker·容器·github
❀͜͡傀儡师4 小时前
docker安装spug运维管理平台
运维·docker·容器
Damon小智5 小时前
Windows系统安装Docker容器搭建Linux环境
linux·运维·windows·docker·子系统
qq_317620315 小时前
03:Docker数据管理与网络
docker·数据持久化·端口映射·网络模式·volume数据卷