答案是必须在Dockerfile的RUN指令中执行composer install,不能放在CMD或ENTRYPOINT中;否则每次启动都重装依赖、破坏缓存、引发网络失败与环境不一致问题,且违反“一次构建、多次运行”原则。

composer install 必须放在 RUN,不能塞进 CMD 或 ENTRYPOINT
容器启动时执行 composer install 是最常见也最危险的错误。它会让每次 docker run 都重拉包、重解析依赖、重生成 autoload —— 网络一抖就失败,生产环境禁外网直接退出,且根本无法利用 Docker 层缓存。
- 现象:容器反复报
Could not fetch packages、Class not found、甚至静默跳过 autoload 生成 - 本质原因:构建环境(你本地)和运行环境(容器)PHP 版本/扩展不一致,而
composer.lock是按构建环境生成的;启动时再装,等于用运行环境“强行 reinterpret”锁文件,必然出错 - 正确做法:在
Dockerfile的RUN指令中执行,确保 vendor 直接打进镜像层,且与运行时环境完全一致
多阶段构建里 builder 和 runner 镜像必须严格对齐
很多人用 php:8.2-cli 构建,却用 php:8.2-fpm-alpine 运行,结果 vendor 装上了,但某些包的 autoloader 生成异常,或 ext-zip 缺失导致类加载失败。
- builder 阶段必须用和最终运行镜像同源的 PHP 版本、SAPI 类型、关键扩展(比如 zip、mbstring、pdo)
- Alpine 镜像需提前
RUN apk add --no-cache ca-certificates git unzip,否则 SSL 或 git clone 失败 - final 阶段只
COPY --from=builder /app/vendor /app/vendor,别复制composer.phar或构建工具,也不该挂载宿主机vendor/作 volume
config.platform.php 锁定版本不是可选,是必填项
即使你用了 php:8.2-cli 镜像,如果 composer.json 里没写 "config": {"platform": {"php": "8.2.15"}},Composer 仍会根据当前环境推测平台能力,可能装入仅兼容 PHP 8.3 的语法(比如 readonly 属性),导致运行时报 ParseError。
- 检查
composer.lock顶部的platform字段是否明确声明了 PHP 和扩展版本 - 构建前运行
composer update --lock并提交更新后的 lock 文件,确保平台信息固化 - 验证命令:
composer show --platform输出应与目标环境完全一致
国内构建卡住?镜像源 + 缓存顺序才是关键
慢不是因为网络差,而是 Docker 缓存失效 + 默认直连 packagist.org 导致超时重试。官方镜像源已停用,必须换阿里云镜像。
- 在
RUN前加:RUN composer config -g repo.packagist https://mirrors.aliyun.com/composer/ - COPY 顺序必须是:先
COPY composer.lock .,再COPY composer.json .,最后RUN composer install;否则会退化成update,破坏可重现性 - 别在
RUN composer install前COPY . /app—— 改一行代码就触发整个 vendor 重建,构建时间从秒级变成分钟级


















