Docker Compose编排实战:多容器应用从开发到生产

**作者:洛水石** | **更新日期:2026-05-11** | **标签:Docker | Docker Compose | 容器编排 | DevOps**

前言

团队来了个新同事,问:"我本地跑个项目要怎么配数据库、Redis、消息队列?"

以前的我:给你10个配置文件,自己装MySQL、Redis、Elasticsearch...大概配置一天能跑起来。

现在的我:一条命令,`docker-compose up -d`,3分钟搞定。

Docker Compose就是来解决****多容器协作****问题的。本文从实战出发,手把手教你用Docker Compose搭建完整的开发/生产环境。

一、Docker Compose核心概念

1.1 为什么需要Compose

|---------------|----------|-----------------|
| 场景 | 痛点 | Compose解决方案 |
| **本地开发** | 手动安装多个服务 | 一键启动整套环境 |
| **测试环境** | 环境不一致 | 固定版本,隔离环境 |
| **演示部署** | 快速交付 | 配置文件即交付物 |
| **CI/CD** | 构建复杂 | 可重复、可版本化 |

1.2 核心组件

▲ Docker Compose架构图

docker-compose.yml
├── version: "3.8" # Compose版本
├── services: # 服务定义
│ ├── web: # 服务名
│ │ ├── image: nginx # 或 build: .
│ │ ├── ports: # 端口映射
│ │ ├── environment: # 环境变量
│ │ ├── volumes: # 持久化
│ │ ├── depends_on: # 依赖关系
│ │ └── networks: # 网络配置
│ ├── api:
│ └── db:
├── networks: # 网络定义
└── volumes: # 卷定义

二、快速开始

▲ Docker容器生命周期

2.1 第一个Compose项目

docker-compose.yml

version: "3.8"

services:
web:
image: nginx:alpine
ports:

  • "80:80"
    volumes:
  • ./html:/usr/share/nginx/html:ro
    depends_on:
  • api
    networks:
  • app-network

api:
image: node:18-alpine
working_dir: /app
volumes:

  • ./api:/app
    command: npm start
    networks:
  • app-network

networks:
app-network:
driver: bridge

启动

docker-compose up -d

查看状态

docker-compose ps

查看日志

docker-compose logs -f api

停止

docker-compose down

重新构建

docker-compose up -d --build

2.2 Laravel项目实战

docker-compose.yml

version: "3.8"

services:

PHP应用

app:
build:
context: ./docker/php
dockerfile: Dockerfile
container_name: laravel_app
ports:

  • "8000:8000"
    volumes:
  • ./:/var/www/html
    depends_on:
  • mysql
  • redis
    environment:
  • DB_HOST=mysql
  • DB_DATABASE=laravel
  • DB_USERNAME=root
  • DB_PASSWORD=secret
  • REDIS_HOST=redis
    networks:
  • laravel

Nginx反向代理

nginx:
image: nginx:alpine
container_name: laravel_nginx
ports:

  • "80:80"
    volumes:
  • ./:/var/www/html
  • ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
    depends_on:
  • app
    networks:
  • laravel

MySQL数据库

mysql:
image: mysql:8.0
container_name: laravel_mysql
ports:

  • "3306:3306"
    environment:
    MYSQL_ROOT_PASSWORD: secret
    MYSQL_DATABASE: laravel
    MYSQL_USER: laravel
    MYSQL_PASSWORD: laravel123
    volumes:
  • mysql_data:/var/lib/mysql
    networks:
  • laravel

Redis缓存

redis:
image: redis:7-alpine
container_name: laravel_redis
ports:

  • "6379:6379"
    volumes:
  • redis_data:/data
    command: redis-server --appendonly yes
    networks:
  • laravel

Composer依赖

composer:
image: composer:2
container_name: laravel_composer
volumes:

  • ./:/app
    working_dir: /app
    depends_on:
  • app
    networks:
  • laravel

networks:
laravel:
driver: bridge

volumes:
mysql_data:
redis_data:

2.3 Nginx配置

docker/nginx/conf.d/default.conf

upstream laravel {
server app:9000;
}

server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;

charset utf-8;

location / {
try_files uri uri/ /index.php?$query_string;
}

location ~ \.php { fastcgi_pass laravel; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME realpath_root$fastcgi_script_name;
include fastcgi_params;
}

location ~ /\.(?!well-known).* {
deny all;
}
}

2.4 PHP Dockerfile

docker/php/Dockerfile

FROM php:8.2-fpm-alpine

安装扩展

RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl bcmath

安装Redis扩展

RUN pecl install redis && docker-php-ext-enable redis

安装Composer

COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html

EXPOSE 9000

三、高级配置

3.1 环境变量文件

.env 文件

MYSQL_ROOT_PASSWORD=secret
MYSQL_DATABASE=laravel
REDIS_PASSWORD=redis123
NGINX_PORT=80

docker-compose.yml

version: "3.8"

services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: {MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: {MYSQL_DATABASE}
env_file:

  • .env
    volumes:
  • mysql_data:/var/lib/mysql

3.2 多环境配置

docker-compose.yml (基础配置)

version: "3.8"

services:
app:
build: ./docker/php
volumes:

  • ./:/var/www/html
    depends_on:
  • mysql

mysql:
image: mysql:8.0
volumes:

  • mysql_data:/var/lib/mysql

networks:
app-network:
driver: bridge

volumes:
mysql_data:

docker-compose.dev.yml (开发环境)

version: "3.8"

services:
app:
environment:

  • DEBUG=true
  • LOG_LEVEL=debug
    ports:
  • "8000:8000"

mysql:
ports:

  • "3306:3306"

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

version: "3.8"

services:
app:
environment:

  • DEBUG=false
  • LOG_LEVEL=info
    restart: unless-stopped
    volumes:
  • app_data:/var/www/html

mysql:
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_PROD_PASSWORD}
restart: unless-stopped

networks:
app-network:
driver: overlay

volumes:
app_data:

使用不同环境

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

3.3 资源限制

version: "3.8"

services:
app:
deploy:
resources:
limits:
cpus: '1.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M

mysql:
deploy:
resources:
limits:
cpus: '2.0'
memory: 4G

3.4 健康检查

version: "3.8"

services:
mysql:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s

app:
depends_on:
mysql:
condition: service_healthy # 等待健康

redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3

四、Swarm集群编排

▲ Docker Swarm集群架构

4.1 切换到Swarm模式

初始化Swarm

docker swarm init

加入Worker节点

docker swarm join-token worker

查看节点

docker node ls

4.2 Swarm部署

docker-compose.swarm.yml

version: "3.8"

services:
app:
image: myapp:latest
deploy:
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
resources:
limits:
cpus: '1.0'
memory: 1G
ports:

  • "80:80"
    volumes:
  • app_data:/app/data
    configs:
  • source: app_config
    target: /app/config.json
    secrets:
  • source: db_password
    target: /run/secrets/db_password

mysql:
image: mysql:8.0
volumes:

  • mysql_data:/var/lib/mysql
    secrets:
  • source: db_password

configs:
app_config:
file: ./config/app.json

secrets:
db_password:
file: ./secrets/db_password.txt

volumes:
app_data:
mysql_data:

部署到Swarm

docker stack deploy -c docker-compose.swarm.yml myapp

查看服务

docker service ls
docker service ps myapp_app

扩缩容

docker service scale myapp_app=5

更新服务

docker service update --image myapp:v2 myapp_app

五、日志与监控

5.1 日志配置

version: "3.8"

services:
app:
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "5"
compress: "true"
volumes:

  • ./logs:/var/www/html/storage/logs

5.2 ELK日志收集

version: "3.8"

services:
app:
logging:
driver: fluentd
options:
fluentd-address: localhost:24224
tag: app.logs

fluentd:
image: fluent/fluentd:v1.16
ports:

  • "24224:24224"
  • "24224:24224/udp"
    volumes:
  • ./docker/fluentd/conf:/fluentd/etc
    depends_on:
  • elasticsearch

elasticsearch:
image: elasticsearch:8.11.0
environment:

  • discovery.type=single-node
  • xpack.security.enabled=false
    volumes:
  • es_data:/usr/share/elasticsearch/data

kibana:
image: kibana:8.11.0
ports:

  • "5601:5601"
    depends_on:
  • elasticsearch

volumes:
es_data:

六、CI/CD集成

6.1 GitHub Actions

.github/workflows/deploy.yml

name: Deploy to Staging

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest

steps:

  • uses: actions/checkout@v4

  • name: Build images
    run: |
    docker-compose -f docker-compose.yml -f docker-compose.prod.yml build

  • name: Push to registry
    run: |
    echo {{ secrets.DOCKER_TOKEN }} \| docker login -u {{ secrets.DOCKER_USER }} --password-stdin
    docker-compose -f docker-compose.yml -f docker-compose.prod.yml push

  • name: Deploy to server
    uses: appleboy/ssh-action@master
    with:
    host: {{ secrets.SERVER_HOST }} username: {{ secrets.SERVER_USER }}
    key: ${{ secrets.SERVER_KEY }}
    script: |
    cd /opt/app
    docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
    docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
    docker-compose -f docker-compose.yml -f docker-compose.prod.yml logs -f --tail=100

七、常见问题

Q1: 端口冲突?

检查端口占用

netstat -tlnp | grep 80

停止其他容器

docker-compose down

修改端口映射

ports:

  • "8080:80" # 改为8080

Q2: 数据卷权限问题?

在Dockerfile中设置

RUN chown -R www-data:www-data /var/www/html
RUN chmod -R 755 /var/www/html

Q3: 网络不通?

查看网络

docker network ls
docker network inspect app_app-network

手动创建网络

docker network create my-network

在compose中引用

networks:
my-network:
external: true

总结

Docker Compose最佳实践:

|--------------|-------------------|
| 场景 | 建议 |
| **开发环境** | 挂载源码卷,热重载 |
| **测试环境** | 固定镜像版本,隔离网络 |
| **生产环境** | Swarm部署,资源限制,日志收集 |

**核心命令**

日常操作

docker-compose up -d # 启动
docker-compose down # 停止
docker-compose restart # 重启
docker-compose logs -f # 查看日志

维护操作

docker-compose build --no-cache # 重新构建
docker-compose exec app bash # 进入容器
docker-compose ps # 查看状态

清理

docker-compose down -v # 删除卷
docker system prune -f # 清理未使用资源

**进阶方向**

  1. Kubernetes(K8s)编排大规模集群
  2. Docker Stack部署Swarm集群
  3. Helm Charts管理复杂应用

*一条命令,搭建完整环境;一份配置,实现快速交付。*

相关推荐
身如柳絮随风扬2 小时前
Nginx 完全指南:核心用途、配置文件详解与动态配置实践
运维·nginx
2601_956139422 小时前
广州VI设计公司哪家强
linux·运维·服务器·python
@encryption2 小时前
RHCE --- 第三节
运维
Vinton_Liu2 小时前
NAT 类型详解:四种 NAT 的数据流与原理解析
运维·服务器
一个处女座的程序猿O(∩_∩)O2 小时前
如何保持nginx配置与前端打包dist的路径保持一致、解决页面刷新白屏以及页面跳转问题
运维·前端·nginx
想唱rap2 小时前
五种IO模型和非阻塞IO
linux·运维·服务器·网络·数据库·tcp/ip
环流_2 小时前
nacos:负载均衡 3大核心操作
运维·nacos·负载均衡
阿洛学长3 小时前
CSDN、掘金、简书博客文章如何转为Markdown?
运维·数据库·架构·php·持续部署
方安乐3 小时前
交换机的自学机制
运维·服务器·网络