第09章:Docker Compose 编排
第09章:Docker Compose 编排
本章目标:掌握 Docker Compose 的语法和使用,学会编排多容器应用,实现一键部署和管理。
9.1 Docker Compose 是什么
9.1.1 定义与价值
Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 YAML 文件,你可以配置应用的所有服务、网络和存储卷,然后用一个命令创建并启动所有服务。
传统方式(多个终端分别操作): 终端1: docker run -d --name db mysql 终端2: docker run -d --name redis redis 终端3: docker run -d --name app myapp 终端4: docker network connect ... 终端5: docker run -d --name nginx nginx Docker Compose 方式(一个文件,一条命令): docker compose up -d9.1.2 Compose 的优势
| 优势 | 说明 |
|---|---|
| 声明式配置 | 一个 YAML 文件描述整个应用架构 |
| 一键启停 | docker compose up/down管理所有服务 |
| 环境隔离 | 每个 compose 项目独立的网络和卷 |
| 开发/测试/生产 | 同一配置适配不同环境 |
| 可版本控制 | compose 文件可以纳入 Git 管理 |
9.2 Compose 文件语法详解
9.2.1 文件结构
# docker-compose.yml 完整结构version:'3.8'# Compose 文件版本services:# 服务定义(容器配置)web:# ... 服务配置db:# ... 服务配置networks:# 自定义网络frontend:backend:volumes:# 声明命名卷db-data:cache-data:configs:# 配置对象app-config:file:./config.ymlsecrets:# 敏感信息db-password:file:./secrets/db_password.txt9.2.2 services 配置详解
services:# ========== 服务名称 ==========web-app:# 基本配置image:myapp:latest# 使用镜像# 或从 Dockerfile 构建build:context:.# 构建上下文dockerfile:Dockerfile# Dockerfile 文件名args:# 构建参数VERSION:1.0.0target:production# 多阶段构建的目标阶段container_name:my-web-app# 容器名称hostname:web-server# 主机名restart:unless-stopped# 重启策略# 环境变量environment:-APP_ENV=production-DB_HOST=db-DB_PORT=3306-REDIS_HOST=redis# 从文件加载环境变量env_file:-.env-.env.production# 端口映射ports:-"80:80"-"443:443"# - "127.0.0.1:8080:80" # 仅本地访问# - "8080:80/tcp" # 指定协议# 卷挂载volumes:-./src:/app/src:ro# 只读挂载-app-logs:/app/logs# 命名卷-/data/images:/app/images# 绝对路径# 网络networks:-frontend-backend# 资源限制deploy:resources:limits:cpus:'2.0'memory:1Greservations:cpus:'0.5'memory:256Mreplicas:2# 副本数restart_policy:condition:on-failuremax_attempts:3# 健康检查healthcheck:test:["CMD","curl","-f","http://localhost:80/health"]interval:30stimeout:5sretries:3start_period:10s# 依赖关系depends_on:db:condition:service_healthy# 等待依赖服务健康redis:condition:service_started# 链接(旧语法,不推荐)links:-db-redis# 别名(DNS 名称)aliases:-web-application# 日志配置logging:driver:json-fileoptions:max-size:"10m"max-file:"3"# 安全选项security_opt:-no-new-privileges:trueread_only:true# 只读文件系统tmpfs:-/tmp-/var/run# 容器内命令command:["python3","app.py"]# 或# command: python3 app.py# 入口点entrypoint:["/app/entrypoint.sh"]# 工作目录working_dir:/app# 用户user:"1000:1000"# 其他容器extra_hosts:-"other-host:192.168.1.100"# PID 模式pid:"host"# 配置文件configs:-source:app-configtarget:/app/config.ymlmode:04449.2.3 networks 配置详解
networks:# 默认 bridge 网络default:driver:bridge# 自定义网络frontend:driver:bridgedriver_opts:com.docker.network.bridge.name:"frontend-br"ipam:driver:defaultconfig:-subnet:192.168.100.0/24gateway:192.168.100.1labels:-"com.example.network.frontend=true"# Overlay 网络(用于 Swarm)backend:driver:overlayattachable:true# 外部网络(使用已存在的网络)existing-network:external:true9.2.4 volumes 配置详解
volumes:# 命名卷(Docker 管理)db-data:driver:localdriver_opts:type:nonedevice:/data/mysqlo:bind# 带标签的卷app-logs:labels:com.example.description:"Application logs"com.example.department:"Operations"# 外部卷(使用已存在的卷)existing-volume:external:true# tmpfs 卷temp-cache:driver:localdriver_opts:type:tmpfsdevice:tmpfso:size=100m,uid=10009.3 Compose 常用命令
9.3.1 服务管理
# 启动所有服务dockercompose up# 后台启动dockercompose up-d# 重建并启动(有变更时)dockercompose up-d--build# 停止并删除容器dockercompose down# 停止并删除容器和卷dockercompose down-v# 查看服务状态dockercomposeps# 查看服务日志dockercompose logs# 实时跟踪日志dockercompose logs-f# 查看特定服务日志dockercompose logs-fweb-app# 查看服务资源使用dockercomposetop9.3.2 单个服务操作
# 启动特定服务dockercompose up-ddb# 停止特定服务dockercompose stop web-app# 重启特定服务dockercompose restart web-app# 进入服务容器dockercomposeexecweb-appbashdockercomposeexecdb mysql-uroot-p# 查看服务进程dockercomposetopweb-app9.3.3 构建相关
# 构建所有服务dockercompose build# 构建特定服务dockercompose build web-app# 不使用缓存构建dockercompose build --no-cache# 拉取最新镜像dockercompose pull# 推送镜像dockercompose push9.3.4 镜像和卷管理
# 列出项目中的镜像dockercompose images# 删除停止的容器dockercomposerm# 列出项目中的卷dockercompose volumels# 删除未使用的卷dockercompose down-v9.4 环境变量管理
9.4.1 多种设置方式
services:web-app:# 方式1:直接在 compose 文件中设置environment:APP_ENV:productionDB_HOST:db# 方式2:从文件加载env_file:-.env# 方式3:使用变量替换(compose 文件中)image:myapp:${VERSION:-latest}# 方式4:在容器内使用command:python3 app.py9.4.2 .env 文件示例
# .env 文件APP_ENV=productionAPP_VERSION=1.0.0DB_ROOT_PASSWORD=supersecretDB_NAME=myappDB_USER=appuserDB_PASSWORD=apppass123REDIS_PASSWORD=redis1239.4.3 多环境配置
# 项目结构project/ ├── docker-compose.yml# 基础配置├── docker-compose.override.yml# 开发环境覆盖├── docker-compose.prod.yml# 生产环境配置├── .env# 默认环境变量├── .env.dev# 开发环境变量└── .env.prod# 生产环境变量# 开发环境(默认)dockercompose up-d# 生产环境dockercompose-fdocker-compose.yml-fdocker-compose.prod.yml up-d# 或使用环境变量COMPOSE_FILE=docker-compose.yml:docker-compose.prod.ymldockercompose up-d9.5 完整的多容器应用示例
9.5.1 LAMP 架构(Linux + Apache + MySQL + PHP)
# docker-compose.ymlversion:'3.8'services:# Web 服务器apache:image:php:8.2-apachecontainer_name:lamp-apacheports:-"80:80"-"443:443"volumes:-./src:/var/www/html-./apache/conf.d:/etc/apache2/sites-enablednetworks:-lamp-networkdepends_on:mysql:condition:service_healthyenvironment:-DB_HOST=mysql-DB_NAME=${DB_NAME:-laravel}-DB_USER=${DB_USER:-user}-DB_PASSWORD=${DB_PASSWORD:-password}restart:unless-stopped# MySQL 数据库mysql:image:mysql:8.0container_name:lamp-mysqlenvironment:MYSQL_ROOT_PASSWORD:${DB_ROOT_PASSWORD:-rootpassword}MYSQL_DATABASE:${DB_NAME:-laravel}MYSQL_USER:${DB_USER:-user}MYSQL_PASSWORD:${DB_PASSWORD:-password}volumes:-mysql-data:/var/lib/mysql-./mysql/initdb:/docker-entrypoint-initdb.dnetworks:-lamp-networkhealthcheck:test:["CMD","mysqladmin","ping","-h","localhost"]interval:10stimeout:5sretries:5restart:unless-stopped# Redis 缓存redis:image:redis:7-alpinecontainer_name:lamp-rediscommand:redis-server--requirepass ${REDIS_PASSWORD:-redis123}volumes:-redis-data:/datanetworks:-lamp-networkhealthcheck:test:["CMD","redis-cli","ping"]interval:10stimeout:5sretries:5restart:unless-stoppednetworks:lamp-network:driver:bridgevolumes:mysql-data:redis-data:9.5.2 Python + Nginx + Gunicorn + PostgreSQL + Redis
# docker-compose.ymlversion:'3.8'services:# Nginx 反向代理nginx:image:nginx:alpinecontainer_name:app-nginxports:-"80:80"-"443:443"volumes:-./nginx/conf.d:/etc/nginx/conf.d:ro-./nginx/ssl:/etc/nginx/ssl:ro-static-files:/app/static:ronetworks:-app-networkdepends_on:-webrestart:unless-stopped# Python Web 应用web:build:context:.dockerfile:Dockerfiletarget:productioncontainer_name:app-webvolumes:-static-files:/app/static-./logs:/app/logsenvironment:-APP_ENV=production-DATABASE_URL=postgresql+asyncpg://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}-REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0networks:-app-networkdepends_on:postgres:condition:service_healthyredis:condition:service_healthyhealthcheck:test:["CMD","curl","-f","http://localhost:8000/health"]interval:30stimeout:5sretries:3restart:unless-stopped# PostgreSQL 数据库postgres:image:postgres:15-alpinecontainer_name:app-postgresenvironment:POSTGRES_DB:${DB_NAME:-myapp}POSTGRES_USER:${DB_USER:-appuser}POSTGRES_PASSWORD:${DB_PASSWORD:-apppass123}PGDATA:/var/lib/postgresql/data/pgdatavolumes:-postgres-data:/var/lib/postgresql/datanetworks:-app-networkhealthcheck:test:["CMD-SHELL","pg_isready -U ${DB_USER:-appuser}"]interval:10stimeout:5sretries:5restart:unless-stopped# Redis 缓存redis:image:redis:7-alpinecontainer_name:app-rediscommand:redis-server--requirepass ${REDIS_PASSWORD:-redis123}volumes:-redis-data:/datanetworks:-app-networkhealthcheck:test:["CMD","redis-cli","-a","${REDIS_PASSWORD:-redis123}","ping"]interval:10stimeout:5sretries:5restart:unless-stoppednetworks:app-network:driver:bridgevolumes:static-files:postgres-data:redis-data:9.5.3 Node.js + MongoDB + Redis
# docker-compose.ymlversion:'3.8'services:# Node.js 应用app:build:context:.dockerfile:Dockerfilecontainer_name:node-appports:-"3000:3000"environment:-NODE_ENV=production-MONGODB_URI=mongodb://mongo:27017/myapp-REDIS_URL=redis://redis:6379volumes:-./uploads:/app/uploadsnetworks:-node-networkdepends_on:mongo:condition:service_healthyredis:condition:service_healthyhealthcheck:test:["CMD","curl","-f","http://localhost:3000/health"]interval:30stimeout:5sretries:3restart:unless-stopped# MongoDB 数据库mongo:image:mongo:6container_name:node-mongoenvironment:MONGO_INITDB_ROOT_USERNAME:${MONGO_USER:-admin}MONGO_INITDB_ROOT_PASSWORD:${MONGO_PASSWORD:-password}volumes:-mongo-data:/data/db-mongo-config:/data/configdbnetworks:-node-networkhealthcheck:test:["CMD","mongosh","--eval","db.adminCommand('ping')"]interval:10stimeout:5sretries:5restart:unless-stopped# Redis 缓存redis:image:redis:7-alpinecontainer_name:node-rediscommand:redis-server--requirepass ${REDIS_PASSWORD:-redis123}volumes:-redis-data:/datanetworks:-node-networkhealthcheck:test:["CMD","redis-cli","-a","${REDIS_PASSWORD:-redis123}","ping"]interval:10stimeout:5sretries:5restart:unless-stoppednetworks:node-network:driver:bridgevolumes:mongo-data:mongo-config:redis-data:9.6 Compose 高级特性
9.6.1 服务扩缩容
# 扩容服务(启动多个实例)dockercompose up-d--scaleweb=3# 缩容dockercompose up-d--scaleweb=1# 注意:使用 scale 时不要映射固定端口# 应该使用随机端口或负载均衡器9.6.2 服务依赖与启动顺序
services:db:image:mysql:8.0# ...redis:image:redis:7# ...web:image:myappdepends_on:db:condition:service_healthy# 等待数据库健康redis:condition:service_started# 只需 Redis 启动# ...9.6.3 配置文件挂载
services:nginx:image:nginx:alpineconfigs:-source:nginx-conftarget:/etc/nginx/conf.d/default.confmode:0444configs:nginx-conf:file:./nginx/default.conf9.6.4 敏感信息管理
services:db:image:mysql:8.0secrets:-db-passwordenvironment:MYSQL_PASSWORD_FILE:/run/secrets/db-passwordsecrets:db-password:file:./secrets/db_password.txt9.7 动手实验
实验 9.1:WordPress 一键部署
# 创建项目目录mkdir-p~/docker-lab/wordpresscd~/docker-lab/wordpress# 创建 docker-compose.ymlcat>docker-compose.yml<<'EOF' version: '3.8' services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress volumes: - db-data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped wordpress: image: wordpress:latest ports: - "8080:80" environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress volumes: - wp-data:/var/www/html depends_on: db: condition: service_healthy restart: unless-stopped volumes: db-data: wp-data: EOF# 启动dockercompose up-d# 访问 http://localhost:8080 完成 WordPress 安装实验 9.2:多服务应用
# 使用上面的 Python + Nginx + PostgreSQL + Redis 示例cd~/docker-lab# 创建项目结构mkdir-pnginx/conf.d# 创建 Nginx 配置cat>nginx/conf.d/default.conf<<'EOF' upstream web { server web:8000; } server { listen 80; server_name localhost; location /static/ { alias /app/static/; } location / { proxy_pass http://web; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF# 启动所有服务dockercompose up-d# 查看服务状态dockercomposeps# 查看日志dockercompose logs-f9.8 本章小结
| 命令 | 说明 |
|---|---|
docker compose up -d | 后台启动所有服务 |
docker compose down | 停止并删除所有服务 |
docker compose ps | 查看服务状态 |
docker compose logs -f | 实时跟踪日志 |
docker compose exec <svc> bash | 进入服务容器 |
docker compose restart <svc> | 重启指定服务 |
docker compose build | 构建服务镜像 |
docker compose pull | 拉取最新镜像 |
9.9 课后练习
- 基础题:使用 Docker Compose 部署 WordPress + MySQL。
- 进阶题:编写一个包含 Web、数据库、缓存、反向代理的完整 compose 文件。
- 实践题:使用多环境配置(dev/prod)管理不同的部署环境。
📖 下一章:企业级镜像仓库 —— 搭建和管理私有镜像仓库
