Files
easygoadmin-wiki/EasyGoAdmin_Beego_NaiveVue/zh/deploy/docker.md
T
2026-10-20 21:19:44 +08:00

568 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 11.6 Docker 生产部署
:::tip 概述
本节提供基于 Docker Compose 的生产环境部署方案,包含 **Nginx 反向代理**、**PHP-FPM 应用**、**MySQL 数据库**和 **Redis 缓存**四个服务的容器编排配置。所有脚本均带详细注释,适合快速搭建生产环境,也便于 CI/CD 集成。
:::
## 架构说明
```
浏览器 → 宿主机:8000 → [Nginx 容器:80] → [PHP-FPM 容器:9000] → ThinkPHP 应用
↕
[MySQL 容器:3306] + [Redis 容器:6379]
```
- **Nginx**:监听 80 端口,处理 HTTP 请求、URL 重写、静态资源缓存
- **PHP-FPM**:监听 9000 端口,执行 PHP 代码
- **MySQL**:数据库服务,数据持久化到 Docker 命名卷
- **Redis**:缓存服务,数据持久化到 Docker 命名卷
## 前置要求
| 依赖 | 版本要求 | 说明 |
|------|----------|------|
| Docker | >= 20.10 | 容器运行时 |
| Docker Compose | >= 2.0 | 容器编排工具 |
| 磁盘空间 | >= 5GB | 镜像 + 数据卷 |
## 文件结构
```
├── docker/
│ ├── Dockerfile # PHP-FPM 应用镜像定义
│ ├── nginx.conf # Nginx 站点配置
│ └── .env.docker # Docker 环境变量(密码等敏感信息)
├── docker-compose.yml # 容器编排配置(放在项目根目录)
├── .env # 应用配置(ThinkPHP 读取)
└── ...
```
## Dockerfile
```dockerfile
# =============================================================================
# Dockerfile — PHP-FPM 应用镜像
# =============================================================================
# 基础镜像:PHP 8.2 + FPM(FastCGI 进程管理器)
# 构建命令:docker-compose build app
# 运行方式:由 Nginx 容器通过 FastCGI 协议调用本容器的 9000 端口
# =============================================================================
FROM php:8.2-fpm
# -----------------------------------------------------------------------------
# 1. 安装系统依赖
# -----------------------------------------------------------------------------
# PHP 扩展编译需要的 C 库和工具,安装后清理 apt 缓存减小镜像体积
RUN apt-get update && apt-get install -y --no-install-recommends \
libpng-dev \ # GD 扩展 — PNG 支持
libjpeg-dev \ # GD 扩展 — JPEG 支持
libfreetype6-dev \ # GD 扩展 — 字体渲染(验证码依赖)
libzip-dev \ # zip 扩展依赖
zip \ # Composer 安装依赖包时可能用到
unzip \ # Composer 解压依赖包
&& rm -rf /var/lib/apt/lists/* # 清理 apt 缓存,减小镜像体积
# -----------------------------------------------------------------------------
# 2. 安装 PHP 扩展
# -----------------------------------------------------------------------------
# 项目必需扩展(根据 composer.json 和 config/ 推导):
# pdo_mysql — MySQL 数据库驱动(config/database.php 使用)
# mbstring — 多字节字符串处理(ThinkPHP 框架依赖)
# gd — 图片处理(验证码生成、图片缩放)
# bcmath — 高精度数学运算(phpspreadsheet 依赖)
# zip — ZIP 压缩(phpspreadsheet 读写 xlsx 依赖)
# redis — Redis 缓存驱动(config/cache.php 使用)
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
mbstring \
gd \
bcmath \
zip \
&& pecl install redis \
&& docker-php-ext-enable redis
# -----------------------------------------------------------------------------
# 3. 安装 Composer
# -----------------------------------------------------------------------------
# 从官方镜像复制 composer 二进制文件,避免重复安装
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# -----------------------------------------------------------------------------
# 4. 配置 PHP 生产环境参数
# -----------------------------------------------------------------------------
# 使用 php.ini-production 作为基础,追加项目所需配置
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# 生产环境追加配置:内存、超时、上传、时区、OPcache 等
RUN echo '\n\
; ====== 生产环境追加配置(Docker 自动生成) ====== \n\
\n\
; 关闭错误显示,防止敏感信息泄露到前端\ndisplay_errors = Off\n\
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED\n\
\n\
; 内存与超时\n\
memory_limit = 256M\n\
max_execution_time = 60\n\
max_input_time = 60\n\
\n\
; 文件上传(与 .env 中 FILE.MAX_SIZE 配合)\n\
upload_max_filesize = 50M\n\
post_max_size = 50M\n\
max_file_uploads = 20\n\
\n\
; 时区(与 .env 中 APP.DEFAULT_TIMEZONE 一致)\n\
date.timezone = Asia/Shanghai\n\
\n\
; OPcache 加速(生产环境必须开启)\n\
opcache.enable = 1\n\
opcache.memory_consumption = 256\n\
opcache.interned_strings_buffer = 16\n\
opcache.max_accelerated_files = 10000\n\
opcache.validate_timestamps = 0\n\
opcache.save_comments = 1\n\
' >> "$PHP_INI_DIR/php.ini"
# -----------------------------------------------------------------------------
# 5. 设置工作目录
# -----------------------------------------------------------------------------
WORKDIR /var/www/html
# -----------------------------------------------------------------------------
# 6. 复制项目文件并安装依赖
# -----------------------------------------------------------------------------
# 先复制 composer 文件,利用 Docker 层缓存 ——
# 只要 composer.json / composer.lock 没变就不重新安装依赖
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction
# 再复制全部项目文件(会覆盖上面的 composer 文件,但内容一致无影响)
COPY . .
# -----------------------------------------------------------------------------
# 7. 设置目录权限
# -----------------------------------------------------------------------------
# runtime — ThinkPHP 运行时缓存、日志(必须可写)
# uploads — 用户上传文件目录(必须可写)
RUN mkdir -p runtime uploads \
&& chown -R www-data:www-data runtime uploads \
&& chmod -R 775 runtime uploads
# -----------------------------------------------------------------------------
# 8. 暴露端口并启动
# -----------------------------------------------------------------------------
# 9000 是 PHP-FPM 的 FastCGI 监听端口,Nginx 通过此端口转发请求
EXPOSE 9000
CMD ["php-fpm"]
```
## Nginx 配置
```nginx
# =============================================================================
# Nginx 配置 — ThinkPHP 8 反向代理
# =============================================================================
# 用途:Docker 容器内 Nginx 服务,将 HTTP 请求转发给 PHP-FPM 处理
# 挂载方式:docker-compose 中 volumes 映射到 /etc/nginx/conf.d/default.conf
# =============================================================================
server {
# 监听容器内 80 端口(宿主机通过 docker-compose ports 映射到 8000)
listen 80;
server_name localhost;
# 网站根目录指向 ThinkPHP 入口目录
# 容器内代码挂载在 /var/www/html,入口文件在 public/index.php
root /var/www/html/public;
index index.php;
# -----------------------------------------------------------------
# URL 重写(ThinkPHP 必需)
# -----------------------------------------------------------------
# 将所有非真实文件请求转发到 index.php,由 ThinkPHP 路由解析
# 例:/api/user/page → /index.php?s=/api/user/page
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
}
}
# -----------------------------------------------------------------
# PHP-FPM 处理
# -----------------------------------------------------------------
# 所有 .php 请求通过 FastCGI 协议转发给 PHP-FPM 容器
# "app" 是 docker-compose 中 PHP-FPM 服务的名称,Docker 内部 DNS 自动解析
location ~ \.php$ {
fastcgi_pass app:9000; # 转发到 PHP-FPM 容器的 9000 端口
fastcgi_index index.php; # 默认索引文件
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; # 引入标准 FastCGI 参数
# 超时设置(秒),防止长请求被 Nginx 提前断开
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
}
# -----------------------------------------------------------------
# 安全规则
# -----------------------------------------------------------------
# 禁止访问隐藏文件(如 .env、.git、.htaccess)
location ~ /\. {
deny all;
}
# 禁止上传目录执行 PHP(防止恶意文件上传后被执行)
location ~ /uploads/.*\.php$ {
deny all;
}
# -----------------------------------------------------------------
# 静态资源缓存
# -----------------------------------------------------------------
# 常见静态文件类型设置 30 天浏览器缓存,减少重复请求
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# -----------------------------------------------------------------
# Gzip 压缩
# -----------------------------------------------------------------
# 对文本类响应启用压缩,减少传输体积
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_min_length 1024; # 小于 1KB 的响应不压缩(压缩收益低)
gzip_comp_level 5; # 压缩级别 1-9,5 为性能与压缩率的平衡点
}
```
## docker-compose.yml
:::tip 与实际文件的关系
项目根目录已内置 `docker-compose.yml`,支持两种模式:
- **快速体验**:`docker-compose up -d`(使用默认密码 root123 / redis123)
- **生产部署**:`docker-compose --env-file docker/.env.docker up -d --build`(使用生产密码)
下方为生产推荐配置参考,实际文件通过 `${VAR:-默认值}` 语法兼容两种场景。
:::
```yaml
# =============================================================================
# Docker Compose 生产部署配置
# =============================================================================
# 服务架构:Nginx → PHP-FPM → MySQL + Redis
# 启动命令:docker-compose --env-file docker/.env.docker up -d
# 停止命令:docker-compose down
# =============================================================================
version: '3.8'
services:
# ===========================================================================
# Nginx 反向代理服务
# ===========================================================================
# 职责:接收外部 HTTP 请求,转发 .php 到 PHP-FPM,直接返回静态资源
# 端口:容器内 80 → 宿主机 8000
# ===========================================================================
nginx:
image: nginx:1.25-alpine # 官方 Nginx 镜像(Alpine 版本,体积小)
container_name: rxthinkcmf-nginx # 容器名称,便于 docker logs / docker exec
ports:
- "8000:80" # 宿主机 8000 → 容器 80
volumes:
# 挂载 Nginx 站点配置(覆盖默认配置)
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro
# 挂载项目代码(与 PHP-FPM 容器共享同一份代码)
- ./:/var/www/html:ro # :ro 只读,Nginx 不需要写入代码
depends_on:
- app # 确保 PHP-FPM 先启动
networks:
- rxthinkcmf-net # 加入内部网络
restart: unless-stopped # 异常退出自动重启
# ===========================================================================
# PHP-FPM 应用服务
# ===========================================================================
# 职责:执行 ThinkPHP PHP 代码,处理业务逻辑
# 端口:9000(FastCGI 协议,仅 Nginx 内部访问)
# ===========================================================================
app:
build:
context: . # 构建上下文为项目根目录
dockerfile: docker/Dockerfile # Dockerfile 路径(相对于 context)
container_name: rxthinkcmf-app
volumes:
# 挂载项目代码(开发/更新时无需重建镜像)
- ./:/var/www/html
# 上传文件独立持久化卷(容器重建不丢失用户上传)
- uploads_data:/opt/data/uploads
environment:
- APP_DEBUG=${APP_DEBUG:-false} # 调试模式,默认关闭
depends_on:
- mysql # 确保数据库先启动
- redis # 确保缓存先启动
networks:
- rxthinkcmf-net
restart: unless-stopped
# ===========================================================================
# MySQL 数据库服务
# ===========================================================================
# 职责:存储业务数据(用户、菜单、字典、文章等)
# 端口:3306(可选暴露,用于外部工具连接调试)
# ===========================================================================
mysql:
image: mysql:8.0 # MySQL 8.0 官方镜像
container_name: rxthinkcmf-mysql
# ports: # 生产环境建议注释掉,不暴露到宿主机
# - "3306:3306"
environment:
# root 用户密码(必须 8 位以上,包含大小写字母和数字)
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
# 启动时自动创建的数据库
MYSQL_DATABASE: ${MYSQL_DATABASE:-rxthinkcmf.thinkphp8.elevue}
# 字符集(支持 emoji 等四字节字符)
MYSQL_CHARSET: utf8mb4
# 排序规则
MYSQL_COLLATION: utf8mb4_general_ci
volumes:
# 数据持久化(容器重建不丢数据)
- mysql_data:/var/lib/mysql
# 初始化 SQL(首次启动时自动执行,仅在数据卷为空时生效)
- ./document/mysql/rxthinkcmf.thinkphp8.elevue.sql:/docker-entrypoint-initdb.d/init.sql:ro
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --default-authentication-plugin=mysql_native_password
networks:
- rxthinkcmf-net
restart: unless-stopped
# ===========================================================================
# Redis 缓存服务
# ===========================================================================
# 职责:会话缓存、数据缓存(config/cache.php 配置的驱动)
# 端口:6379(可选暴露,用于外部工具连接调试)
# ===========================================================================
redis:
image: redis:7-alpine # Redis 7 Alpine 版本(体积小)
container_name: rxthinkcmf-redis
# ports: # 生产环境建议注释掉,不暴露到宿主机
# - "6379:6379"
command: redis-server --requirepass ${REDIS_PASSWORD} # 设置访问密码
volumes:
# 数据持久化(RDB 快照文件)
- redis_data:/data
networks:
- rxthinkcmf-net
restart: unless-stopped
# =============================================================================
# 命名卷(Named Volumes)
# =============================================================================
# Docker 管理的持久化存储,容器删除后数据保留
# 删除所有数据:docker-compose down -v(-v 参数同时删除命名卷)
# =============================================================================
volumes:
mysql_data: # MySQL 数据文件
redis_data: # Redis RDB 快照文件
uploads_data: # 用户上传文件
# =============================================================================
# 内部网络
# =============================================================================
# 所有服务通过此网络互通,容器间使用服务名(如 "mysql")作为主机名
# 外部无法直接访问此网络,必须通过 Nginx 的 ports 映射进入
# =============================================================================
networks:
rxthinkcmf-net:
driver: bridge
```
## 环境变量配置
创建 `docker/.env.docker` 文件:
```ini
# Docker 环境变量(密码等敏感信息,切勿提交 Git)
MYSQL_ROOT_PASSWORD=Your_Strong_Password_2024
MYSQL_DATABASE=rxthinkcmf.thinkphp8.elevue
REDIS_PASSWORD=Your_Redis_Password_2024
APP_DEBUG=false
```
:::warning 安全提示
- `docker/.env.docker` 包含生产密码,**必须加入 `.gitignore`**
- 密码至少 16 位,包含大小写字母和数字
- JWT 密钥在应用 `.env` 文件中配置,不在此文件中
:::
## 应用 .env 配置
容器启动前,确保项目根目录 `.env` 文件中以下配置正确:
```ini
APP_DEBUG = false
[APP]
SHOW_ERROR_MSG = false
[DATABASE]
; 连接地址(Docker 内部使用服务名 "mysql")
HOSTNAME = mysql
; 密码(与 .env.docker 中 MYSQL_ROOT_PASSWORD 一致)
PASSWORD = Your_Strong_Password_2024
[CACHE]
; 连接地址(Docker 内部使用服务名 "redis")
REDIS_HOST = redis
; 密码(与 .env.docker 中 REDIS_PASSWORD 一致)
REDIS_PASSWORD = Your_Redis_Password_2024
[FILE]
; 上传目录(容器内路径,与 docker-compose uploads_data 卷对应)
UPLOAD_DIR = /opt/data/uploads
```
## 启动部署
```bash
# 1. 配置环境变量
# 复制模板并修改密码
cp docker/.env.docker docker/.env.docker.local
vi docker/.env.docker.local # 修改密码
# 2. 配置应用 .env
cp .env.example .env
vi .env # 修改数据库、Redis 连接信息
# 3. 构建并启动所有服务
docker-compose --env-file docker/.env.docker.local up -d --build
# 4. 查看运行状态
docker-compose ps
# 5. 查看应用日志(确认无报错)
docker-compose logs -f app
```
## 常用命令
```bash
# --------------------------------------------------------------------------
# 生命周期管理
# --------------------------------------------------------------------------
# 启动所有服务(后台运行)
docker-compose up -d
# 停止所有服务(保留数据卷)
docker-compose down
# 停止并删除所有数据卷(⚠️ 清空数据库和上传文件)
docker-compose down -v
# 重建镜像并启动(Dockerfile 或 composer.json 变更后)
docker-compose up -d --build
# 重启单个服务
docker-compose restart app
# --------------------------------------------------------------------------
# 日志排查
# --------------------------------------------------------------------------
# 查看所有服务日志
docker-compose logs -f
# 查看单个服务日志
docker-compose logs -f app
docker-compose logs -f nginx
docker-compose logs -f mysql
# --------------------------------------------------------------------------
# 进入容器调试
# --------------------------------------------------------------------------
# 进入 PHP-FPM 容器
docker-compose exec app bash
# 进入 MySQL 容器
docker-compose exec mysql bash
# 在容器内执行 SQL
docker-compose exec mysql mysql -uroot -pYour_Strong_Password_2024 rxthinkcmf.thinkphp8.elevue
# --------------------------------------------------------------------------
# 数据库操作
# --------------------------------------------------------------------------
# 导入 SQL 文件
docker-compose exec -T mysql mysql -uroot -pYour_Strong_Password_2024 rxthinkcmf.thinkphp8.elevue < document/mysql/rxthinkcmf.thinkphp8.elevue.sql
# 导出数据库备份
docker-compose exec mysql mysqldump -uroot -pYour_Strong_Password_2024 rxthinkcmf.thinkphp8.elevue > backup_$(date +%Y%m%d).sql
# --------------------------------------------------------------------------
# ThinkPHP 命令
# --------------------------------------------------------------------------
# 数据库迁移
docker-compose exec app php think db:migrate
# 清除运行时缓存
docker-compose exec app php think clear
# 查看路由列表
docker-compose exec app php think route:list
```
## 生产环境建议
| 配置项 | 建议值 | 说明 |
|--------|--------|------|
| APP_DEBUG | false | 关闭调试模式,防止 SQL/路径泄露 |
| MYSQL_ROOT_PASSWORD | 强密码(>=16位) | 包含大小写字母和数字 |
| REDIS_PASSWORD | 强密码 | 与数据库密码不同 |
| JWT.SECRET | 随机字符串(>=32字节) | 在应用 .env 中配置 |
| FILE.UPLOAD_DIR | /opt/data/uploads | 使用命名卷持久化 |
| 数据卷 | 持久化挂载 | 避免容器重启丢失数据 |
| Nginx SSL | 443 + 证书 | 生产环境必须启用 HTTPS |
## SSL 配置(HTTPS)
生产环境建议在 Nginx 前增加 SSL 终止,修改 `nginx.conf`:
```nginx
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# ... 其余配置不变 ...
}
# HTTP 跳转 HTTPS
server {
listen 80;
server_name api.example.com;
return 301 https://$server_name$request_uri;
}
```
docker-compose.yml 中增加证书挂载:
```yaml
nginx:
volumes:
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./ssl/cert.pem:/etc/nginx/ssl/cert.pem:ro
- ./ssl/key.pem:/etc/nginx/ssl/key.pem:ro
```
## 相关文档
- [后端部署](/zh/deploy/backend.html) — Nginx/Apache 详细配置
- [前端部署](/zh/deploy/frontend.html) — Vue3 前端部署
- [数据库迁移](/zh/deploy/db-migrate.html) — 多数据库迁移工具
- [环境变量参考](/zh/appendix/config-reference.html) — 完整配置项说明