【问题标题】:How to deploy correctly when using Composer's develop / production switch?使用 Composer 的开发/生产切换时如何正确部署?
【发布时间】:2014-03-10 09:33:52
【问题描述】:

Composer 可以选择仅在开发时加载多个依赖项,因此这些工具不会安装在生产环境中(在实时服务器上)。这(理论上)对于仅在开发中才有意义的脚本非常方便,例如测试、假数据工具、调试器等。

要走的路是用你在开发中需要的工具添加一个额外的require-dev 块:

"require-dev": {
    "codeception/codeception": "1.6.0.3"
}

然后(理论上)通过

加载这些依赖项
composer install --dev

问题和疑问:

Composer 在 2013 年显着改变了 installupdate 的行为,现在默认安装 require-dev-dependencies (!),随意创建带有 require-dev 块的 composer.json 并执行composer install 进行复制。

由于最常见的部署方式是推送 composer.lock(保存您当前的 composer 设置),然后在生产服务器上执行composer install,这也将安装开发东西。

在不安装 -dev 依赖项的情况下部署此 的正确方法是什么?

注意:我试图在这里创建一个规范的 Q/A 来澄清奇怪的 Composer 部署。随意编辑这个问题。

【问题讨论】:

  • @all: 不知道赏金在哪里 :( 我将开始另一种方法。
  • 如果您不积极奖励它,并且没有答案被接受或获得足够的支持,那么没有人会获得赏金。
  • 我个人完全不喜欢这种方法。 composer.lock 永远不应该添加到 Git 存储库中,永远不要。正确的方法是在暂存时使用 composer update 然后将文件同步到生产中(当然,如果一切正常的话)。登台必须是生产环境的精确副本。 composer.lock 应该是 .gitignore 的一部分。
  • composer.lock 肯定会包含在您的 CSV 中!!!您还如何确保每个人都使用相同的版本?所以永远不要从你的 CSV 中排除 composer.lock !!!
  • @TobiasGaertner 我认为您的意思是 VCS(版本控制软件),否则您是正确的并且符合 the project's official recommendations

标签: php deployment composer-php


【解决方案1】:

为什么

恕我直言,Composer 现在默认使用--dev 标志(在安装更新时)是有充分理由的。 Composer 主要在需要行为的场景中运行:

Composer 的基本工作流程如下:

  • 新项目启动:composer.phar install --dev,json 和 lock 文件已提交到 VCS。
  • 其他开发人员开始参与该项目:签出 VCS 和 composer.phar install --dev
  • 开发人员添加依赖项:composer.phar require <package>,如果您想要在 require-dev 部分中的包(并提交),请添加 --dev
  • 其他人也同意:(结帐和)composer.phar install --dev
  • 开发人员想要更新版本的依赖项:composer.phar update --dev <package>(并提交)。
  • 其他人也同意:(结帐和)composer.phar install --dev
  • 项目已部署:composer.phar install --no-dev

如您所见,--dev 标志的使用(远)多于--no-dev 标志,尤其是当从事该项目的开发人员数量增加时。

生产部署

在不安装“dev”依赖项的情况下部署它的正确方法是什么?

好吧,composer.jsoncomposer.lock 文件应该提交给 VCS。不要省略 composer.lock,因为它包含有关应使用的软件包版本的重要信息。

执行生产部署时,您可以将 --no-dev 标志传递给 Composer:

composer.phar install --no-dev

composer.lock 文件可能包含有关开发包的信息。这没关系。 --no-dev 标志将确保未安装这些开发包。

当我说“生产部署”时,我指的是旨在用于生产的部署。我并不是在争论 composer.phar install 是否应该在生产服务器上完成,或者在可以审查事情的登台服务器上完成。这不是这个答案的范围。我只是指出如何在不安装“dev”依赖项的情况下composer.phar install

题外话

--optimize-autoloader 标志在生产环境中也可能是可取的(它会生成一个类映射,这将加速您的应用程序中的自动加载):

composer.phar install --no-dev --optimize-autoloader

或者当自动部署完成时:

composer.phar install --no-ansi --no-dev --no-interaction --no-plugins --no-progress --no-scripts --optimize-autoloader

如果您的代码库支持它,您可以将--optimize-autoloader 换成--classmap-authoritative。更多信息here

【讨论】:

  • 我同意大部分内容,但有一个例外。 “composer install --no-dev”应该只在临时环境中执行,并且该环境应该被认为是不可变的。我不想在我的生产服务器上直接下载任何依赖项,而无需通过预览/登台。这只是一个额外的小心。
  • @Scalable:虽然我同意你的看法(Sven 在他的回答中很好地涵盖了这一点),但这不是我回答的范围,也不是我所说的“生产部署”。我添加了一段来说明这一点。
  • 其实我认为默认应该是危险性较小的选项。将 --dev 设为默认值并在生产环境中意外安装 composer 可能是致命的。
  • --optimize-autoloader 中的好点。还要考虑--classmap-authoritative - 从这里的文档getcomposer.org/doc/03-cli.md 你可以看到:“仅从类映射中自动加载类。隐式启用--optimize-autoloader”所以如果你知道类“在那里”,你可以使用,这可能除非您动态生成类,否则应该在您的 prod 环境中发生。
  • 很好的答案,我建议直接在composer.json 中添加optimize-autoloader{"config": { "optimize-autoloader": true } }
【解决方案2】:

我认为自动化流程更好:

在您的 git 存储库中添加 composer.lock 文件,确保您在发布时使用 composer.phar install --no-dev,但在您的开发机器中,您可以使用任何 composer 命令而不担心,这不会投入生产,生产将基于锁定文件中的依赖关系。

在服务器上签出此特定版本或标签,并在替换应用程序之前运行所有测试,如果测试通过,则继续部署。

如果测试依赖于开发依赖,因为 composer 没有测试范围依赖,一个不太优雅的解决方案可以使用开发依赖(composer.phar install)运行测试,删除供应商库,再次运行 composer.phar install --no-dev,这将使用缓存的依赖项,因此速度更快。但是,如果您知道其他构建工具中的作用域概念,那就太难了

自动化这个,忘记其余的,去喝啤酒:-)

PS.:正如下面的@Sven 评论,不签出 composer.lock 文件不是一个好主意,因为这将使 composer install 像 composer update 一样工作。

您可以使用 http://deployer.org/ 实现自动化,这是一个简单的工具。

【讨论】:

  • 不提交和签出composer.lock 将使composer install 表现得像composer update。因此,您部署的版本不是您开发的版本。这可能会产生麻烦(鉴于最近在 Composer 中使用“替换”解决了唯一的安全问题,因此更是如此)。你不应该在无人看管的情况下运行composer update,而不验证它没有破坏任何东西。
  • @Sven 这是在同一评论中建议在部署之前自动运行单元测试的方式。但你是对的,最好还是保留 composer.lock 文件。
  • 现在您唯一需要解释的是:如何在没有 PHPUnit 等开发依赖项的情况下在服务器上运行测试?
  • 如果将依赖项、测试和部署放在一个工具中,比如 Java Gradle 或 SBT 甚至 Maven(maven 不太好),那就太好了。一个使 composer phpunit 和部署协同工作的 PHP 工具。甚至是制作这些东西的 Gradle 或 Scala SBT 插件,因为它们是不可知的构建工具,该插件甚至可以使用资产,如最小化 javascript 和编译 sass、最小化 css。有人知道吗?
  • 当然这是在服务器中测试真实环境,而不是直接在站点vhost中,您可以将其放在一个单独的临时文件夹中,并在成功时将结果移动到vhost中跨度>
【解决方案3】:

在生产服务器上,我将 vendor 重命名为 vendor-<datetime>,并且在部署期间将有两个供应商目录。

HTTP cookie 使我的系统选择新的供应商autoload.php,并且在测试之后我在它们之间进行了完全原子/即时切换以禁用旧的供应商目录以处理所有未来的请求,然后我删除了之前的目录一些几天后。

这避免了我在 apache/php 中使用的文件系统缓存引起的任何问题,并且还允许任何活动的 PHP 代码继续使用以前的供应商目录。


尽管有其他建议反对它,但我个人在服务器上运行 composer install,因为这比从我的暂存区域(我的笔记本电脑上的虚拟机)进行 rsync 更快。

我使用--no-dev --no-scripts --optimize-autoloader。您应该阅读每个文档以检查这是否适合您的环境。

【讨论】:

    【解决方案4】:

    实际上,我强烈建议不要在生产服务器上安装依赖项。

    我的建议是在部署机器上检查代码,根据需要安装依赖项(这包括在代码投入生产时不安装开发依赖项),然后将所有文件移动到目标机器。

    为什么?

    • 在共享主机上,您可能无法访问命令行
    • 即使您这样做了,PHP 也可能在命令、内存或网络访问方面受到限制
    • 可能未安装存储库 CLI 工具(Git、Svn),如果您的锁定文件记录了检查某个提交而不是将该提交作为 ZIP 下载(您使用 --prefer-source,或者 Composer 没有其他方法可以获取该版本)
    • 如果您的生产机器更像是一个小型测试服务器(想想 Amazon EC2 微实例),则可能甚至没有足够的内存来执行composer install
    • 虽然 Composers 尝试不破坏任何东西,但您对以部分损坏的生产网站结尾的感觉如何,因为在 Composers 安装阶段无法加载一些随机依赖项

    长话短说:在您可以控制的环境中使用 Composer。您的开发机器确实符合条件,因为您已经拥有操作 Composer 所需的所有东西。

    在不安装 -dev 依赖项的情况下部署它的正确方法是什么?

    要使用的命令是

    composer install --no-dev
    

    这将在任何环境中工作,无论是生产服务器本身,还是部署机器,或者是应该进行最后检查的开发机器,以发现是否有任何开发要求被错误地用于真实软件。

    该命令不会安装或主动卸载 composer.lock 文件中声明的开发需求。

    如果您不介意在生产服务器上部署开发软件组件,则运行 composer install 可以完成相同的工作,但只是增加移动的字节数,并创建更大的自动加载器声明。

    【讨论】:

    • 有趣的工作流程,但有一个很大的缺点:存储库不应包含供应商文件夹/内容本身(Composer 页面上的官方声明),因此它们永远不会被直接推送到在基于 git 的部署中生产(这是一个常见的标准 afaik,如果我错了,请纠正我)。所以基本上上述解决方案只适用于“老式” FTP 部署!?请让我们进一步讨论...
    • 我建议的工作流程不包括通过 GIT 将代码推送到生产服务器。事实上,我建议不要这样做,因为这样做会迫使您在生产服务器上安装 Composer 依赖项,这可能会带来很多问题。如果您希望您的部署顺利运行,您必须在销毁当前版本并替换它之前组装运行应用程序所需的所有代码。不喜欢 FTP?通过 SSH 进行 RSync,然后通过翻转符号链接来切换版本。但如果你愿意,你也可以在 prod 中 push、checkout 和 composer install。
    • @Panique:我刚刚看到了你的那部分评论,我必须回答:“在基于 git 的部署中推送到生产环境(这是一个常见的标准 afaik,请纠正我”米错)” - 不,这不是通用标准。这只是一种方法。
    • 我所在的团队已将其纳入他们的工作流程并取得了巨大成功。我们有一台构建机器(当然是 Jenkins),它:1)从 SC 签出 2)运行 composer install/update 3)运行单元测试 4)删除开发依赖项 5)生成一个 phar 文件(app-1.34.phar 等)。有一个单独的机制被通知并决定何时获取该文件,将其传输到何处以及如何处理它。一些团队选择将 phar 放在服务器上后对其进行解包,而一些团队则按原样运行它。这让我们对部署的稳定性和可重复性充满信心。
    • 我 100% 同意这个答案。 Composer 不应该安装在部署服务器上,也不应该安装在 git 上。持续部署/集成服务器应该管理源代码和依赖项获取: git pull > composer install > deploy
    【解决方案5】:

    现在require-dev 默认启用,对于本地开发,您可以在不使用--dev 选项的情况下执行composer installcomposer update

    当您想要部署到生产环境时,您需要确保composer.lock 没有来自require-dev 的任何包。

    你可以这样做

    composer update --no-dev
    

    使用--no-dev 在本地进行测试后,您可以将所有内容部署到生产环境并根据composer.lock 进行安装。此处再次需要--no-dev 选项,否则composer 会说“锁定文件不包含require-dev 信息”

    composer install --no-dev
    

    注意:小心任何可能在开发和生产之间引入差异的事情!我通常会尽可能避免 require-dev,因为包含开发工具并不是很大的开销。

    【讨论】:

    • 这在细节上其实是不正确的。无需检查 composer.lock 的开发依赖项。您只需运行 composer install --no-dev,您将只安装常规依赖项 - 事实上,Composer 还将在此步骤中删除任何开发依赖项。
    • 如果我的本地 composer.lock 中有开发依赖项(并可能影响非开发包的版本),那么我想更新它以反映它在生产中的情况。这也迫使您在生产中运行composer install --no-dev,因为composer install 会出错。从技术上讲,我认为您是对的;这不是必需的,但这是我喜欢的额外安全级别。
    • 好的,演示场景:您的应用需要dev/toolprod/lib:~1.0。最新的 prod/lib 是 1.3,但 dev/tool 还需要 prod/lib:1.1.*。结果:您将安装版本 1.1.9(最新的 1.1.x 分支)并在开发过程中使用它。我会说只更新--no-dev 是不安全的,因此包括最新的 prod/lib 1.3 并假设一切正常而无需测试。由于缺乏开发/工具,因此可能无法进行测试。我会假设因为在生产中不需要 dev/tool,所以不应该推出它,但是软件必须使用 prod/lib 1.1.9。
    • 如果您使用的是--no-dev,那么您需要在本地测试它,正如我在答案中提到的那样。我仍然建议不要使用--no-dev
    • 所以基本上你建议这个:composer update,然后做一些开发,然后做composer update --no-dev,然后做发布测试,然后推送到生产并做composer install --no-dev。两个问题:1. 我无法在没有开发依赖项的情况下测试版本,以及 2. 我无法在生产环境中安装例如 Git。
    猜你喜欢
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-14
    • 1970-01-01
    • 2019-04-15
    相关资源
    最近更新 更多