必须用多阶段构建分离构建与运行阶段,否则vendor/会混入dev依赖、测试文件、.git和未优化autoloader,导致镜像多出50–200mb;单阶段构建因残留非运行文件、未加--no-dev/--optimize-autoloader及选用胖基础镜像,易膨胀至400mb+。

为什么直接 composer install 会导致镜像层臃肿且不可复用
因为默认行为会把 vendor/ 目录连同所有依赖源码、测试文件、文档一并打包进镜像层,哪怕你只用其中几个类。更糟的是,每次 composer.json 微调(比如改个版本号),整个 vendor/ 层就失效,Docker 缓存全丢。
- Composer 默认下载完整包(含
tests/、docs/、.git/),而生产环境根本不需要 -
--no-dev必须加,否则开发依赖(如phpunit)也会打进镜像 - 不分离
composer.lock和composer.json的 COPY 时机,缓存命中率极低 - PHP 扩展未提前安装,导致
composer install过程中反复失败重试,拖慢构建
如何用多阶段构建 + 镜像分层控制 vendor 内容
核心是把依赖安装和最终镜像彻底拆开:第一阶段装全量依赖并精简,第二阶段只复制必要文件。中文镜像只是加速手段,不是分层关键。
- 第一阶段用
FROM php:8.2-cli,先COPY composer.json composer.lock ./,再RUN composer install --no-dev --optimize-autoloader --apcu-autoloader - 精简前加
RUN composer clear-cache,避免缓存污染影响后续构建 - 精简时用
RUN find vendor/ -name "tests" -type d -prune -exec rm -rf {} + 2>/dev/null || true清掉测试目录(有些包没tests/,所以加|| true) - 第二阶段用
FROM php:8.2-apache,只COPY --from=0 /app/vendor /var/www/html/vendor,不带任何构建工具链
中文镜像配置必须写在 Dockerfile 里,不能靠宿主机全局设置
宿主机的 ~/.composer/config.json 对容器内无效;如果只在 docker build 命令里传 --build-arg,又容易漏掉或覆盖。最稳的方式是显式声明。
- 在
RUN composer config -g repo.packagist composer https://packagist.phpcomposer.com之后,立刻跟一句&& composer config -g -a repos.packagist.org.type composer(新版 Packagist 镜像要求显式设 type) - 若用阿里云镜像,地址是
https://mirrors.aliyun.com/composer/,注意末尾斜杠不能少,否则composer install会报Invalid repository type - 不要用
composer config --global后再RUN composer install分两行——Docker 构建每行都是新 shell,global 配置不会继承
vendor 层缓存失效的三个隐蔽触发点
你以为改了 composer.json 才会失效?其实这些操作同样会让上层缓存作废,白搭优化。
-
composer.lock文件权限变化(比如 Git 某次提交改了chmod),Docker 会认为文件内容不同 - 在
COPY composer.json composer.lock ./之前执行了任何RUN指令(哪怕只是apt update),都会让 COPY 缓存失效 - 使用
ADD而非COPY加载 lock 文件,ADD 会自动解压 tar 包,导致 hash 计算方式不同
最稳妥的做法是:COPY 两文件必须是 RUN 指令前的第一步,且确保 Git 提交前统一执行 chmod 644 composer.lock。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











