转载

使用 Bluemix 将 Java 应用程序迁移到混合云,第 3 部分

在本系列的第 1 部分 和第 2 部分 中,我们介绍了将 Web 应用程序迁移到 Bluemix™ 的典型 Java EE 用例。现在我们会问,如果您有一个独立(stand-alone)的 Java 应用程序该怎么办?您如何让一个具有 main() 方法的 Java 应用程序在 Bluemix 中运行?

这是一个常见的场景。可能有许多原因导致您想要这么做。您的应用程序可能是一个批处理程序,它按一个时间表运行,会在停止或睡眠之前的短时间内执行某种密集的数据处理。它可能是一个在协议(比如 AMQP)上监听命令的程序。或者它可能使用一个嵌入式 HTTP 服务器(比如 Netty)而不是框架(比如 Spring 或 JEE)。

在我们完成实现此场景的过程后,我们发现了一些有关 Cloud Foundry 和 Bluemix 的架构,以及在它们之中如何管理应用程序的有趣信息。事实证明,前面的问题有一个非常简单的答案,我们将在文末介绍。但是,除非您首先跟随我们走一些弯路,否则您无法理解 为什么 这个简单的答案是真的,或者如何自行找到这样的答案。

构建您的应用程序所需内容

  • 一个 Bluemix 帐户
  • 一个 Eclipse 开发环境
  • Cloud Foundry CLI (参见第 1 部分)

获取代码

这是一个教程系列的第 3 部分,将介绍如何在 Bluemix 中运行独立的 Java 程序。我们会分享一些浏览 Cloud Foundry 文档,使用 CF 命令行工具,以及在 Cloud Foundry 和 Bluemix 中调试的技巧。

PaaS 的优缺点

Bluemix 是所谓的 平台即服务 (PaaS) 的一个示例。使用您的平台作为服务会让开发人员的工作更轻松,因为这样可以提供简单的工具和运行时来帮助完成开发人员必须执行的最常见任务。但是请注意短语 “最常见”。大多数 PaaS 层都共享同一哲学理念:它们假设您在开发中采取一条明确、显眼的路径。如果您偏离了该路径,它们就会为您提供一些指引,但不要期望这些踪迹被标记出来,也不要期望它们是经常有人采用的路径。

这就是我们的示例应用程序面临的问题。如果查看许多 Bluemix 应用程序示例,您会看到目前在构建 Java 应用程序时采用的最常见路径针对的是使用 Liberty Application Server 的应用程序。但我们的情况更简单。我们不需要应用服务器。我们仅有一个包含一个 main() 方法的程序。要确定如何开始,我们需要执行第一步。

第 1 步. 创建一个 Java JAR 文件

为了了解程序运行情况,哪里可能出错和如何调试,我们将从我们运行的 Java 应用程序的一个简化版本开始。我们将使用 Eclipse 开发我们的代码,但不会使用针对 Bluemix 的 Eclipse 插件来部署此示例。相反,我们使用 Cloud Foundry 命令行接口,使用日志来调试。

此示例使用两个 Java JAR 文件:hellojavamain.jar 和 hellojavamainrunnable.jar。可单击上面的 “获取代码” 链接获取这两个文件。另外,如果喜欢自行构建(并学习更多知识),可执行这些步骤。

  1. 在 Eclipse 中创建一个新 Java 项目(选择 File > New > Java Project )。将该示例命名为 "HelloJava" 。在 Create a Java Project 窗口中,确保将 Execution Environment 设置为 JavaSE-1.6 并单击 Finish
  2. 创建一个新 Java 类(选择 New > Class ),并将它命名为 HelloJavaMain (对于本例,在默认包中创建它就行了)。
  3. 将您的类的源代码替换为以下 Java 源代码:
    public class HelloJavaMain { public static void main(String[] args) {  for (int i=0; i<1000; i++) {  System.out.println("It worked! Hello World!");  try {   Thread.sleep(1000);   } catch (InterruptedException e) {  // This should not happen   e.printStackTrace();  }  } } }
    这只是长期运行的 Java 进程的一个简单示例。它最终将在 1000 秒后结束,这对我们的示例而言已足够长。此代码只是一个复杂示例的简化版本,而复杂示例可执行一些有趣的操作,比如处理一些数据,或者甚至监听某个异步协议上的连接。
  4. 选择该类,然后使用 Run As > Java Application 菜单选项来测试该代码。
  5. 您应在 Eclipse 控制台中看到许多类似这样的输出:
    It worked!Hello World!
  6. 使用 Eclipse Export 功能将此项目导出为 JAR 文件: File > Export
  7. 在导出窗口中选择 Java > JAR File ,然后选择您的项目。将该 JAR 文件命名为 hellojavamain.jar 并单击 Finish

第 2 步. 将应用程序部署到 Bluemix:第一次尝试

现在我们将进入这种简单而幼稚的方法的有趣部分。您会认为可以像其他数十个使用 Bluemix 和 Cloud Foundry 的示例一样,只需使用 cf push 和一些额外的参数。

cf push hellojavamain-ABC -p hellojavamain.jar

在本例中,要推送的第一个参数是要创建或更新的应用程序的名称。 –p 参数指定您想要运行的代码的位置(即您的 JAR 文件)。

  1. 登录到 Cloud Foundry Tools 并输入一个类似下面这样的命令:
    cf push hellojavamain-<your_initials> -p hellojavamain.jar
    例如,
    cf push hellojavamain-ABC -p hellojavamain.jar
    (注意:附加您姓名的首字母或任何 3 个随机字母,以避免应用程序由于没有唯一的名称而失败。)
  2. 如果正确编写了代码,程序应该很有希望成功。它应该首先将您的 JAR 文件识别为 Java 代码,将选择 Java Liberty buildpack。然后上传该 droplet(这是一个包含您的代码和 Java Liberty 的已打包容器)并尝试运行它。但是,您将在 cf push 命令的输出中看到一系列重复的消息:
    0 of 1 instances running, 1 starting
    0 of 1 instances running, 1 starting

    最终,这一系列消息的末尾是以下崩溃消息:
    FAILED
  3. 要确定何处发生了故障,可输入以下命令:
    cf logs hellojavamain-ABC -–recent
  4. 开始浏览日志时,您会在日志深处发现一个有趣的行,它类似于:
    2015-08-09T17:09:15.31-0400 [App/0] ERR [ERROR ] CWWKZ0124E:Application myapp does not contain any modules.
    这一行告诉我们,应用程序要求该 JAR 文件是包含 JEE 模块的文件,而不是包含一个 main() 方法的 Java SE JAR 文件。这是我们的第一个教训:最简单、最幼稚的部署机制行不通。

第 3 步. 将应用程序部署到 Bluemix:第二次尝试

这一次,您可能认为(像我当初一样),问题在于在我们完全不需要 Liberty 应用服务器时,Bluemix 默认选择了 Java Liberty buildpack。如果阅读了本系列的第 1 部分,您会知道在 Bluemix 中,还有另一个 Java 开发选项:标准的 Java buildpack 。可为 push 使用 – b 命令行选项,选择一个与自动选择的 buildpack 不同的 buildpack。

  1. 登录到 Cloud Foundry Tools,键入
    cf push hellojavamain-ABC -p hellojavamain.jar -b java_buildpack
    其中 ABC 替换为您的姓名首字母或任意 3 个随机字母。
  2. 您现在会看到出现了一个新问题。该命令尝试执行 push ,但最终得到一个错误:
    FAILED
    Server error, status code:400, error code:170004, message:App staging failed in the buildpack compile phase
  3. 为什么它会失败?如果再次输入
    cf logs hellojavamain-ABC --recent
    您会看到日志深处埋藏着下面这行内容:
    2015-08-09T17:25:19.52-0400 [STG] ERR No container can run this application
  4. 您可能会再次思考:这是什么意思?我完全没有使用 IBM Bluemix Container 服务。此错误信息实际上在单词 "container" 的使用上稍微有点歧义。该消息不是指 Docker 容器或 IBM Container 服务。 文档 规定:“容器组件表示应用程序将运行的方式。容器类型包括从传统的应用服务器和 servlet 容器到简单的 Java main() 方法执行。”
  5. 这就是本例中发生的情况。失败是由于 “容器组件” 没有理解它应如何运行该应用程序。事实上, 更深入 地分析文档会发现以下信息:“对于具有 main() 方法的 Java 应用程序,只要它们打包为自执行 JAR,就可以运行。”

第 4 步. 创建一个可运行的 JAR 文件并将应用程序部署到 Bluemix:第三次尝试

最后一行就是我们需要的线索。在 Java 编程中,您通过在 manifest.mf 文件中规定哪个类包含 main() 方法来使 JAR 文件可执行。在 Eclipse 中,可通过不将 JAR 文件导出为常规 JAR 文件,而导出为 Eclipse 所谓的 “可运行的” JAR 文件来实现此目的。

  1. 返回到 Eclipse 中,选择 File > Export 。在打开的 Export 窗口中,确保您没有导出为标准的 JAR 文件,而是选择 Runnable JAR file
  2. 在随后的窗口中,在 "Launch Configuration" 下的下拉菜单中选择 HelloJavaMain 类。这样,导出您的 JAR 文件时,会在该文件的清单文件中创建正确的条目。 使用 Bluemix 将 Java 应用程序迁移到混合云,第 3 部分

    点击查看大图

    关闭 [x]

    使用 Bluemix 将 Java 应用程序迁移到混合云,第 3 部分

  3. 这样能否修复该问题?在确定之前,我们应说明一下,如果您未使用 Eclipse,而只是使用命令行在操作,我们已提供了修改文件的副本:hellojavamainrunnable.jar。现在您已将 JAR 文件重新导出为可运行的 JAR 文件,可使用以下命令再次尝试运行它:
    cf push hellojavamain-ABC -p hellojavamainrunnable.jar -b java_buildpack
  4. 最初,此过程看起来很有希望。buildpack 执行编译,部署应用程序,这一次它找到了代码。但是,查看输出会看到以下信息:
    0 of 1 instances running, 1 starting
    0 of 1 instances running, 1 starting
    0 of 1 instances running, 1 down
    0 of 1 instances running, 1 down
    再次检查日志(使用与上面相同的命令),您会看到应用程序在实际运行和打印输出,但运行时间不长。事实证明您仍然遗漏了一部分关键信息。请注意日志中的这一行:
    2015-09-07T10:33:35.10-0400 [DEA] ERR Instance (index 0) failed to start accepting connections
  5. 在没有在 HTTP 上监听的 Java 应用程序中(比如我们的简单示例),您必须将 -no-route 参数添加到 push 命令中。否则,Cloud Foundry 会认为您希望将 HTTP 流量路由到您的程序。没有该参数,该类最初会加载到 Java 代码中,并正常启动和运行。但是最终, DEA 抛出了一个超时错误。

尽管在第一次尝试时应用程序实际已启动,但因为没有在监听器端口上监听它,所以 Cloud Foundry 认为它关闭了。

第 5 步. 指定一个工作者进程

我们通过最后一个命令将各部分结合起来,部署我们的 Java 工作者进程:

cf push hellojavamain-ABC -p hellojavamainrunnable.jar -no-route

此刻您可能会问,指定 Java buildpack 的 –b 选项发生了什么?我们希望向您介绍 Java buildpack,您可查阅 Cloud Foundry 网站上的文档,了解为什么需要可运行的 JAR 文件和 -no-route 选项。实际上,尽管您可指定 Java buildpack,但您也可在默认的 Liberty buildpack(它构建于 Java buildpack 之上)上完成所有这些工作。您可使用任意一个 buildpack,可使用 -b 参数在它们之间切换:

  1. 输入:
    cf push hellojavamain-ABC -p hellojavamainrunnable.jar -b java_buildpack -no-route

    cf push hellojavamain-ABC -p hellojavamainrunnable.jar -b liberty-for-java -no-route
  2. 在任意一个命令后,控制台应显示一个已请求的状态 started (没有关联的 URL)和一个 running 状态。 使用 Bluemix 将 Java 应用程序迁移到混合云,第 3 部分
  3. 在日志中,您应看到一系列成功消息,没有错误: 使用 Bluemix 将 Java 应用程序迁移到混合云,第 3 部分
  4. 像在之前的教程 中一样,您希望在完成后清理该应用程序。首先停止应用程序:
    cf stop hellojavamain-ABC
  5. 然后,删除它:
    cf delete hellojavamain-ABC 并回答 Y

结束语

我们在开发的道路上难免会走一些弯路,但最终我们找到了到达目的地的道路,学到了许多有关在 Bluemix 中调试 Java 应用程序的经验。现在您已看到如何开始将标准的独立 Java 应用程序迁移到 Bluemix。您可采取我们在本系列之前的文章中介绍的相同方法,将您的应用程序绑定到服务,并利用 Bluemix 所提供的不同服务。在未来的教程中,我们将介绍将 Java 应用程序连接到内部部署的数据库。

BLUEMIX SERVICE USED IN THIS TUTORIAL: Liberty for Java 运行时 帮助您轻松地开发、部署和扩展 Java Web 应用程序。

相关主题: Cloud Foundry Bluemix

正文到此结束
Loading...