ThinkPHP 项目如何用 Docker 容器化部署?

文章导读
ThinkPHP 容器化部署的核心是将 Web 根目录限定为 public 目录,并在 Docker 构建阶段完成 Composer 依赖安装,同时单独挂载 runtime 目录解决权限问题。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 常见问题
  7. G 参考来源
A A

ThinkPHP 容器化部署的核心是将 Web 根目录限定为 public 目录,并在 Docker 构建阶段完成 Composer 依赖安装,同时单独挂载 runtime 目录解决权限问题。

先说结论:ThinkPHP 容器化成功的关键在于构建阶段预装依赖、运行时权限对齐以及 Web 服务器正确配置伪静态。

  • 适合 ThinkPHP 6/8 及需要环境一致性的生产部署场景
  • 先准备 Dockerfile 分层构建策略与 Nginx 伪静态配置
  • 验收时检查 runtime 写入权限与路由跳转是否正常

命令速用版

以下是 Dockerfile 关键片段与 Nginx 配置核心指令,可直接用于构建与配置。

Dockerfile 关键指令:
RUN mkdir -p /var/www/runtime && chmod -R 777 /var/www/runtime
RUN composer install `--no-dev` `--optimize-autoloader`

Nginx location 配置:
location / {
  try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
  fastcgi_split_path_info ^(.+\.php)(/.+)$;
  fastcgi_param PATH_INFO $fastcgi_path_info;
}

为什么会这样

容器启动失败通常是因为自动加载文件缺失或目录权限不匹配,而非框架代码错误。

ThinkPHP 依赖 vendor/autoload.php 进行类加载,若 Docker 构建时未执行 composer install,容器内 vendor 目录为空,导致 Class 'think\App' not found 错误。runtime 目录用于存放缓存与日志,若宿主机挂载目录的 UID 与容器内 www-data 用户不一致,PHP 进程无法写入文件,引发 Permission denied 错误。Nginx 默认不传递 PATH_INFO,若未配置 fastcgi_split_path_info,ThinkPHP 路由无法解析伪静态 URL。

分步处理

按以下步骤完成镜像构建与容器编排,确保依赖、权限与路由配置正确。

1. 编写 Dockerfile 分层构建

先复制 composer 配置文件安装依赖,再复制代码,避免代码变更触发依赖重装。在构建阶段创建 runtime 目录并赋予权限,不要依赖容器启动时的 chown 命令。

COPY composer.json composer.lock ./
RUN composer install `--no-dev` `--optimize-autoloader`
COPY . .
RUN mkdir -p /var/www/runtime && chmod -R 777 /var/www/runtime

2. 配置 Docker Compose 挂载

将 public 目录挂载为 Web 根目录,runtime 目录单独挂载为可写,.env 文件挂载至项目根目录而非 public 子目录。

volumes:
  - ./public:/var/www/html:ro
  - ./runtime:/var/www/runtime:rw
  - ./.env:/var/www/.env

3. 配置 Nginx 伪静态

root 指向 public 目录,location 块中补充 PATH_INFO 参数,确保 ThinkPHP 路由能获取完整路径信息。

ThinkPHP 项目如何用 Docker 容器化部署?
root /var/www/html/public;
location ~ \.php$ {
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

怎么验证是否生效

通过容器内文件检查与页面访问测试,确认依赖加载与权限配置无误。

1. 检查依赖文件

进入容器执行 ls -l vendor/autoload.php,确认文件存在且非空。若文件缺失,说明构建阶段未成功执行 composer install。

2. 验证环境变量

在容器内运行 php think env:show 或 php -r "var_dump(\think\Env::get('app.debug'));",确认.env 文件已被正确加载。

3. 测试路由与写入

访问非首页路由如 /index.php/user/login,确认不报 404。查看 runtime/log 目录是否有新日志文件生成,确认权限写入正常。

常见坑

以下场景容易导致部署失败,操作时需特别注意权限隔离与配置细节。

  • UID 不一致:宿主机与容器内 www-data 用户 ID 不同会导致挂载目录不可写,建议在 Dockerfile 中显式 chmod 777 而非 chown。
  • Web 根目录错误:Nginx root 必须指向 public 目录,若指向项目根目录会导致 app 等敏感目录暴露。
  • PATH_INFO 丢失:Nginx 未配置 fastcgi_split_path_info 会导致 ThinkPHP 路由失效,所有请求 fallback 到首页。
  • 多实例缓存冲突:多个容器共用同一 runtime 目录会导致缓存错乱,每个实例应独立挂载 runtime 目录。

常见问题

Class 'think\App' not found 怎么解决?

原因是 Composer 自动加载文件未生成,需在 Dockerfile 构建阶段执行 composer install `--no-dev` `--optimize-autoloader`。

Nginx 配置后路由依然 404 怎么办?

检查 location 块是否缺少 fastcgi_param PATH_INFO $fastcgi_path_info;,且 root 是否指向了 public 目录。

runtime 目录报错 Permission denied 如何处理?

避免在容器启动时 chown,应在 Dockerfile 中创建目录并 chmod 777,或确保挂载时宿主机目录权限与容器用户一致。

参考来源

  • 一键部署上线:thinkphp 使用 Docker 容器化【DevOps】
  • Docker 容器化搭建 ThinkPHP 运行环境:一键部署与迁移指南【教程】
  • ThinkPHP 怎么上 Docker_ThinkPHP 容器化部署解答【汇总】
  • ThinkPHP 项目结构如何适应容器化部署_Docker 目录挂载实践
  • ThinkPHP 如何使用 Docker 部署
  • ThinkPHP 在 Docker 中如何快速部署_容器化环境搭建与镜像构建
  • ThinkPHP 项目在 Docker 容器中的部署优化_高性能容器化环境配置
  • ThinkPHP 的 Docker 部署怎么做?ThinkPHP 如何容器化运行?
  • ThinkPHP 伪静态怎么配 Docker_ThinkPHP 多语言容器化部署说明【教程】
  • 使用 Docker 部署 Thinkphp8 环境