ThinkPHP 项目如何使用 Docker 容器化部署并配置数据卷?
ThinkPHP 项目容器化部署时,将 public 目录单独挂载到/var/www/html 可避免 90% 以上的路由失效和静态资源 404 问题,同时需确保 runtime 目录对 www-data 用户有写权限,否则会出现 mkdir(): Permission denied 错误。
原因分析
ThinkPHP 默认依靠 public/index.php 作为入口文件启动,Nginx 或 Apache 的 DocumentRoot 必须指向 public 目录,否则会导致路由失效、静态资源 404、__ROOT__路径错乱。Docker 部署中常见错误是直接挂载整个项目根目录到/var/www/html,结果 Web 服务暴露了 app/、runtime/等敏感目录。根据 2026 年 4 月 12 日的技术记录,ThinkPHP 应用启动报 file_put_contents(/runtime/) 权限拒绝是最常见的容器启动失败原因,根本问题是容器用户和宿主机权限没对齐。另外,SELinux(如 CentOS 主机)会阻止容器进程写入挂载目录,报错类似 failed to open stream: Permission denied,但日志里不提示 SELinux。
Dockerfile 编写与基础镜像选择
推荐使用 php:8.2-fpm 或 php:7.4-apache 作为基础镜像。2026 年 1 月 4 日的实践表明,基于官方 PHP 镜像构建时需安装必要扩展:RUN docker-php-ext-install mysqli pdo pdo_mysql。ThinkPHP 6+ 默认依赖 pdo_mysql、mbstring、curl、json、xml,这些在官方 php:8.1-apache 镜像里不全预装,尤其是 pdo_mysql 得自己装扩展和对应 client lib。Dockerfile 示例:
FROM php:8.2-fpm WORKDIR /var/www/html RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd COPY --from=composer:latest /usr/bin/composer /usr/bin/composer COPY composer.json composer.lock ./ RUN composer install --no-dev --optimize-autoloader COPY . . RUN chown -R www-data:www-data /var/www/runtime /var/www/storage EXPOSE 9000 CMD ["php-fpm"]
注意:构建镜像时用 RUN mkdir -p /var/www/runtime && chown -R www-data:www-data /var/www/runtime,别等运行时再改。
数据卷配置与目录挂载策略
挂载时只映射 public 目录:用-v $(pwd)/public:/var/www/html,而非-v $(pwd):/var/www/html。runtime、config、extend 这些非公开目录,通过另一条-v 单独挂载,路径与容器内应用结构对齐(例如-v $(pwd)/runtime:/var/www/runtime)。2026 年 4 月 13 日的实践指出,多容器场景下 runtime 需隔离,避免缓存、日志、进程文件冲突。宿主机挂载 runtime 目录时,避免直接挂载整个项目目录,改用只读挂载 + 单独可写挂载:-v ./app:/var/www:ro -v ./runtime:/var/www/runtime。如果用 docker run 启动,加-u www-data 参数,确保 PHP 进程以正确用户身份运行。
Docker Compose 多服务编排
使用 docker-compose.yml 定义多个服务,典型配置包含 app(运行 PHP 业务代码)、nginx(处理 HTTP 请求并转发至 PHP-FPM)、mysql(存储应用数据)。2025 年 7 月 31 日的部署方案显示,web 服务基于自定义镜像并挂载代码目录,依赖 db 服务,通过 environment 传递 app_debug、db_host 等环境变量,db 服务使用 mysql:5.7 镜像并设置 root 密码和数据库名,映射 3306 端口。.env 文件不能硬编码进镜像,得运行时注入,本地开发的.env 含数据库密码、密钥等,打进镜像等于泄露凭证。Docker Compose 或 Kubernetes 中应通过 env_file 或 secrets 注入。
Nginx 配置与 PATH_INFO 传递
Nginx 配置里 try_files $uri $uri/ /index.php?$query_string 不生效是常见问题。ThinkPHP 的 URL 路由依赖正确的 PATH_INFO 传递,而默认 nginx 配置常把$fastcgi_script_name 当作脚本路径,导致$_SERVER['PATH_INFO']为空,Route::rule() 全部 fallback 到首页或 404。需在 nginx 配置中正确设置 fastcgi_param PATH_INFO $fastcgi_path_info; 确保 ThinkPHP 路由正常工作。
注意事项
第一,权限问题:容器里跑 ThinkPHP 最常卡在日志、缓存、模板编译全写不进 runtime 目录,检查 php-fpm.conf 里的 user 和 group 是否与容器内实际用户一致(常见坑:镜像用 www-data,但你自定义了用户却没同步改 fpm 配置)。第二,缓存清理:容器重启时,若宿主机挂载的 runtime 目录残留旧缓存(如 cache/下的 opcode 或模板编译文件),可能导致路由解析异常、配置未更新、甚至 Class not found。第三,数据库连接:把数据库迁移写在 ENTRYPOINT 里,结果 MySQL 容器还没起来,PHP 容器先报 SQLSTATE[HY000] [2002] Connection refused 然后退出,需用 wait-for-it.sh 或 dockerize 工具做依赖等待。第四,服务器配置:2026 年 3 月 23 日的部署记录指出,服务器配置必须高于 2 核 2G,不然 docker build 时会因为性能问题不成功一直卡着,阿里云 8 核 16G 按量付费一个小时才 1 块钱可用于测试。第五,开发环境优化:禁用 opcache.revalidate_freq=0 在开发阶段,不然改了配置不生效,误以为容器没重启。
参考来源
来源:技术社区 - ThinkPHP 项目结构如何适应容器化部署_Docker 目录挂载实践(2026 年 4 月 13 日)
来源:技术社区 - ThinkPHP 在 Docker 中如何快速部署_容器化环境搭建与镜像构建(2026 年 4 月 12 日)
来源:技术社区 - 如何实现 ThinkPHP 应用的 Docker 容器化_Dockerfile 编写与 PHP 扩展安装(2026 年 3 月 28 日)
来源:技术社区 - 使用 Docker 部署 Thinkphp8 环境(2026 年 3 月 23 日)
原文链接:https://www.zjcp.cc/ask/9602.html
