# 2.8 Docker 快速体验 :::tip 概述 Docker 方案适合快速体验项目功能,无需在本机手动安装 PHP、MySQL、Redis 等环境。项目内置完整的 Nginx + PHP-FPM 架构配置,一条命令即可启动,脚本全文见下方(供参考,无需手动创建)。生产环境部署请参考 [11.6 Docker 生产部署](/zh/deploy/docker.html)。 ::: ## 架构说明 ```text 浏览器 → admin.laravel13.naivevue → [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_NaiveVue/ ├── 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_NaiveVue # 启动所有服务(首次会自动构建镜像,约 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.naivevue} - 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://admin.laravel13.naivevue} # 跨域来源(快速体验默认放开) - 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.naivevue} # 自动创建的数据库 volumes: - mysql_data:/var/lib/mysql # 数据持久化 - ./document/mysql/rxthinkcmf.laravel13.naivevue.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.naivevue.sql) MYSQL_ROOT_PASSWORD=Your_Strong_Password_2024 MYSQL_DATABASE=rxthinkcmf.laravel13.naivevue # Redis REDIS_PASSWORD=Your_Redis_Password_2024 # 应用 JWT_SECRET=<32 字符以上随机值,openssl rand -base64 32 生成> APP_DEBUG=false DOMAIN_URL=http://admin.laravel13.naivevue CORS_ALLOW_ORIGIN=http://admin.laravel13.naivevue ``` :::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://admin.laravel13.naivevue | Nginx → PHP-FPM → Laravel | | 健康检查 | http://admin.laravel13.naivevue/up | Laravel 内置健康路由 | | MySQL | localhost:3306 | 用户名 root,默认密码 root123 | | Redis | localhost:6379 | 默认密码 redis123 | 验证后端是否正常: ```bash # 健康检查 curl http://admin.laravel13.naivevue/up # 验证码(同时验证 PHP→Redis 链路,返回 code=0 即成功) curl http://admin.laravel13.naivevue/api/captcha # → {"code":0,"ok":true,"msg":"操作成功","data":{...}} # 登录获取 Token(默认管理员账号 admin / 123456,登录后立即修改) # 验证码参数 key/code 与 /api/captcha 响应字段一致 curl -X POST http://admin.laravel13.naivevue/api/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"123456","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.naivevue < document/mysql/rxthinkcmf.laravel13.naivevue.sql # 进入 MySQL 命令行 docker compose exec mysql mysql -uroot -pYour_Strong_Password_2024 rxthinkcmf.laravel13.naivevue # -------------------------------------------------------------------------- # 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` 全部配置项说明