在 Liberica 运行时容器上运行 Spring Boot 应用

1、简介

在本教程中,我们将了解如何把使用 Spring Boot 创建的 Java 应用作为 Docker 容器运行,具体来说,我们将在 Alpaquita Linux 上使用 Liberica JDK 来创建运行我们应用的 Docker 镜像。

Liberica JDK 和 Alpaquita Linux 是 BellSoft 产品的一部分。BellSoft 的愿景是使 Java 成为云原生应用程序的首选语言。

2、简单的 Spring Boot 应用

先用 Java 创建一个简单的应用,然后将其容器化。通过 Spring Boot,我们只需进行最少的配置,就能轻松创建基于 Spring 的独立生产级应用。

初始化 Spring Boot 应用的最简单方法是使用 Spring Boot CLI。通过它,可以在命令行中使用 start.springboot.io 创建一个新项目:

$ spring init --build=gradle --dependencies=web spring-bellsoft

如上,添加了 web 依赖,以构建 RESTful API,并将 Apache Tomcat 作为默认的嵌入式容器。选择 Gradle 作为构建工具,默认的语言是 Java。

然后,可以将生成的项目导入 IDE(如 IntelliJ Idea),开始开发应用。

添加一个简单的 REST API,接收一个 Integer 参数,并返回等于或小于该数字的斐波纳契数列:

@RestController
public class DemoController {

    @GetMapping("/api/v1/fibs")
    public List<Integer> getFibonacciSeriesBelowGivenInteger(Integer input) {
        List<Integer> result;
        if (input == 0)
            result = List.of(0);
        else {
            int n = 0; int m = 1;
            result = new ArrayList<>(Arrays.asList(n));
            while (m <= input) {
                result.add(m);
                m = n + m; n = m - n;
            }
        }
        return result;
    }
}

在 Gradle 中构建应用非常简单,只需运行以下命令即可:

# 使用了生成的 Gradle Wrapper
./gradlew clean build

生成项目的默认打包方式是 JAR,上述命令成功执行后,将在输出目录 ./build/libs 中创建最终可执行 JAR。

运行该 JAR,启动应用:

java -jar ./build/libs/spring-bellsoft-0.0.1-SNAPSHOT.jar

然后,调用 API,看看它是否运行正常:

$ curl http://localhost:8080/api/v1/fibs?input=5
[0,1,1,2,3,5]

这就是本教程将会使用到的一个超级简单的应用。

3、容器化

容器是一种标准的软件单元,它将代码和所有依赖项打包在一起。它是一种操作系统虚拟化的形式,提供了一种一致的部署应用程序的方式。如今,在云环境中运行任何应用程序时,容器已成为默认选择。

我们需要一个容器平台来将我们的应用作为容器运行。容器平台除其他功能外,还提供用于创建和管理容器的容器引擎。Docker 是最流行的平台,旨在构建、共享和运行容器应用程序。

容器引擎从容器镜像创建容器。容器镜像是一个不可变的静态文件,包含容器运行所需的一切。然而,它共享主机的操作系统内核。因此,它提供了完全的隔离性,但仍然是轻量级的。

Docker 容器栈

创建 Docker 镜像的一种方式是将创建镜像的步骤描述为 Dockerfile。然后,可以使用 Docker 守护进程根据 Dockerfile 创建镜像。Docker 的原始镜像格式现在已成为 开放容器倡议(OCI)镜像规范。

将应用作为容器运行的一个核心的优势是,在多个环境中提供一致的部署体验。例如,假设我们使用 Java 17 构建了一个简单的应用,但需要在一个只有 Java 11 运行时的环境中进行部署。

为了避免这种意外情况,容器镜像允许我们打包应用程序的所有关键依赖,例如操作系统的二进制文件/库和 Java 运行时环境。通过这样做,我们可以确保无论应用程序在哪个环境中部署,它的行为都是一致的。

4、Liberica Runtime 容器

一个容器镜像由多个相互叠加的 “层” 组成。每个层代表对文件系统的特定修改。通常,我们从一个最符合应用要求的基础镜像开始,并在其之上构建额外的层。

BellSoft 提供了几个针对在云环境中运行 Java 应用程序进行高度优化的镜像。它们使用了 Alpaquita Linux 和 Liberica JDK 进行构建。在使用这些镜像之前,让我们来看一下它们的的优点。

4.1、Alpaquita Linux 的优势

Alpaquita Linux 是基于 Alpine Linux 的轻量级操作系统。它专为 Java 量身定制,并针对云原生应用程序的部署进行了优化。它的基本镜像大小为 3.22 MB,运行时只需少量资源。

Alpaquita Linux 有两个版本,一个基于优化的 musl libc,另一个基于 glib libc。这里的 libc 是指 ISO C 标准中规定的 C 语言标准库。它为多项任务提供宏、类型定义和函数。

除了针对 Java 应用程序进行优化外,Alpaquita Linux 还为我们的部署提供了多项安全功能。这些功能包括网络功能、自定义构建选项和进程隔离。它还包括内核锁定和内核模块签名等内核加固功能。

此外,Alpaquita Linux 经过优化以便于部署,它使用内核模块压缩来减小软件包的大小。它提供了可靠且高效的堆栈,具备内核优化和内存管理等性能特性,可用于运行应用程序。

Alpaquita Linux 只打包了少量操作系统组件。不过,我们可以从 Alpaquita APK Repository 中安装额外的模块和附加软件包。最重要的是,Alpaquita Linux 的 LTS 版本支持周期为四年。

4.2、Liberica JDK 的优势

Liberica JDK 是用于现代 Java 部署的开源 Java 运行时。它由 OpenJDK 的主要贡献者 BellSoft 提供,承诺为 Java 应用程序提供适用于云、服务器和桌面的单一运行时。它还推荐用于基于 Spring 的 Java 应用程序。

Liberica JDK 支持各种架构,如 x86 64/32位、ARM、PowerPC 和 SPARC。它还支持多种操作系统,如 Windows、macOS 和大多数 Linux 发行版。此外,它还支持目前使用的几乎所有 Java 版本。

Liberica JDK 的关键优势之一是非常轻量级。基于 Alpaquita Linux for Java 17 的 Liberica 运行时容器不到 70 MB。它承诺在降低流量、存储、内存消耗和总成本的同时提供更好的性能。

它还具有多种工具,可与 JDK 运行时配合使用。用户可以访问用于监控和更新的工具。此外,用户还可以访问 Liberica 管理中心(LAC),这是一个用于运行时监控、许可证控制和安全更新的企业工具。

Liberica JDK 已通过 Java SE 规范的 TCK 验证,并在每个发布之前经过全面测试以确保其稳定性。此外,BellSoft 保证提供至少八年的 Liberica JDK 生命周期支持,包括错误修复、安全补丁和其他必要的改进。

5、创建容器镜像

现在,我们准备使用 Alpaquita Linux 和 Liberica JDK 对我们的应用进行容器化。第一步是选择一个包含这些依赖项的基础镜像。虽然,我们可以创建自己的基础镜像,但 BellSoft 在 Docker Hub 上维护了多个镜像 供我们选择。

5.1、选择 Liberica 运行时容器

Alpaquita Linux 镜像,提供了不同选项的 Liberica JDK Lite 和 Liberica JRE 供选择。通常,我们可以通过标签来识别,标签可能包含以下之一:

  • jdk:带有 Liberica JDK Lite 版本的 Alpaquita Linux 镜像
  • jdk-all:Liberica JDK 包,可用于使用 jlink 工具创建自定义运行时
  • jre:仅包含用于运行 Java 应用的 Liberica JRE

镜像的标签除了包含 JDK 版本之外,还有关于镜像的其他信息。让我们来看一下 BellSoft 使用的镜像标签约定:

[JDK type]-Java version-[slim]-[OS release]-[libc type]-[date]

标签的不同部分告诉我们镜像的特定方面,用于帮助我们从众多可用的镜像中选择合适的镜像:

  • JDK type:JDK 的类型(JDK、jdk-all 和 jre,如前所述)
  • Java version:JDK 所符合的 Java 版本
  • slim:表示镜像是否是精简版的
  • OS version:操作系统的版本(目前只有 stream
  • libc type:标准 C 语言库的类型(如前所述,是 glibc 还是 musl)
  • date:镜像的发布日期

5.2、将应用容器化

现在,选择一个合适的镜像。例如,如果我们想要使用带有 glibc 的 Java 17 作为我们的应用程序,我们需要选择标签为 “jdk-17-glibc” 的镜像。

选择好了基础镜像标签,下一步就是创建一个 Dockerfile,以定义如何为我们的应用创建容器镜像:

FROM bellsoft/liberica-runtime-container:jdk-17-glibc
VOLUME /tmp
ARG JAR_FILE=build/libs/java-bellsoft-0.0.1-SNAPSHOT.jar
 ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

这个相当简单的 Dockerfile 表明我们希望从 Liberica 运行时容器和我们的应用程序 Fat JAR 开始。还定义了 ENTRYPOINT,并提供了在容器启动后运行我们的应用程序的指令。

我们应该把这个 Dockerfile 放在应用程序代码库目录的根目录下。然后,可以使用以下命令在本地仓库中创建容器镜像:

docker buildx build -t spring-bellsoft .

默认情况下,这将从注册中心 Docker Hub 拉取基础镜像,并为我们的应用创建容器镜像。然后,我们可以将该镜像作为容器运行:

docker run --name fibonacci -d -p 8080:8080 spring-bellsoft

注意,我们已将本地端口 8080 与容器端口 8080 进行了映射。因此,我们可以像本文前面那样访问我们的应用:

$ curl http://localhost:8080/api/v1/fibs?input=5 
[0,1,1,2,3,5]

至此,我们成功地使用 BellSoft 发布的 Liberica 运行时容器对本文前面创建的应用进行容器化。

6、总结

本文介绍了为 Spring Boot 应用创建 BellSoft Liberica 运行时容器的基础知识,还了解了作为 Liberica 运行时容器组成部分的 Alpaquita Linux 和 Liberica JDK 的优势。


参考:https://www.baeldung.com/spring-docker-liberica