Files
rxthinkcmf-wiki/RXThinkCMF_Laravel13_NaiveVue/zh/quickstart/docker.md
T
2026-10-08 17:50:29 +08:00

623 lines
24 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.
# 2.8 Docker 快速体验
:::tip 概述
Docker 方案适合快速体验项目功能,无需在本机手动安装 PHP、MySQL、Redis 等环境。项目内置完整的 Nginx + PHP-FPM 架构配置,一条命令即可启动,脚本全文见下方(供参考,无需手动创建)。生产环境部署请参考 [11.6 Docker 生产部署](/zh/deploy/docker.html)。
:::
## 架构说明
```text
浏览器 → localhost:8000 → [Nginx 容器:80] → [PHP-FPM 容器:9000] → Laravel 应用
↕
[MySQL 容器:3306] + [Redis 容器:6379]
```
- **Nginx**:监听 80 端口(宿主机映射 8000),处理 HTTP 请求、URL 重写、静态资源缓存
- **PHP-FPM**:监听 9000 端口,执行 PHP 代码(镜像内置 PHP 8.3 + 扩展 + Composer 依赖)
- **MySQL**:数据库服务,数据持久化到 Docker 命名卷,**首次启动自动导入**数据库脚本
- **Redis**:缓存 / 会话 / 队列服务(JWT 会话、字典缓存均依赖),数据持久化到命名卷
## 文件结构
```text
RXThinkCMF_Laravel13_EleVue/
├── docker-compose.yml # 容器编排(项目根目录)
├── .dockerignore # 构建上下文排除(.env、vendor、SQL 等)
├── docker/
│ ├── Dockerfile # PHP-FPM 镜像定义
│ ├── nginx.conf # Nginx 站点配置
│ └── .env.docker # 环境变量(密码等)
├── .env # 应用配置(Laravel 读取)
└── ...
```
## 前置要求
| 依赖 | 版本要求 | 说明 |
|------|----------|------|
| Docker Desktop | >= 20.10(含 Compose v2) | 已安装并**启动**,`docker compose version` 可验证 |
| 项目已初始化 | 根目录存在 `.env` 且 `APP_KEY` 已生成 | 未初始化见下方命令 |
| JWT_SECRET | `.env` 中 >= 32 字符 | 应用启动 fail-close 校验,不满足拒绝启动 |
尚未初始化时,先在宿主机执行(依赖 [2.1 开发环境准备](/zh/quickstart/environment.html) 中的 PHP 8.3 + Composer):
```bash
composer setup
# 等价于:composer install → 复制 .env → key:generate → migrate --force → npm install → npm run build
```
## 快速启动
项目已内置完整的 Docker 配置文件(`docker-compose.yml`、`docker/Dockerfile`、`docker/nginx.conf`),无需手动创建,直接启动即可:
```bash
cd RXThinkCMF_Laravel13_EleVue
# 启动所有服务(首次会自动构建镜像,约 2-5 分钟)
docker compose up -d
# 查看运行状态(首次 mysql 需导入约 226MB SQL,初始化 1~3 分钟,
# 等到 mysql 变为 healthy,app 依赖健康检查会自动等待)
docker compose ps
# 查看日志(确认无报错)
docker compose logs -f app
```
:::tip 说明
`docker-compose.yml` 使用 `${VAR:-默认值}` 语法,未配置 `docker/.env.docker` 时自动使用默认密码(root123 / redis123),适合快速体验。生产部署请参考 [11.6 Docker 生产部署](/zh/deploy/docker.html) 使用 `--env-file` 指定生产密码。
:::
### 端口冲突处理(本机有 Laragon 时)
本机 Laragon 已占用 3306(MySQL)/ 6379(Redis)时,修改 `docker/.env.docker` 中的宿主机端口即可:
```ini
NGINX_PORT=8000 # Web 端口(被占用时改为 8080 等)
MYSQL_PORT=3307 # 与 Laragon MySQL 冲突时改为 3307
REDIS_PORT=6380 # 与 Laragon Redis 冲突时改为 6380
```
容器之间通过**服务名**(`mysql` / `redis`)互相通信,改宿主机端口不影响容器内部连接。
## docker-compose.yml
项目根目录的 `docker-compose.yml` 内容如下(供参考,无需手动创建):
```yaml
# =============================================================================
# Docker Compose — RXThinkCMF Laravel13 容器编排
# =============================================================================
# 架构:Nginx(80) → PHP-FPM(9000) → MySQL(3306) + Redis(6379)
#
# 快速启动(使用默认密码):
# docker compose up -d
#
# 生产部署(使用 .env.docker 中的密码):
# docker compose --env-file docker/.env.docker up -d --build
# =============================================================================
services:
# ===========================================================================
# Nginx 反向代理
# ===========================================================================
nginx:
image: nginx:1.25-alpine
container_name: rxthinkcmf-laravel13-nginx
ports:
- "${NGINX_PORT:-8000}:80" # 宿主机端口(默认 8000),可通过环境变量覆盖
volumes:
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro # 站点配置(只读)
- ./:/var/www/html:ro # 项目代码(只读)
depends_on:
- app
networks:
- rxthinkcmf-laravel13-net
restart: unless-stopped
# ===========================================================================
# PHP-FPM 应用服务
# ===========================================================================
# 执行 Laravel 代码,处理 API 请求和业务逻辑
# ===========================================================================
app:
build:
context: . # 构建上下文为项目根目录
dockerfile: docker/Dockerfile # Dockerfile 路径
container_name: rxthinkcmf-laravel13-app
volumes:
- ./:/var/www/html # 项目代码(可写,上传文件随宿主机持久化)
environment:
- APP_DEBUG=${APP_DEBUG:-true} # 调试模式(快速体验默认开启)
# 数据库:容器内通过服务名 mysql 访问(覆盖 .env 中的 127.0.0.1)
- DB_CONNECTION=mysql
- DB_HOST=mysql
- DB_PORT=3306
- DB_DATABASE=${MYSQL_DATABASE:-rxthinkcmf.laravel13.elevue}
- DB_USERNAME=root
- DB_PASSWORD=${MYSQL_ROOT_PASSWORD:-root123}
# 缓存 / 会话 / 队列:统一走 Redis(数据库脚本不含 framework 表)
- CACHE_STORE=redis
- SESSION_DRIVER=redis
- QUEUE_CONNECTION=redis
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD:-redis123}
# JWT 签名密钥(应用启动要求 >= 32 字符)
- JWT_SECRET=${JWT_SECRET:-your_random_jwt_secret_key_at_least_32_bytes_long}
# 文件访问域名(接口返回上传文件的完整地址)
- FILE_DOMAIN_URL=${DOMAIN_URL:-http://localhost:8000}
# 跨域来源(快速体验默认放开)
- CORS_ALLOW_ORIGIN=${CORS_ALLOW_ORIGIN:-*}
depends_on:
mysql:
condition: service_healthy # 等待 MySQL 就绪(含首次 SQL 导入)
redis:
condition: service_started # 等待 Redis 启动
networks:
- rxthinkcmf-laravel13-net
restart: unless-stopped
# ===========================================================================
# MySQL 数据库
# ===========================================================================
# 存储业务数据,首次启动自动导入数据库脚本
# ===========================================================================
mysql:
image: mysql:8.0
container_name: rxthinkcmf-laravel13-mysql
ports:
- "${MYSQL_PORT:-3306}:3306" # 宿主机端口(默认 3306),可通过环境变量覆盖
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123} # root 密码
MYSQL_DATABASE: ${MYSQL_DATABASE:-rxthinkcmf.laravel13.elevue} # 自动创建的数据库
volumes:
- mysql_data:/var/lib/mysql # 数据持久化
- ./document/mysql/rxthinkcmf.laravel13.elevue.sql:/docker-entrypoint-initdb.d/init.sql:ro # 初始化 SQL(仅首次启动执行)
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --default-authentication-plugin=mysql_native_password
healthcheck: # 健康检查:确保 MySQL 可接受连接
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-root123}"]
interval: 10s
timeout: 5s
retries: 30
start_period: 60s # 首次启动需导入约 226MB SQL,给足缓冲时间
networks:
- rxthinkcmf-laravel13-net
restart: unless-stopped
# ===========================================================================
# Redis 缓存
# ===========================================================================
# 提供缓存加速(JWT 会话/字典/权限缓存),与 config/database.php 中 redis 配合
# ===========================================================================
redis:
image: redis:7-alpine
container_name: rxthinkcmf-laravel13-redis
ports:
- "${REDIS_PORT:-6379}:6379" # 宿主机端口(默认 6379),可通过环境变量覆盖
command: redis-server --requirepass ${REDIS_PASSWORD:-redis123} # 访问密码
volumes:
- redis_data:/data # 数据持久化
networks:
- rxthinkcmf-laravel13-net
restart: unless-stopped
# =============================================================================
# 命名卷 — 持久化存储
# =============================================================================
# 容器删除后数据保留,彻底重置请执行:docker compose down -v
# =============================================================================
volumes:
mysql_data: # MySQL 数据文件
redis_data: # Redis RDB 快照
# =============================================================================
# 内部网络
# =============================================================================
# 容器间通过服务名(mysql / redis / app)互相访问
# =============================================================================
networks:
rxthinkcmf-laravel13-net:
driver: bridge
```
## Dockerfile
将以下内容保存为 `docker/Dockerfile`:
```dockerfile
# =============================================================================
# Dockerfile — PHP-FPM 应用镜像(RXThinkCMF Laravel13)
# =============================================================================
# 基础镜像:PHP 8.3 + FPM(FastCGI 进程管理器)
# 构建命令:docker compose build app
# 运行方式:由 Nginx 容器通过 FastCGI 协议调用本容器的 9000 端口
# =============================================================================
FROM php:8.3-fpm
# -----------------------------------------------------------------------------
# 1. 安装系统依赖
# -----------------------------------------------------------------------------
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 — 多字节字符串处理(Laravel 框架依赖)
# gd — 图片处理(验证码生成、图片缩放)
# bcmath — 高精度数学运算(phpspreadsheet 依赖)
# zip — ZIP 压缩(phpspreadsheet 读写 xlsx 依赖)
# redis — Redis 扩展(phpredis:缓存/会话/队列/JWT 会话均依赖)
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
# -----------------------------------------------------------------------------
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# -----------------------------------------------------------------------------
# 4. 配置 PHP 生产环境参数
# -----------------------------------------------------------------------------
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN echo '\n\
; ====== 生产环境追加配置(Docker 自动生成) ====== \n\
\n\
display_errors = Off\n\
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED\n\
memory_limit = 256M\n\
max_execution_time = 60\n\
max_input_time = 60\n\
upload_max_filesize = 50M\n\
post_max_size = 50M\n\
max_file_uploads = 20\n\
date.timezone = Asia/Shanghai\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 = 1\n\
opcache.revalidate_freq = 0\n\
opcache.save_comments = 1\n\
' >> "$PHP_INI_DIR/php.ini"
# -----------------------------------------------------------------------------
# 5. 设置工作目录
# -----------------------------------------------------------------------------
WORKDIR /var/www/html
# -----------------------------------------------------------------------------
# 6. 复制项目文件并安装依赖(利用 Docker 层缓存)
# -----------------------------------------------------------------------------
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction
COPY . .
# -----------------------------------------------------------------------------
# 7. 设置 Laravel 可写目录权限
# -----------------------------------------------------------------------------
# storage — 日志、缓存、会话、编译视图(必须可写)
# bootstrap/cache — 配置/路由/事件缓存(必须可写)
# public/uploads — 用户上传文件目录(必须可写)
RUN mkdir -p \
storage/framework/cache \
storage/framework/sessions \
storage/framework/views \
storage/logs \
bootstrap/cache \
public/uploads \
&& chown -R www-data:www-data storage bootstrap/cache public/uploads \
&& chmod -R 775 storage bootstrap/cache public/uploads
# -----------------------------------------------------------------------------
# 8. 暴露端口并启动
# -----------------------------------------------------------------------------
EXPOSE 9000
CMD ["php-fpm"]
```
## Nginx 配置
将以下内容保存为 `docker/nginx.conf`:
```nginx
# =============================================================================
# Nginx 配置 — RXThinkCMF Laravel13 反向代理
# =============================================================================
server {
# 监听容器内 80 端口(宿主机通过 docker-compose ports 映射到 8000)
listen 80;
server_name localhost;
# 网站根目录指向 Laravel 公开目录(容器内代码挂载在 /var/www/html)
root /var/www/html/public;
index index.php;
# -----------------------------------------------------------------
# URL 重写(Laravel 路由)
# -----------------------------------------------------------------
# 真实文件直接返回,其余交给 public/index.php 由 Laravel 路由解析
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# -----------------------------------------------------------------
# PHP-FPM 处理(仅入口 index.php 可执行)
# -----------------------------------------------------------------
# "app" 是 docker-compose 中 PHP-FPM 服务的名称,Docker 内部 DNS 自动解析
location = /index.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 参数
fastcgi_read_timeout 300; # 超时设置(秒),防止长请求被提前断开
fastcgi_send_timeout 300;
}
# 其余 .php 文件(含上传目录)一律 404,防止恶意脚本被执行
location ~ \.php$ {
return 404;
}
# -----------------------------------------------------------------
# 安全规则:禁止访问隐藏文件(如 .env、.git、.htaccess)
# -----------------------------------------------------------------
location ~ /\. {
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;
gzip_comp_level 5;
}
```
## 环境变量配置
将以下内容保存为 `docker/.env.docker`:
```ini
# Docker 环境变量(密码等敏感信息,切勿提交 Git)
# 端口(宿主机端口,冲突时修改)
NGINX_PORT=8000
MYSQL_PORT=3306
REDIS_PORT=6379
# MySQL(首次启动自动导入 document/mysql/rxthinkcmf.laravel13.elevue.sql)
MYSQL_ROOT_PASSWORD=Your_Strong_Password_2024
MYSQL_DATABASE=rxthinkcmf.laravel13.elevue
# Redis
REDIS_PASSWORD=Your_Redis_Password_2024
# 应用
JWT_SECRET=<32 字符以上随机值,openssl rand -base64 32 生成>
APP_DEBUG=false
DOMAIN_URL=http://localhost:8000
CORS_ALLOW_ORIGIN=http://localhost:8000
```
:::tip 与本地 .env 的关系
`docker-compose.yml` 的 `environment` 块会把数据库 / Redis / JWT 等配置**以容器环境变量注入,优先级高于 `.env` 文件**——因此容器内自动使用服务名 `mysql` / `redis`,**无需修改本地 `.env`**(与手动部署用同一份 `.env` 互不干扰)。
:::
## 配置优先级
变量插值优先级(高 → 低):
```text
1. shell 环境变量
2. --env-file 指定的文件(如 docker/.env.docker)
3. 项目根目录 .env(compose 自动读取)
4. docker-compose.yml 中的 ${VAR:-默认值}
```
## 访问服务
启动成功后:
| 服务 | 地址 | 说明 |
|------|------|------|
| 后端 API | http://localhost:8000 | Nginx → PHP-FPM → Laravel |
| 健康检查 | http://localhost:8000/up | Laravel 内置健康路由 |
| MySQL | localhost:3306 | 用户名 root,默认密码 root123 |
| Redis | localhost:6379 | 默认密码 redis123 |
验证后端是否正常:
```bash
# 健康检查
curl http://localhost:8000/up
# 验证码(同时验证 PHP→Redis 链路,返回 code=0 即成功)
curl http://localhost:8000/api/captcha
# → {"code":0,"ok":true,"msg":"操作成功","data":{...}}
# 登录获取 Token(默认管理员账号 admin / 123456,登录后立即修改)
# 验证码参数 key/code 与 /api/captcha 响应字段一致
curl -X POST http://localhost:8000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"123456","key":"<captcha_key>","code":"<验证码字符>"}'
```
## 数据持久化
| 数据 | 位置 | `down` 后 | `down -v` 后 |
|------|------|-----------|--------------|
| MySQL 数据 | 命名卷 `mysql_data` | 保留 | **删除** |
| Redis 数据 | 命名卷 `redis_data` | 保留 | **删除** |
| 上传文件 | 宿主机项目目录(挂载) | 保留 | 保留 |
| 代码 | 宿主机项目目录(挂载) | 保留 | 保留 |
## 常用命令
```bash
# --------------------------------------------------------------------------
# 服务管理
# --------------------------------------------------------------------------
# 启动服务
docker compose up -d
# 停止服务(保留数据)
docker compose down
# 停止并清空所有数据(重新开始)
docker compose down -v
# 重建镜像(Dockerfile 或 composer.json 变更后)
docker compose up -d --build
# --------------------------------------------------------------------------
# 日志排查
# --------------------------------------------------------------------------
# 查看所有日志
docker compose logs -f
# 查看应用日志 / 数据库日志(首次看导入进度)
docker compose logs -f app
docker compose logs -f mysql
# --------------------------------------------------------------------------
# 进入容器
# --------------------------------------------------------------------------
# 进入 PHP-FPM 容器
docker compose exec app bash
# 进入 MySQL 容器
docker compose exec mysql bash
# --------------------------------------------------------------------------
# 数据库操作
# --------------------------------------------------------------------------
# 导入 SQL(手动方式,首次启动已自动导入)
docker compose exec -T mysql mysql -uroot -pYour_Strong_Password_2024 rxthinkcmf.laravel13.elevue < document/mysql/rxthinkcmf.laravel13.elevue.sql
# 进入 MySQL 命令行
docker compose exec mysql mysql -uroot -pYour_Strong_Password_2024 rxthinkcmf.laravel13.elevue
# --------------------------------------------------------------------------
# Laravel Artisan 命令
# --------------------------------------------------------------------------
# 清除配置缓存
docker compose exec app php artisan config:clear
# 容器内执行 tinker 验证 Redis 连通
docker compose exec app php artisan tinker
# 查看路由列表
docker compose exec app php artisan route:list
```
## 常见问题
### 端口被占用
```bash
# Windows 查看占用端口的进程
netstat -ano | findstr :8000
# Linux/Mac
lsof -i :8000
# 解决方案:修改 docker/.env.docker 中的端口
# NGINX_PORT=8080 # 改为 8080
```
### 数据库连接失败
`docker-compose.yml` 的 `environment` 块会把 `DB_HOST` 覆盖为 `mysql`(Docker 服务名)。若手动改过 compose 导致覆盖失效,确认容器内环境变量 `DB_HOST=mysql`,不是 `127.0.0.1`:
```bash
docker compose exec app printenv DB_HOST
# → mysql
```
### 容器启动后立即退出
```bash
# 查看退出原因
docker compose logs app
# 常见原因:
# 1. JWT_SECRET 长度不足(< 32 字符)→ 应用 fail-close 拒绝启动,重新生成密钥
# 2. PHP 扩展缺失 → 检查 Dockerfile 中的 docker-php-ext-install
# 3. 目录权限问题 → 确认 storage 和 bootstrap/cache 目录可写
# 4. composer install 失败 → 检查网络或镜像源
```
### 首次启动 mysql 一直 unhealthy
首次启动需导入约 226MB 数据库脚本,初始化 1~3 分钟属正常。查看进度:
```bash
docker compose logs -f mysql
# 等待 "ready for connections" 出现后,mysql 变为 healthy,app 自动启动
```
### 验证码一直失败
Redis 未启动或密码不匹配:
```bash
docker compose ps # 确认 redis 容器状态
docker compose logs redis # 查看 Redis 日志
docker compose exec app php artisan tinker # 容器内验证连通
```
### 重新开始
```bash
# 删除所有容器、网络、数据卷,完全重来
docker compose down -v
docker compose up -d --build
```
## 相关文档
- [生产部署](/zh/deploy/docker.html) — 生产环境完整方案与安全加固
- [后端启动](/zh/quickstart/backend-start.html) — 不用 Docker,手动启动
- [数据库初始化](/zh/quickstart/database-init.html) — 手动导入 SQL
- [环境变量配置](/zh/quickstart/env-vars.html) — `.env` 全部配置项说明