Laravel 应用 Docker 容器化指南
把 Laravel 应用装进 Docker 的完整流程:编写 Dockerfile、构建镜像、Docker Compose 编排 PHP-FPM/Nginx/MySQL 服务。开发与生产两种语境的配置要点一次讲清。
本文依据官方文档整理,未执行运行验证或性能基准。代码片段展示局部用法,业务函数、数据和环境需按项目补齐;版本与配置以所引文档为准。
直接回答:Laravel 容器化的标准形态是 Docker Compose 三件套——PHP-FPM 容器跑应用、Nginx 容器做 Web 入口、MySQL 容器存数据,开发环境可共享源码挂载,生产镜像应包含锁定的代码与 vendor。Dockerfile 基于 php:fpm 装扩展、Composer 装依赖;生产版要关闭 Xdebug、开启 OPcache、用多阶段构建瘦身。
整体架构
浏览器 → Nginx 容器 :80 → PHP-FPM 容器 :9000 → MySQL 容器 :3306
以下 Compose 是本地开发示意,不是可直接上线的完整清单。生产应把应用代码和 vendor 构建进镜像,Nginx 只需公开资源及与 FPM 一致的脚本路径。
Dockerfile 要点
FROM php:8.3-fpm
RUN apt-get update && apt-get install -y libpng-dev libzip-dev \
&& docker-php-ext-install pdo_mysql gd zip opcache
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
COPY . .
RUN composer install --no-dev --optimize-autoloader
构建上下文须用 .dockerignore 排除 .env、.git 和本机 vendor;补齐 composer.lock 对 PHP 与扩展的要求,并给 storage/bootstrap/cache 最小写权限。关键点:扩展用官方 docker-php-ext-install 装;Composer 用多阶段复制而非镜像内安装;生产构建 --no-dev。
Compose 编排
services:
app:
build: .
volumes: [".:/var/www"]
web:
image: nginx:alpine
ports: ["80:80"]
volumes: [".:/var/www", "./nginx.conf:/etc/nginx/conf.d/default.conf"]
db:
image: mysql:8
environment: { MYSQL_DATABASE: blog, MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?set a development root password}" }
还需编写 nginx.conf:root 指向 /var/www/public,PHP 请求通过 fastcgi_pass app:9000 交给 FPM,并正确设置 SCRIPT_FILENAME。示例未包含完整 Nginx 配置、应用数据库用户、健康检查和数据库持久卷,必须补全后运行;勿将 FPM 9000 端口暴露公网。
首次请求失败时,先分别查看 Nginx 和 PHP-FPM 日志:前者确认转发结果,后者查脚本路径或权限错误。使用观测云集中采集时,按 DataKit 日志采集指南为两类日志设置不同来源和一致的服务标签,保留同一请求的时间与标识。
生产语境的差异
- 关闭 Xdebug、开 OPcache(
opcache.validate_timestamps=0) .env不进镜像,运行时注入- 配置注入完成后执行
php artisan config:cache;迁移由受控的单独部署任务执行,先备份、审核破坏性变更,避免每个副本启动时竞相迁移 - 多阶段构建:依赖层与代码层分离,最终镜像只留运行时
常见问题(FAQ)
Q:开发环境也用这套吗?
A:用同一套 Compose 文件,但开 Xdebug、挂源码、开 OPcache 时间戳校验(opcache.validate_timestamps=1)——用 compose override 文件区分两套配置。
Q:队列与计划任务怎么容器化?
A:各起独立容器:php artisan queue:work 与 php artisan schedule:work(或 cron 每分钟调 schedule:run),复用同一镜像不同启动命令。
Q:镜像里的 vendor 和挂载的源码冲突怎么办?
A:volume 会覆盖容器内代码目录。做法:开发环境在挂载目录预装与 lock 文件一致的 vendor,或用显式初始化的命名卷。生产不挂载覆盖代码,也不在每次启动时联网装依赖。
官方参考
资料核对日期:2026-09-29。