Laravel 项目抽离 vendor 目录的问题

第一次来问问题,最近才用laravel框架,之前一直用yaf及公司自研框架

核心的问题是:希望把vendor目录从项目代码中抽离出来,实现单独部署vendor并几个项目共用一个vendor。
遇到的问题是:把vendor目录拷贝出来到一个单独目录,然后软连接ln -s到项目目录中的vendor,但它不工作,找到的原因是laravel框架引入项目文件时是从单独出来的vendor目录查找,所以很显然是找不到的。

把vendor抽离出来的原因是:希望自动化部署,不希望每次增加新包或者更新包的时候在部署的时候需要composer require ,单独部署vendor。

生成环境运行composer真的很蛋疼

有没有同学抽离过vendor,分享一下经验。

附言 1  ·  4年前

@Wi1dcard 提供了比较成熟的部署方案。

刚刚我也解决了vendor抽离只后autoload不到的问题
在bootstrap注册autoload就可以了。
./bootstrap/app.php

<?php
require_once __DIR__ . '/../vendor/autoload.php';

$autoload = new Composer\Autoload\ClassLoader();
$autoload->addPsr4('App\\', "../app/");
$autoload->addClassMap([
    "database/",
    "tests/"
]);
$autoload->register();

非常感谢大家的意见和建议。

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
最佳答案

@Thinklong

首先我们肯定是希望至少一个项目组使用的环境、版本都统一,也是规范化的其中一项吧,所以把lock和json及vendor统一在git上管理(最小颗粒是项目组统一),这样就不会出现lock文件管理和扩展包依赖的问题。

vendor 绝对不应该进入版本管理,应当进入版本管理的是 lock,同一个 lock 安装出来的依赖应当是完全一致的。

我非常赞同你所说的部署方案,但如果我有20台目标机需要部署,在目标机进行install会有很多问题,比如部署周期可能会比较长、其中一台install失败就得重新部署等等很多不可控的因素。

在服务器上直接 composer install 也是可以的,但是就需要一套编排 / 部署系统来调度,如果遇到某台机器安装依赖失败,那么就不能把流量导向过去(不需要全部重新部署)。目前来看比较优秀的方案是 Kubernetes,很多国内厂也做了不少类似的轮子项目,你可以自行 Google。

如果在部署机先install然后打包scp到目标机,部署机如果项目比较多,部署机会吃不消。

其实没多少压力。composer install 主要就是网络流量的消耗,根据你的方案,这台「部署机」应当是个长期存在的实例,包含着每次依赖安装产生的 Composer global cache,而项目的依赖变动一般不会太大,所以每次 Install 其实没什么压力。如果是担心「部署机」到「目标机」的网络流量消耗的话,现在云服务商都有 VPC 功能,直接走内网即可。

按照这个方案施行的话,我推荐一个工具:Ansible。

最后,你提到的方案是「所谓部署机」 代码到「实际服务器」。如果有做 CI 的话,我还是更推荐 CI 上只打 Artifact 并上传到对象存储,随后通知「实际服务器」到对象存储 代码。

4年前 评论
未进化的类人猿 3年前
讨论数量: 21

@Thinklong

首先我们肯定是希望至少一个项目组使用的环境、版本都统一,也是规范化的其中一项吧,所以把lock和json及vendor统一在git上管理(最小颗粒是项目组统一),这样就不会出现lock文件管理和扩展包依赖的问题。

vendor 绝对不应该进入版本管理,应当进入版本管理的是 lock,同一个 lock 安装出来的依赖应当是完全一致的。

我非常赞同你所说的部署方案,但如果我有20台目标机需要部署,在目标机进行install会有很多问题,比如部署周期可能会比较长、其中一台install失败就得重新部署等等很多不可控的因素。

在服务器上直接 composer install 也是可以的,但是就需要一套编排 / 部署系统来调度,如果遇到某台机器安装依赖失败,那么就不能把流量导向过去(不需要全部重新部署)。目前来看比较优秀的方案是 Kubernetes,很多国内厂也做了不少类似的轮子项目,你可以自行 Google。

如果在部署机先install然后打包scp到目标机,部署机如果项目比较多,部署机会吃不消。

其实没多少压力。composer install 主要就是网络流量的消耗,根据你的方案,这台「部署机」应当是个长期存在的实例,包含着每次依赖安装产生的 Composer global cache,而项目的依赖变动一般不会太大,所以每次 Install 其实没什么压力。如果是担心「部署机」到「目标机」的网络流量消耗的话,现在云服务商都有 VPC 功能,直接走内网即可。

按照这个方案施行的话,我推荐一个工具:Ansible。

最后,你提到的方案是「所谓部署机」 代码到「实际服务器」。如果有做 CI 的话,我还是更推荐 CI 上只打 Artifact 并上传到对象存储,随后通知「实际服务器」到对象存储 代码。

4年前 评论
未进化的类人猿 3年前

每个项目都有不同的包,公用了可能更麻烦

4年前 评论
fffswhk 4年前
Thinklong (楼主) 4年前
Thinklong (楼主) 4年前
Wi1dcard 4年前
22 (作者) 4年前
Thinklong (楼主) 4年前

没做过 每个vendor/composer/都是__DIR___ 手动修改应该就可以了。

    public static $files = array (
        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
        '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',

不过composer-dump-autoload就失效了,每次更新都要手动修改,应该可以写个脚本替换。
我个人觉得你这个想法很好。

4年前 评论
Epona

在生产上弄两套代码,一套composer 之后,将vendor 复制到另一份下面就可以吧

4年前 评论

这是不久前写的一个测试环境部署的jenkins脚本,分为打包和部署。解压和传输在jenkins上做的,懒得拉了。

build机器下装依赖打包,服务器全量更新

只为了能用省事,没有优化过,所以大佬们看到轻喷

archive.sh

#!/usr/bin/env bash

# 这个文件在根目录执行

UPLOAD_FILE_NAME=msy-push.tar

composer install --ignore-platform-reqs
/usr/local/php71/bin/php -v
rm -f deploy-cache/${UPLOAD_FILE_NAME}
tar --exclude 'deploy-cache' --exclude='.git' -zcf deploy-cache/${UPLOAD_FILE_NAME} ./

deploy.sh

#!/usr/bin/env bash

# 默认项目上传到临时目录 /root/deploy 下,文件名为 PROJECT_NAME
# web提供服务目录为 /data/wwwroot/msy 软连接到 /data/wwwroot/${DEPLOY_ROOT_NAME}/${PROJECT_NAME}

project_path=$(cd `dirname $0`; pwd)
up_project_path="${project_path%/*}"
PROJECT_NAME="${up_project_path##*/}"
DEPLOY_ROOT_NAME=msy-push
DEPLOY_SYMLINK_NAME=msy-push
DEPLOY_ENV_NAME=.msy-push.env
DEPLOY_UP_NAME=msy-push-deploy

mv ${PROJECT_NAME} /data/wwwroot/${DEPLOY_UP_NAME}/${PROJECT_NAME}
cp /root/deploy-config/${DEPLOY_ENV_NAME} /data/wwwroot/${DEPLOY_UP_NAME}/${PROJECT_NAME}/.env
cd /data/wwwroot/${DEPLOY_UP_NAME}/${PROJECT_NAME}
/usr/local/php71/bin/php artisan optimize
/usr/local/php71/bin/php artisan migrate --force
cd /data/wwwroot
chown -R www:www ${DEPLOY_ROOT_NAME}/${PROJECT_NAME}
chmod -R 755 ${DEPLOY_ROOT_NAME}/${PROJECT_NAME}
rm -f ${DEPLOY_SYMLINK_NAME}
ln -sf /data/wwwroot/${DEPLOY_UP_NAME}/${PROJECT_NAME} ${DEPLOY_SYMLINK_NAME}
chown -h www:www ${DEPLOY_SYMLINK_NAME}
chown -R www:www ${DEPLOY_UP_NAME}/${PROJECT_NAME}
4年前 评论

我不太赞成这么做。观点如下:

  1. 如何管理 composer.lock 文件?多个项目共享 vendor,那么它们的 lock 文件必须保持一致。暂时想不到什么好的解决方案能够比较容易地在多个 Git repo 内共享 composer.lock。
  2. 不得不保证所有项目依赖的扩展包版本全部一致,出现依赖版本冲突时无法解决;升级某一个扩展包将会直接影响多个项目。

针对这个问题,以下是我觉得比较好的部署方案:

  1. 滚动部署,利用 Deployer 或者类似的方案(新创建一个副本、等待部署完成后,再将流量「导向」至新的副本)。
  2. 直接在 CI 上执行 Composer install,并打包 Artifacts。在服务器上直接下载带有依赖的 Artifact 压缩包并解压即可。
4年前 评论
Thinklong (楼主) 4年前

现在我就是这么弄的,生产环境有个 vendors 文件夹,ln -s 链接过去,vendors 文件夹下面每一个目录都是 vendor,命名是 composer.json 的 md5sum,根据 md5 值算出该 composer.json 是否有现成对应的 vendor,有就软链接,没有就同步过去

4年前 评论
"config" : {
    "vendor-dir": "....."
}
4年前 评论

这种做法本质上已经增加了项目之间依赖的耦合度。CICD 是可以做到 vendor 缓存,比如:drone还有对于项目的升级对于用户体验而言,可以选择滚动升级,这样就不影响客户的体验了。

4年前 评论

@Thinklong

首先我们肯定是希望至少一个项目组使用的环境、版本都统一,也是规范化的其中一项吧,所以把lock和json及vendor统一在git上管理(最小颗粒是项目组统一),这样就不会出现lock文件管理和扩展包依赖的问题。

vendor 绝对不应该进入版本管理,应当进入版本管理的是 lock,同一个 lock 安装出来的依赖应当是完全一致的。

我非常赞同你所说的部署方案,但如果我有20台目标机需要部署,在目标机进行install会有很多问题,比如部署周期可能会比较长、其中一台install失败就得重新部署等等很多不可控的因素。

在服务器上直接 composer install 也是可以的,但是就需要一套编排 / 部署系统来调度,如果遇到某台机器安装依赖失败,那么就不能把流量导向过去(不需要全部重新部署)。目前来看比较优秀的方案是 Kubernetes,很多国内厂也做了不少类似的轮子项目,你可以自行 Google。

如果在部署机先install然后打包scp到目标机,部署机如果项目比较多,部署机会吃不消。

其实没多少压力。composer install 主要就是网络流量的消耗,根据你的方案,这台「部署机」应当是个长期存在的实例,包含着每次依赖安装产生的 Composer global cache,而项目的依赖变动一般不会太大,所以每次 Install 其实没什么压力。如果是担心「部署机」到「目标机」的网络流量消耗的话,现在云服务商都有 VPC 功能,直接走内网即可。

按照这个方案施行的话,我推荐一个工具:Ansible。

最后,你提到的方案是「所谓部署机」 代码到「实际服务器」。如果有做 CI 的话,我还是更推荐 CI 上只打 Artifact 并上传到对象存储,随后通知「实际服务器」到对象存储 代码。

4年前 评论
未进化的类人猿 3年前

QAQ 20 台机器了,不考虑考虑自己做 Composer 镜像?这样内网更新快,其次还稳定版本,专人负责管理 Composer 镜像也合情合理了~

4年前 评论
xianyunyehe

自动化部署,你可以用jekins 服务器上第一次composer 了之后,一般都有缓存,下次install 很快。

4年前 评论

可以优化下

$autoload = require_once __DIR__ . '/../vendor/autoload.php';

$autoload->addPsr4('App\\', "../app/");
$autoload->addClassMap([
    "database/",
    "tests/"
]);
$autoload->register();
4年前 评论
MCZHNTTHXQ 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!