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();

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

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

@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年前

@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年前

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

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

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

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

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

4年前 评论

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

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年前 评论

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

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

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年前

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