我喜欢认为有两个问题空间:
构建工件(理想情况下与环境无关,因为这意味着 QA 可以获取工件的哈希值,在该工件上运行他们的测试,当需要部署时,验证灰烬并且您知道它已经过 QA。如果您的构建产生不同的工件取决于 QA 的 env 还是 staging env 或生产 env,那么您必须做更多的工作以确保投入生产的工件已经过 QA 测试并已在 staging 中上演)
将工件运送到环境中。在该环境需要配置工件的情况下,运输过程应该包括该配置,或者通过将适当的配置文件放在目标环境中并让工件拾取它,或者通过打开工件、配置它们并将它们密封回去向上(但以可重复和确定的方式)
Maven 是为第一个问题空间而设计的。“Maven 方式”是关于生成与环境无关的构建工件并将它们发布到二进制工件存储。如果您查看 Maven 生命周期,您将看到在工件被deploy
编辑到 Maven 存储库(二进制工件存储)之后阶段停止。简而言之,Maven 认为它的工作已经完成。test
此外,对于uniting 和ing有生命周期阶段,integration-test
这两个阶段都应该可以通过与环境无关的工件来实现,但这并不是您需要的完整测试集......而是要完成您的测试,您需要实际部署将构建的工件放入真实环境中。
许多人试图劫持 Maven 以超越其目标(包括我自己)。例如,您有cargo-maven-plugin
和ship-maven-plugin
which 涉及 maven 最终游戏之外的方面(即在工件到达 maven 存储库之后)。其中,我个人觉得,ship-maven-plugin
(我写的,因此我以前的“包括我自己”)最接近使用“在 maven 之后”,因为默认情况下它被设计为运行,而不是在-SNAPSHOT
您检查过的项目版本上运行在磁盘上,而是在它从远程存储库中提取的同一项目的发布版本上,例如
mvn ship:ship -DshipVersion=2.5.1
IMO,货物的目的是在integration-test
生命周期的各个阶段使用,但同样,您可以将其劫持用于其他目的。
如果您正在生产收缩包装的软件,即用户购买并安装在其系统上的那种软件,安装程序本身旨在为最终用户环境配置应用程序。让 Maven 构建生成安装程序很好,因为实际的安装程序(至少在某种程度上)与环境无关。好的,它可能是仅 Microsoft Windows 的安装程序,或仅 Linux 的安装程序,但它并不关心它安装在哪台用户机器上。
不过,现在我们倾向于更多地关注软件即服务,因此我们将软件部署到我们控制的服务器上。更容易被拖到“Maven 黑暗面”,其中构建配置文件用于调整构建工件的内部配置(毕竟我们只有三个部署到的环境)并且我们正在快速移动,所以不想花时间让应用程序从外部到构建的工件(听起来很熟悉?)中获取特定于环境的配置。我称之为黑暗面的原因是你真的在与 maven 想要的工作方式作斗争......你总是想知道本地存储库中的 jar 是否是使用不同的配置文件构建的,所以你最终不得不做完整的始终保持干净的构建。pom.xml
...试想一下,如果您遵循 maven 方式,您只需从存储库中获取工件并将其移动到不同的环境中,未经修改,不受干扰,并使用 MD5、SHA1(希望是 GPG)签名来证明它是同一个神器。
所以,你问,我们如何编码运输到生产......
那么有很多方法可以解决这个问题。他们都有一套相似的核心原则,即
您可以使用良好的旧 bash 脚本,或者您可以使用更“现代”的工具,例如为第二个问题空间设计的 chef 和 puppet。
建议
您应该为正确的工作使用正确的工具。
如果是我,我会这样做:
使用 Maven 发布插件削减发布
构建的工件应该始终与环境无关。
构建的工件应包含所有配置选项的“合理默认值”。换句话说,如果缺少没有合理默认值的必需配置选项,它们应该快速爆炸,或者如果未指定可选选项,它们应该以合理的方式执行。所需配置选项的一个示例可能是数据库连接详细信息(除非应用程序乐于使用内存数据库运行)
在厨师 vs 傀儡战争中选择一方(无论哪一方,如果你愿意,你可以改变立场。如果你有 ANT 思维,厨师可能更适合你,如果你喜欢依赖管理魔法,傀儡可能更适合你更好的)
开发人员应该在定义用于部署的主厨/木偶脚本方面有发言权,至少是这些脚本的与环境无关的部分。
操作应定义 Chef/puppet 部署的生产环境特定细节
将所有这些脚本保存在 SCM 中。
使用 Jenkins 或任何 CI 来自动化尽可能多的步骤。Jenkins 的升级构建插件是您的朋友。
您的最终游戏是每次提交,只要它通过了所有必需的测试,*可以*自动部署到生产中(或者也许有人说“继续”)......注意不要说你实际上是这样做的对于每一次提交,只有你可以