composer如何在air-gapped系统中同步多个项目的依赖?

1次阅读

离线可复现依赖的核心是:在有网机器上执行 composer update –with-all-dependencies 确保 composer.lock 含完整 dist 信息和校验和,并将 vendor/ 与 lock 文件一同打包交付,禁用缓存与自动回退,必要时用 –ignore-platform-reqs 跳过平台检查。

composer如何在air-gapped系统中同步多个项目的依赖?

composer install --no-install 生成离线可复现的锁文件

空气间隙(air-gapped)环境无法联网,所以关键不是“怎么装”,而是“怎么让每个项目在无网时也能还原完全一致的依赖”。核心动作是:所有依赖解析和版本锁定必须在有网机器上做完,且确保 composer.lock 包含完整包元数据(包括 dist 信息和校验和)。

常见错误是只拷贝 composer.json 过去,结果离线运行 composer install 直接报错 Could not find package ... —— 因为没锁版本,也没提前下载包。

  • 有网机器上,对每个项目执行 composer update --with-all-dependencies(强制刷新全树),再确认 composer.lock 中每个 dist 条目都有 urlshasum
  • 禁用 packagist 自动回退:在 composer.json"repositories": [{"type": "composer", "url": "https://packagist.org"}],再删掉 ~/.composer/cache 避免本地缓存干扰判断
  • 不要用 --no-scripts--no-plugins 生成锁文件,否则某些插件依赖(如 hirak/prestissimo)可能被跳过,导致离线行为不一致

把 vendor 和 lock 文件一起打包进离线介质

仅靠 composer.lock 不够。Composer 离线安装时仍会尝试访问网络获取包 zip/tar,除非你提供完整 vendor/ 或预下载的包存档。最稳妥的做法是:把整个 vendor/ 目录 + composer.lock 打包,直接复制过去。

有人想省空间只传 .zip 包,但容易踩坑:Composer 默认不读取任意路径的 zip,除非配置 artifact 仓库 —— 而这个配置本身要写进 composer.json,且只对 require 的顶层包生效,对递归依赖无效。

  • 打包前运行 composer install --no-dev --optimize-autoloader,减少体积并排除 dev-only 包
  • 确认 vendor/autoload.php 可正常 require,避免因路径或权限问题导致 autoload 失败
  • 如果项目多、vendor 共享率高,可用 rsync -a --delete 增量同步,比每次全量压缩更快

composer install --ignore-platform-reqs 绕过 PHP 扩展缺失报错

离线系统常存在 PHP 版本或扩展与开发机不一致,比如开发机有 ext-redis,而目标机没有,composer install 就会卡在平台需求检查阶段,报错 Your requirements could not be resolved to an installable set of packages.

这不是依赖冲突,而是 Composer 在做预检。此时不能改 composer.json,因为会破坏锁文件语义;也不能硬删 platform 配置,因为有些扩展是运行时必需的。

  • --ignore-platform-reqs 让安装跳过检查,但需确保运行时环境实际满足要求(比如代码真用了 Redis::connect(),没扩展就会 fatal Error
  • 更安全的做法是:在有网机器上用目标环境的 PHP 运行 composer install --dry-run 验证兼容性,提前暴露问题
  • 若必须支持多 PHP 版本,可在 composer.json 中用 config.platform.php 锁定虚拟平台版本,避免锁文件记录真实环境信息

为什么不用 composer archive 或私有 Packagist?

这两个方案在 air-gapped 场景下反而增加复杂度,不是“不能用”,而是容易忽略部署链路断点。

composer archive 生成的是单个项目源码包,不含依赖,也不带 autoloader 映射;私有 Packagist(如 Satis)需要额外维护 Web 服务、HTTP 路由、https 证书、用户鉴权 —— 而 air-gapped 系统通常连基础 Web 服务都不允许启用。

  • 私有 Packagist 的 packages.json 必须定期 rebuild,一旦漏掉某个子依赖的更新,离线 install 就会失败
  • composer archive 输出的 zip 解压后仍是源码,仍需执行 composer install,又回到网络问题
  • 真正轻量可控的方式,是把「已验证可运行」的 vendor/ 当作构建产物交付 —— 类似 Go 的静态编译,不追求过程优雅,只保结果确定

最易被忽略的一点:不同项目的 vendor/ 目录不能混用,哪怕包名版本相同。Composer 的 autoloader 是基于当前项目路径生成的,跨项目挪用会导致类加载路径错乱,报 class not found 却查不出原因。

text=ZqhQzanResources