Java Web部署:构建代码还是部署.war文件?

9
部署J2EE/Java Web应用程序的两种主要方式(在非常简单的意义上):
部署已组装的构件到生产环境中:
在这种情况下,我们在其他地方创建了.war文件(或其他文件),将其配置为生产环境(可能为多个盒子创建 numerous artifacts ),并将生成的构件放置在生产服务器上。
优点:生产环境中没有开发工具,可以直接重复使用测试中的构件,执行部署的人员不需要了解构建过程。
缺点:创建和部署构件需要两个过程;预先构建的构件的潜在复杂配置可能使流程难以脚本化/自动化;必须对二进制构件进行版本控制。
在生产环境中构建构件:
在这种情况下,日常用于在开发人员桌面上构建和部署的相同过程用于部署到生产环境。
优点:只需维护一个过程;并且它经过频繁使用进行了大量测试/验证。在构件创建时可能更容易定制配置,而不是在后期定制预先构建的构件;不需要对二进制构件进行版本控制。
缺点:所有生产环境中都可能需要复杂的开发工具;部署人员需要了解构建过程;您没有部署您测试过的东西。
我主要使用第二个过程,但是这也是出于必要性(没有时间/优先级进行另一个部署过程)。个人而言,我不认同“生产环境必须清除所有编译器等”的论点,但我可以理解部署已测试的内容(而不是构建另一个构件)的逻辑。
然而,Java Enterprise应用程序对配置非常敏感,因此在配置构件时有两个流程似乎会引发麻烦。
想法是什么?
更新:
以下是一个具体的示例:
我们使用OSCache,并启用磁盘缓存。配置文件必须位于.war文件中,并引用文件路径。该路径在每个环境中都不同。构建过程检测用户配置的位置,并确保放置在war中的属性文件对其环境正确。
如果我们将构建过程用于部署,那么只需为生产环境创建正确的配置即可(例如 production.build.properties )。
如果我们遵循“部署已组装的构件到生产环境中”,则需要另一个过程来提取(不正确的)OSCache属性并将其替换为适合于生产环境的属性。
这样就创建了两个过程来完成相同的事情。
因此,问题是:
是否可以避免这种情况而无需在生产环境上进行编译?
如果不能,这是否值得?“不要重复自己”的价值大于“不在生产环境中编译”吗?
7个回答

7
我坚决反对在生产服务器上进行部署,因为这意味着你使用的是与测试不同的程序版本。这也意味着每个部署机器都有一个不同的JAR/WAR文件。即使没有其他原因,也要做统一编译,以便在跟踪错误时不必担心服务器之间的不一致性。
此外,如果您能轻松映射构建和创建它的源代码之间的关系,就无需将构建放入版本控制中。
在我们工作的地方,我们的部署流程如下(这是在Linux上,使用Tomcat):
1. 测试更改并提交到Subversion。(不一定按顺序;我们不要求提交的代码经过测试。我是唯一的全职开发人员,所以SVN树本质上是我的开发分支。您可能会有不同的情况。) 2. 将JAR/WAR文件复制到以Subversion版本号命名的共享目录中的生产服务器上。Web服务器只有读取权限。 3. 部署目录包含指向版本命名目录中的文件的相对符号链接。这样,目录列表将始终显示生成正在运行的版本的源代码版本。在部署时,我们更新一个日志文件,它只是一个目录列表。这使得回滚变得容易。(但需要注意的是,Tomcat通过真实文件的修改日期而不是符号链接来检查新的WAR文件,因此在回滚时我们必须触摸旧文件。) 4. 我们的Web服务器将WAR文件解压缩到本地目录。此方法具有可扩展性,因为WAR文件位于单个文件服务器上;我们可以有无限数量的Web服务器,并且只进行单个部署。

如果您有信心可以从源代码重新创建war文件,为什么不在生产环境中构建它呢?如果将war文件视为神圣的话,似乎应该将其放入版本控制中... - davetron5000
首先,我不太自信能够纯粹地从源代码创建它。有些东西无法正确地检入 SVN,或者我需要一个特殊的测试生产环境构建来解决难以重现的错误。另外,我们备份 WAR 文件;SVN 历史记录用于调试,而不是回滚。 - David Leppik
你可以在生产环境中拥有自动化部署程序,但不要在其上进行构建(因为您需要测试构建等等)。 - Thorbjørn Ravn Andersen

3

我曾经工作的大部分地方都使用第一种方法,即将特定于环境的配置信息单独部署(并且更新频率更低),而不是与war/ear一起部署。


1

存在配置服务,例如重量级 ZooKeeper,大多数容器都可以使用 JNDI 进行一些配置。这将把配置与构建分离,但可能会过度。然而,它们确实存在。很多取决于您的需求。

我还使用了一种流程,其中构件使用占位符来存储配置值。当 WAR 部署时,它会被解压并用适当的值替换占位符。


1
我强烈推荐“将已组装的构件部署到生产环境”,例如war文件。这就是为什么我们的开发人员在他们的开发沙盒中使用相同的构建脚本(在我们的情况下是Ant)来构建war,就像用于创建最终构件一样。这样它就像代码本身一样被调试,更不用说完全可重复了。

我不明白,如果开发人员正在使用相同的脚本,那么这不就是“在生产环境中生成工件”的情况吗?您是否有一个脚本用于编译和创建war文件,另一个脚本用于部署它? - davetron5000

1
我会推崇使用支持分布式构建的持续集成解决方案。在您的SCM中检查的代码可以触发构建(进行即时测试),您还可以安排构建以创建QA的工件。然后,您可以将这些工件升级到生产环境并部署它们。
这是我目前正在设置的内容,使用AnthillPro
编辑:我们现在使用Hudson。强烈推荐!

1
除了我们使用开源构建服务器Hudson之外,答案也是一样的。自动构建服务器可以自动构建、测试和生成所有构建产品以进行测试和部署,这是一件好事。 - John Munsch

0

如果您在相对于配置管理方面提出这个问题,那么您的答案需要基于您认为的受控制构件来确定。从配置管理角度来看,在一个环境下使用某些源文件能够运行而在另一个环境中不能运行是不可接受的情况。配置管理对环境变量、优化设置、编译器和运行时版本等非常敏感,您必须考虑到这些因素。

如果您在相对于可重复流程创建方面提出这个问题,那么答案需要基于您愿意容忍的痛苦的位置和数量来确定。使用 .war 文件可能会导致更多的前期痛苦,以节省测试和部署周期的工作量。使用源文件和构建工具可能会节省前期成本,但是您将不得不忍受更多的痛苦来应对部署过程中的问题。

针对具体示例的更新

与您的示例相关的两个问题。

  1. .war 文件只是带有替代扩展名的 .zip 文件。您可以使用标准 zip 实用程序直接替换配置文件。

  2. 重新考虑是否需要将配置文件放在 .war 文件中。将其放在类路径上或在服务器启动时在执行命令行中指定属性是否足够。

通常,我会尽量将部署配置要求限定在特定的部署位置。

0

使用1个打包好的war文件进行部署是一个良好的实践。
我们使用ant来替换不同环境之间的值。我们在文件中使用 @@@ 变量,这个变量将被我们的ant脚本替换。Ant脚本替换文件中正确的项,并在每次部署之前更新war文件。

<replace file="${BUILDS.ROOT}/DefaultWebApp/WEB-INF/classes/log4j.xml" token="@@@" value="${LOG4J.WEBSPHERE.LOGS}"/>


<!-- update the war file We don't want the source files in the war file.-->
<war basedir="${BUILDS.ROOT}/DefaultWebApp" destfile="${BUILDS.ROOT}/myThomson.war" excludes="WEB-INF/src/**" update="true"/>

总结一下,Ant 可以完成所有的工作,而我们使用 Anthill 来管理 Ant。Ant 会构建 war 文件,替换文件路径,更新 war 文件,然后部署到目标环境。实际上,这是一个流程,只需要在 Anthill 中点击一个按钮即可完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接