Capsule:开源的 JVM 应用部署工具

现实世界中,应用程序部署过程可能没有想象中的那么简单。应用程序其实非常「敏感」,在部署过程中,它会发现自己身处一个陌生的环境中,并且在与不同硬件、不同基础设施软件,以及陌生的邻居(应用程序)行交互。如果期望应用程序正常地运行,编码和部署过程都是重中之重。两者之间的平衡常常依赖于程序的编写语言、程序构成的运行时和工具,因此,不同的技术栈可能需要不同的部署工具。

但 JVM 应用程序对环境的要求非常少——只需一个 JVM 和一个内核,然而意想不到是,目前为止尚不存在一个通用的 JVM 应用部署工具/机制。Fat JARs 并不总奏效,而且它们需要平台特定的脚本。最近有人使用 Docker 来部署 Java 应用,事实上 Docker 并不适用于这种任务:它的主要目的之一是提供通用的应用可移植性(类似 JVM 应用已经具备的特性),同时它也需要下载、部署并管理各种 full-OS 镜像和存 repositories。作为运行时不可知工具,Docker 也无法利用 JVMs 的优势。

当下,经过一年的发展,Capsule 1.0 正式发布——一个简单、健壮且灵活的 JVM 应用部署工具。Capsule 迎合 JVM 应用的独特优势和需求,因此这里有理由相信这是最简单、最强大的 JVM 应用部署方式,不管是用于一个桌面应用、microservice 或复杂的 Web 应用。Capsule 不仅适用于 Java 应用程序,还能应用于所有 JVM 语言,从 Jruby、Jython 和 Groovy,到 Kotlin、Clojure 和 Scala,再到 Frege 和 OCaml-Java。如果你在写 JVM 程序,给 Capsule 一个机会。

你可以这样来理解 capsule,将它当作 steroids 上的1个 fat JAR(在允许本地库的同时也不会干扰到依赖项)与1个声明式启动脚本的整合;另一个理解方式是,将其当作部署阶段的构建工具。正如构建管理工具一样, Capsule 从构建到应用发布的各个环节都有全方位的管理。

Capsule 在设计时一直遵循以下原则:

  • 打包应该是轻量、可移植和便捷的。无论多么复杂,不管有多少 JAR 文件组成,或者有多少脚本语言的源文件还是本地库,Capsule 都可以包装任何 JVM 应用到一个名为 Capsule 的可执行 JAR,并且可以在任何平台上运行。Capsule 可以直接包含应用的所有依赖项,或简单地声明部分或者全部,一旦发布将会被完整的下载。这就是 fat JAR 的工作方式。如果愿意, capsules 本身也可以置于 Maven repositories,在发布时进行下载。
  • 安装对主机系统的影响最小,并对更新选择性支持。在 capsule 首次安装时,其正常运行需要依赖在1个临时目录中生成的一些文件,随后用户可以在任何时刻删除这些文件,不会对 capsule 产生任何不良影响。capsule 可以选择性地支持更新——不管是应用或者是其依赖关系——当启动时会自动下载。这些依赖关系——可以是语言运行时或者是 Web 容器——也可以被其他 capsule 共享。
  • 发布必须是确定和灵活的,可能是安全的且有选择地限制。发布一个 capsule 不需要启动脚本。Capsules 查找请求的 JVM 版本、设置 classpath、必要的 agents 并设置 JVM flags。Capsules 在启动时也可以创建自己的容器(来限制资源使用,或使用已知的端口以避免对其他项目形成干扰),同时 JVM 应用可以在无特权的容器下运行,这些容器是安全的。另外,安全性由 JVM 提供的安全机制保证。此外, capsules 只需要一个内核和一个 JVM ——甚至不需要 shell,他们便能在 JVM microkernels 上运行,比如 OSv。通过 caplets 和组件定制 capsule 的行为,所有这些功能都是完全可编程、可组合的。

当工具和标准已经存在时,不用再重造车轮。Capsule 是用 Java 编写的,并可以通过 Java 扩展。它遵循 JVM 生态系统,而不是重造车轮,仅使用现有的工具和标准。capsule 打包在一个可执行 JAR,并将所有元数据存储为简单的 JAR-manifest attributes 中;并且可以根据需要,从 Maven repositories 中下载全部或者部分,并通过 Maven、Gradle 和 Leiningen 这些流行的 JVM 工具构建。Capsule 本身是一个简单的 Maven 依赖,就像所有的构建工具插件,不需要再安装其他新工具。

通过 Caplets 实现的 Capsule 魔法

Capsule 之所以能保持简单还能提供这些功能主要归功于 caplets,以模块化定制 Capsule 行为。Caplets 可以嵌入到1个 capsule,或者单独进行包装并使用命令行包装和修改现有 capsule 行为。

Capsule 的第一个 caplet 是 Maven caplet,允许开发者在 manifest attributes 中声明部分或全部的应用依赖关系,而不用嵌入到 capsule JAR 里。虽然这对许多应用来说并不必要,不妨通过以下两个用例来深入了解 Capsule 的潜力。

首先是一个简单的 Hello World servlet。建成后,它将创建一个标准的 WAR 文件并部署到任何 servlet 容器。仔细观察后发现,WAR 的确有点特别。其内容是:

 247 META-INF/MANIFEST.MF 
    1124 WEB-INF/classes/co/paralleluniverse/examples/HelloWorldServlet.class 
    653 WEB-INF/web.xml 
    161596 Capsule.class 
    1467463 capsule-maven-1.0.jar

如你所见, WAR 包含 Capsule 类,这意味着它是一个capsule,也是嵌入式 JAR,而 capsule-maven-1.0.jar是 Maven caplet。JAR manifest 是这样的:

Manifest-Version: 1.0
Main-Class: Capsule
Premain-Class: Capsule
Caplets: co.paralleluniverse:capsule-maven:1.0
Application: org.eclipse.jetty:jetty-runner:9.3.3.v20150827
Allow-Snapshots: true
Min-Java-Version: 1.7.0
Args: $CAPSULE_JAR

取代部署 WAR 到 servlet 容器,你可以直接执行 java -jar build/libs/capsule-runnable-war.war (或者,甚至简单的./capsule-runnable-war.war,如果 capsule是「真正可执行」——见用户文档的指令),它会自动下载 Jetty,并用 Jetty 来启动 servlet。Jetty 工件将被缓存,并可以共享到其他需要的 caplets中。

另一个例子使用 JavaScript,Avatar 项目在 JVM 上实现 Node.js。capsule JAR 包含了 JavaScript 源、 Capsule 类和 Maven caplet:

608 META-INF/MANIFEST.MF
    161596 Capsule.class
    1467463 capsule-maven-1.0.jar
    266 app.js

当 capsule 发布,Avatar 运行时——包括针对本地操作系统的本地库,将从 Maven repository 下载到本地并缓存,并与其他 Avatar capsules 共享。

其他 caplets 将包含:一个守护进程 caplet, 作为 Unix 或 Windows 守护进程来发布 capsule;一个安全 caplet,会在 Java 沙箱(通过安全策略定义)内启动 capsule;一个 desktop caplet,会将包含了一个 GUI 应用程序的 capsule 转化为一个 Windows、Mac 或 Linux 的本地可执行程序;一个容器 caplet,在一个或多个容器内运行 capsule。

为 Capsules 设计的轻量级容器

容器对沙箱应用来说是一个有效方式,可以简化部署和巩固服务器,所以对任何的软件堆栈而言,它们都非常有利于 dev-ops 和安全。然而,由于 JVM 应用只有最小的环境需求 (即一个内核和一个 JVM),它们通常是可移植的,使用一个像 Docker 的容器解决方案无疑是浪费时间和空间。另一方面,shield caplet 创建了一个轻量级容器,无需创建大图像。

例如,可以通过简单地桥接网络在1个容器中方便地运行 quasar-stocks Web 应用。

java -jar capsule-shield-0.1.0.jar quasar-stocks-thin.jar

随后就可以轻松地检索程序所运行的容器IP地址:

lxc-attach -P ~/.capsule/apps/quasarstocks.Application_0.1.0-SNAPSHOT/capsule-shield/ -n lxc -- /sbin/ifconfig

当一切如预期那样正常工作,无需任何复杂的操作,就可以在最终部署的服务器上(可能是一个守护进程)发布相同的命令来配置端口转发使服务公共可用,并通过沙箱保证了应用程序的强安全性。

现在

是时间打开 capsule.io 并启动 capsules 了!

  1. 它们需要跟踪以避免冲突,甚至这样还不够,因为它们不支持本地库。
  2. 它们可能需要不可移植的发布脚本,以便于在操作系统 shell 命令下执行,并选择正确的 JRE 版本、设置类路径、代理和 JVM 参数。
  3. 所有平台都支持 JVM,必要的脚本和本地构件可能也一样需要。
  4. 可能需要更长的启动时间,比如依赖项需要重新下载。
  5. shield caplet 使用 LXC 将 capsule 放于容器内。


相关文章

发表评论

Comment form

(*) 表示必填项

还没有评论。

跳到底部
返回顶部