在生产环境中,手动部署服务不仅繁琐,还容易因环境差异引发各种兼容性问题。Docker Compose 通过声明式配置,让你只需一条命令就能启动完整的 Web 服务栈。本文详细介绍如何使用 Docker Compose 部署 Nginx 反向代理 + MySQL 数据库 + Redis 缓存的经典组合。
一、项目结构规划
首先创建项目目录,所有配置文件集中管理,便于迁移和版本控制:
mkdir -p ~/prod-deploy && cd ~/prod-deploy
mkdir -p nginx/conf.d mysql/conf redis/conf data/mysql data/redis logs/nginx logs/mysql logs/redis
touch logs/nginx/.gitkeep logs/mysql/.gitkeep logs/redis/.gitkeep
ls -la
最终目录结构如下:
prod-deploy/
├── docker-compose.yml
├── .env
├── nginx/
│ ├── Dockerfile
│ └── conf.d/
│ └── default.conf
├── mysql/
│ └── conf/
│ └── custom.cnf
├── redis/
│ └── conf/
│ └── redis.conf
├── data/
│ ├── mysql/
│ └── redis/
└── logs/
├── nginx/
├── mysql/
└── redis/
二、编写 .env 环境变量文件
敏感信息(密码、密钥)统一放在 .env 文件中,不要提交到代码仓库:
# MySQL 配置
MYSQL_ROOT_PASSWORD=MySecureRootPass2026!
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=AppUserPass2026!
# Redis 配置
REDIS_PASSWORD=RedisSecurePass2026
# 时区
TZ=Asia/Shanghai
# 网络
COMPOSE_PROJECT_NAME=prod_stack
注意:.env 文件要加入 .gitignore,避免密码泄露。
三、编写 docker-compose.yml
这是整个部署的核心文件,定义了四个服务:app(Nginx)、mysql、redis,以及用 Docker-in-Docker 方式启动的 PHP-FPM(或任何后端应用)。
version: "3.9"
services:
# Nginx 反向代理服务
nginx:
build: ./nginx
container_name: prod_nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./logs/nginx:/var/log/nginx
- ./data/www:/usr/share/nginx/html:ro
depends_on:
app:
condition: service_healthy
networks:
- backend
# PHP-FPM 应用服务(示例)
app:
image: php:8.2-fpm-alpine
container_name: prod_app
restart: always
working_dir: /var/www/html
volumes:
- ./data/www:/var/www/html:rw
environment:
- DB_HOST=mysql
- DB_PORT=3306
- DB_DATABASE=${MYSQL_DATABASE}
- DB_USERNAME=${MYSQL_USER}
- DB_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD}
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
healthcheck:
test: ["CMD", "php-fpm", "-t"]
interval: 10s
timeout: 5s
retries: 3
networks:
- backend
# MySQL 数据库服务
mysql:
image: mysql:8.0
container_name: prod_mysql
restart: always
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: ${TZ}
volumes:
- ./mysql/conf:/etc/mysql/conf.d:ro
- ./data/mysql:/var/lib/mysql
- ./logs/mysql:/var/log/mysql
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- backend
# Redis 缓存服务
redis:
image: redis:7-alpine
container_name: prod_redis
restart: always
command: redis-server /usr/local/etc/redis/redis.conf --requirepass ${REDIS_PASSWORD}
volumes:
- ./redis/conf:/usr/local/etc/redis:ro
- ./data/redis:/data
- ./logs/redis:/logs
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
- backend
networks:
backend:
driver: bridge
四、Nginx 配置详解
4.1 构建自定义 Nginx 镜像(包含 SSL 和 realip 模块)
# nginx/Dockerfile
FROM nginx:1.25-alpine
# 安装额外工具(用于健康检查)
RUN apk add --no-cache curl
# 替换默认配置(挂载外部配置)
# 这里不COPY任何文件,全部通过 volume 挂载,保持灵活性
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
4.2 Nginx 站点配置
# nginx/conf.d/default.conf
upstream php_backend {
server app:9000;
keepalive 32;
}
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.php index.html;
# 访问日志
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# 默认首页
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM 处理
location ~ \.php$ {
fastcgi_pass php_backend;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 超时配置
fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
# 静态资源缓存(30天)
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
五、MySQL 配置文件
# mysql/conf/custom.cnf
[mysqld]
# 基础设置
max_connections = 500
wait_timeout = 600
interactive_timeout = 600
# 字符集
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# InnoDB 设置
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
# 查询缓存(MySQL 8.0 已移除,此处仅作记录)
# query_cache_type = 1
# query_cache_size = 64M
# 慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# 二进制日志(用于主从复制)
log_bin = mysql-bin
expire_logs_days = 7
max_binlog_size = 100M
[client]
default-character-set = utf8mb4
六、Redis 配置文件
# redis/conf/redis.conf
# 安全认证
requirepass RedisSecurePass2026
# 持久化策略
save 900 1
save 300 10
save 60 10000
# AOF 持久化
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
# 内存策略(当内存满时淘汰最少使用的key)
maxmemory 256mb
maxmemory-policy allkeys-lru
# 日志
loglevel notice
logfile "/logs/redis.log"
# 安全
protected-mode yes
bind 0.0.0.0
# 超时
timeout 300
tcp-keepalive 60
七、常用运维命令
7.1 启动与停止
# 前台启动(调试用)
docker-compose up
# 后台启动(生产环境)
docker-compose up -d
# 带日志启动
docker-compose up -d --build
docker-compose logs -f
# 停止并清理
docker-compose down
# 停止并清理数据卷(慎用,会丢失数据)
docker-compose down -v
7.2 容器管理
# 进入容器(调试)
docker exec -it prod_nginx sh
docker exec -it prod_mysql mysql -u root -p
docker exec -it prod_redis redis-cli -a RedisSecurePass2026
# 查看容器状态
docker-compose ps
# 查看资源使用
docker stats
# 查看日志
docker-compose logs -f --tail=100 nginx
docker-compose logs mysql --tail=50
docker-compose logs redis --tail=50
7.3 数据库备份与恢复
# 备份数据库
docker exec prod_mysql sh -c 'exec mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction --routines --triggers --events "$MYSQL_DATABASE"' > backup_$(date +%Y%m%d_%H%M%S).sql
# 恢复数据库
docker exec -i prod_mysql sh -c 'exec mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' < backup_20260421_120000.sql
# 备份 Redis 数据(生成 RDB 快照)
docker exec prod_redis redis-cli -a RedisSecurePass2026 SAVE
7.4 更新服务
# 重新构建并启动
docker-compose up -d --build
# 单独重启某个服务
docker-compose restart nginx
docker-compose restart mysql
docker-compose restart redis
# 清理未使用的镜像和网络
docker system prune -f
八、数据迁移到新服务器
只需复制整个目录,到新机器执行 docker-compose up -d 即可:
# 打包整个项目(含数据)
tar -czvf prod-backup.tar.gz \
docker-compose.yml .env nginx/ mysql/ redis/ data/ logs/
# 传输到新服务器
scp prod-backup.tar.gz root@newserver:/opt/prod-deploy/
# 在新服务器解压并启动
ssh root@newserver
cd /opt/prod-deploy
tar -xzvf prod-backup.tar.gz
docker-compose up -d
提示:首次在新机器启动时,会自动拉取镜像,请确保网络通畅。
九、健康检查与监控
Docker Compose 的 healthcheck 会在 MySQL 完全就绪后才启动依赖它的服务,避免连接失败。以下命令可以手动验证各服务健康状态:
# 检查健康状态
docker inspect --format='{{.State.Health.Status}}' prod_mysql
docker inspect --format='{{.State.Health.Status}}' prod_redis
docker inspect --format='{{.State.Health.Status}}' prod_app
# Nginx 配置文件检查
docker exec prod_nginx nginx -t
# 测试 PHP-FPM
docker exec prod_app php-fpm -t
# 测试 Redis 连接
docker exec prod_redis redis-cli -a RedisSecurePass2026 PING
十、总结
通过 Docker Compose,我们实现了:
- ✅ Nginx:反向代理 + 静态资源服务 + 安全头
- ✅ MySQL:持久化存储 + 自动健康检查 + 备份脚本
- ✅ Redis:缓存加速 + 内存管理 + AOF 持久化
- ✅ 一键部署:
docker-compose up -d启动全套服务 - ✅ 数据持久化:宿主机目录映射,不丢数据
- ✅ 配置分离:环境变量管理敏感信息
整套架构适合中小型项目的生产环境部署,配置清晰、易于维护、可完整迁移。有任何问题欢迎留言交流!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END










暂无评论内容