在 Jenkins 上为多个环境构建工件并将其上传到 S3

Posted

技术标签:

【中文标题】在 Jenkins 上为多个环境构建工件并将其上传到 S3【英文标题】:Building Artifacts on Jenkins for Multiple Environments and Uploading them to S3 【发布时间】:2013-07-29 00:56:47 【问题描述】:

环境:

大约十几个服务:WAR 和 JAR(使用 Tanuki 包装器运行) 每个服务都被部署到开发、登台和生产:环境使用不同的 web.xml 文件、Spring 配置文件(在 Tanuki 包装器上设置)... 我们希望将工件存储在 AWS S3 上,以便我们的 EC2 实例可以轻松获取它们:一些服务在多台机器上运行,AutoScaling 实例在启动后自动获取最新版本,开发工件应在它们完成后自动部署更新了,...

我们当前的部署过程如下所示:

    Jenkins 构建和测试我们的代码 一旦我们满意,我们就会使用 Artifactory plugin 发布版本(仅用于生产部署;开发和暂存工件基于普通的 Jenkins 构建) 我们使用Promoted Builds plugin 为每个项目(开发、登台、生产)提供 3 个不同的推广作业,为所需环境构建工件,然后将其上传到 S3

这几乎可以正常工作,但是我们遇到了多个烦恼:

    由于无法提交到存储库,Artifactory 插件无法标记和更新源代码(这可能特定于我们的 Jenkins 提供商 CloudBees)。没关系 - 我们可以手动完成。 Jenkins S3 plugin 不能正确处理多个上传目标(我们为每个环境使用一个) - 它会尝试上传到所有目标并在您保存配置时复制设置:JENKINS-18563。没关系 - 我们正在使用 shell 脚本进行上传,它工作正常。 提升作业有时会失败,因为它们可以在与原始构建不同的实例上运行 - 要么导致失败(因为文件丢失而构建),要么导致构建过时(因为正在使用旧版本)。同样,这可能由于 CloudBees 提供的特定设置而发生。这可以通过再次运行构建并希望这次升级作业在与其构建相同的实例上运行来解决(在我的理解中这纯粹是运气)。

CloudBees 建议我们在运行升级作业之前进行代码检查,因为工作区是短暂的,不能保证它存在或保持最新状态。但是,升级作业中的 shell 脚本似乎不遵守另一个 *** thread 中所述的环境变量,即使它们链接在 textarea 字段下方。所以svn checkout $SVN_URL -r $SVN_REVISION 不起作用。

我很确定这可以通过一些解决方法来解决,但我肯定做错了什么。我认为许多其他人正在以类似的方式部署他们的应用程序,并且必须有更好的方法 - 没有各种解决方法和烦恼。

感谢您的任何指点并阅读所有内容!

【问题讨论】:

您能否详细说明为什么您的 Artifactory 无法提交源代码控制? 看起来提交和标记毕竟很好,只是缺少对最新快照的更新。我创建了一个单独的问题,因为这只是一个小问题,而不是原始问题的核心:***.com/questions/17921881/… 【参考方案1】:

您面临的最大问题是您实际上想在促销活动中进行构建。提升的构建插件旨在执行一些小操作,主要是在构建的存档工件上,或者执行标记或其他此类操作。

该设计确保它在从属设备上获得工作空间。但是(这是一个通用的 Jenkins 事情,而不是 CloudBees 特定的)首先,您获得的工作空间不必是用于您要推广的构建的工作空间。可能是:

    一个空的工作区 项目最新版本的工作区(可能比您尝试推广的版本更新) 项目旧版本的工作区(当您无法进入具有项目最新版本的从属设备时)

现在,您获得哪些完全取决于您的 Jenkins 集群所承受的负载。在 CloudBees 上运行时,您通常最有可能遇到上述前两种情况。

因此,您在促销活动中采取的行动应该是“自给自足的”。因此,例如,他们会将存档的工件复制到特定目录中,然后使用这些复制的工件来做他们的“事情”。或者他们将触发下游构建,并通过提升的构建中的参数传递。或者他们将在远程服务器上执行一些操作而不使用任何本地状态(即在蓝绿部署中翻转开关)

就你而言,你在多条战线上作战。你在战斗的第二条战线是你在和 Maven 战斗。

Maven 不喜欢激活的构建配置文件生成不同的、非等效的工件。 Maven 可能可以使用 release 配置文件生成一个带有 javascript 缩小的工件版本,并且可能会剥离调试信息(尽管如果可以避免它会更好)...但那是因为这两个工件是相等的。一个经过 JavaScript 缩小的 web 应用应该和没有缩小的 web 应用一样好用(除非缩小会引入错误) 您使用配置文件来构建完全不同的工件。这很糟糕,因为 Maven 不会将活动配置文件存储为部署到 Maven 存储库的信息的一部分。因此,当您声明对其中一个工件的依赖时,您不知道在构建该工件时哪个配置文件处于活动状态。这样做的一个常见副作用是您最终会出现裂脑工件,其中复合工件的一部分与开发数据库通信,另一部分与生产数据库通信。当开发人员想要切换到构建生产构建时经常运行mvn clean install -Pprod && mvn clean install -Pprod,您可以看出这种不良代码气味,因为他们过去曾被脑裂工件烧毁。这是糟糕设计的症状,而不是 Maven 的问题(除了能够创建特定于架构的 Maven 工件构建会很好......但它们可能会引发自己的问题) 为不同部署环境处理不同工件创建的“Maven 方式”是使用单独的模块重新打包“通用”工件。作为典型的 Maven 处理不良架构的微妙方法,您需要为每个要定位的环境添加重新打包模块......这不鼓励拥有许多不同的目标环境......(即,如果你有 10 个 webapps/services部署和三个目标部署环境,您将拥有 10 个通用模块和 3x10 目标特定模块...提供 40 个模块构建)并希望鼓励您找到一种方法,让工件在部署时自行发现其正确配置。

我怀疑破解解决方案的最安全方法是依赖复制存档的工件。

    在主构建期间,创建一个文件,该文件将检出与正在构建的版本相同的版本,例如

    echo '#!/usr/bin/env sh' > checkout.sh
    echo "svn revert . -R" >> checkout.sh
    echo "svn update --force -r $SVN_REVISION" >> checkout.sh
    

    虽然你可能想写一些更健壮的东西,例如确保您在 SVN 工作副本中,确保工作副本使用正确的远程 URI,删除任何不需要的文件等

    确保您创建的脚本已存档。

    在升级过程开始时添加,将存档的checkout.sh 复制到工作区,然后运行该脚本。您应该能够像以前一样执行所有后续促销步骤。

更好的解决方案是为每个提升流程创建构建作业,并将 SVN 修订作为构建参数传递(但需要为您设置更多工作(因为您已经拥有提升流程设置)

最好的解决方案是修复您的体系结构,以便您生成能够从目标环境中发现其正确配置的工件,这样您就可以将相同的工件部署到每个所需的环境,而无需重新构建工件。

【讨论】:

感谢您的详细解答!假设我们可以创建一个通用工件(我将不得不与其他开发人员讨论这个问题),我如何将它复制到 S3(因为$WORKSPACE/target 将不可用)?至少我必须重命名 WAR / JAR 文件 (foo-latest.war) 并将其上传到 S3 - 这样 EC2 实例就有一个静态 URL 来获取应用程序。 回答我自己的问题:您需要一个后期构建步骤来存档工件。

以上是关于在 Jenkins 上为多个环境构建工件并将其上传到 S3的主要内容,如果未能解决你的问题,请参考以下文章

通过 jenkins 上传的 JFrog Artifactory 工件不会出现在构建中

ProGet 上传本地工件

在 Jenkins 插件中读取构建工件

如何在将通用工件上传到jenkins管道中的JFrog Artifactory时重命名现有文件夹

詹金斯从工件加载文件时出错

如何仅在 Jenkins 上为一个子模块执行包?