1. Introduction
1.导言
In this tutorial, we’ll explore ways to run a standard Java application created using Spring Boot as a Docker container. More specifically, we’ll use Liberica JDK on top of Alpaquita Linux to create the Docker image that will run our application.
在本教程中,我们将探讨如何将使用 Spring Boot 创建的标准 Java 应用程序作为 Docker 容器运行。更具体地说,我们将在 Alpaquita Linux 上使用 Liberica JDK 创建将运行应用程序的 Docker 镜像。
Liberica JDK and Alpaquita Linux are part of the product offerings from BellSoft. BellSoft is an organization that has the vision to make Java the preferred language for cloud-native applications. Through their targeted offerings, they promise a better experience at lower costs.
Liberica JDK 和 Alpaquita Linux 是 BellSoft 产品的一部分。BellSoft是一家致力于使 Java 成为云原生应用程序首选语言的组织。通过有针对性的产品,他们承诺以更低的成本提供更好的体验。
2. A Simple Spring Boot Application
2.一个简单的 Spring Boot 应用程序
Let’s begin by creating a straightforward application in Java that we’ll proceed to containerize. We’ll use Spring Boot to create this application. Spring Boot makes it easy to create stand-alone, production-grade Spring-based applications with minimal configurations.
让我们先用 Java 创建一个简单的应用程序,然后将其容器化。我们将使用 Spring Boot 来创建此应用程序。Spring Boot 可让您以最少的配置轻松创建独立的、基于 Spring 的生产级应用程序。
The simplest way to initialize a Spring Boot application is to use the Spring Boot CLI. It lets us create a new project by using start.spring.io right from our favorite command line:
初始化 Spring Boot 应用程序的最简单方法是使用 Spring Boot CLI。通过它,我们可以在自己喜欢的命令行中使用 start.spring.io 创建一个新项目:
$ spring init --build=gradle --dependencies=web spring-bellsoft
Here, we are adding web as a dependency that allows us to build applications with RESTful APIs and Apache Tomcat as the default embedded container. We’ve selected Gradle as the build tool here. However, it chooses Java as the language and many other things as default.
在这里,我们添加了 web 作为依赖项,它允许我们使用 RESTful API 和 Apache Tomcat 作为默认的嵌入式容器来构建应用程序。在这里,我们选择 Gradle 作为构建工具。不过,Gradle 默认选择 Java 作为语言,还选择了许多其他语言。
Then, we can import the generated project into our favorite IDE, like IntelliJ Idea, and start developing the application. As said earlier, we’ll keep this very simple. Hence, we’ll add a simple REST API that takes a number as an input and returns the Fibonacci series equal to or less than that number:
然后,我们可以将生成的项目导入我们最喜欢的集成开发环境,如 IntelliJ Idea,并开始开发应用程序。如前所述,我们将保持非常简单。因此,我们将添加一个简单的 REST API,将一个数字作为输入,并返回等于或小于该数字的斐波纳契数列:
@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;
}
}
Building the application in Gradle is as simple as running the following command, which uses the Gradle wrapper generated before:
在 Gradle 中构建应用程序非常简单,只需运行以下命令即可,其中使用了之前生成的 Gradle 封装器:
./gradlew clean build
The default packaging for the generated project is JAR which implies that the above command on success will result in the final executable JAR created in the output directory “./build/libs“. We can start the application using this JAR file:
生成项目的默认打包方式是 JAR,这意味着上述命令成功执行后,将在输出目录”./build/libs“中创建最终的可执行 JAR。我们可以使用该 JAR 文件启动应用程序:
java -jar ./build/libs/spring-bellsoft-0.0.1-SNAPSHOT.jar
Then, we can call our API and see if it is working fine:
然后,我们就可以调用我们的应用程序接口,看看它是否运行正常:
$ curl http://localhost:8080/api/v1/fibs?input=5
[0,1,1,2,3,5]
This concludes our effort to create a simple application for the rest of the tutorial. We’ll be using this application deployable to containerize the application.
至此,我们为本教程的其余部分创建一个简单应用程序的工作告一段落。我们将使用此应用程序的可部署性来对应用程序进行容器化。
3. Containerizing Our Application
3.将我们的应用程序容器化
A container is a standard unit of software that packages up code and all its dependencies. It’s a form of operating system virtualization that offers a consistent way to deploy applications. Today, it has become the default choice for running any application in cloud environments.
容器是一种标准的软件单元,用于打包代码及其所有依赖项。它是操作系统虚拟化的一种形式,为部署应用程序提供了一种一致的方式。如今,它已成为在云环境中运行任何应用程序的默认选择。
We require a container platform to run our simple application as a container. A container platform, among other things, provides a container engine to create and manage containers. Docker is the most popular platform designed to build, share, and run container applications.
我们需要一个容器平台来将我们的简单应用作为容器运行。容器平台除其他功能外,还提供用于创建和管理容器的容器引擎。Docker 是用于构建、共享和运行容器应用程序的最流行的平台。
The container engine creates a container from the container image. A container image is an immutable static file that includes everything a container needs to run. However, it shares the operating system kernel of the host. Hence, it offers complete isolation but is still lightweight:
容器引擎会根据容器映像创建容器。容器映像是一个不可变的静态文件,其中包含容器运行所需的一切。不过,它共享主机的操作系统内核。因此,它提供了完全的隔离,但仍然是轻量级的:
One of the ways to create a Docker image is to describe the recipe for creating the image as a Dockerfile. Then, we can use the Docker daemon to create an image from the Dockerfile. The original image format from Docker has now become the Open Container Initiative (OCI) Image Specification.
创建 Docker 镜像的方法之一是将创建镜像的配方描述为 Dockerfile。然后,我们可以使用 Docker 守护进程从 Docker 文件创建映像。Docker 的原始映像格式现已成为 Open Container Initiative (OCI) 映像规范。
One of the key advantages of running an application as a container is that it offers a consistent deployment experience across multiple environments. For instance, imagine we deliver our simple application built using Java 17 but deployed in an environment with Java 11 runtime.
以容器形式运行应用程序的主要优势之一是,它能在多个环境中提供一致的部署体验。例如,假设我们交付了使用 Java 17 构建的简单应用程序,但部署在使用 Java 11 运行时的环境中。
To avoid this surprise, container images allow us to package all critical dependencies for our application, like OS binaries/libraries and the Java runtime. By doing so, we can be sure that our application will behave the same, no matter which environment it gets deployed.
为了避免这种意外,容器映像允许我们打包应用程序的所有关键依赖项,如操作系统二进制文件/库和 Java 运行时。通过这样做,我们可以确保无论在哪种环境中部署,应用程序的行为都是一样的。
4. Liberica Runtime Containers
4.Liberica 运行时容器
A container image is composed of multiple layers stacked on each other. Each layer represents a specific modification to the file system. Typically, we begin with a base image that best matches our application’s requirements and build additional layers on top of it.
容器镜像由多个层堆叠而成。每一层都代表对文件系统的特定修改。通常情况下,我们从最符合应用程序要求的基本映像开始,然后在其基础上构建附加层。
BellSoft offers several images highly optimized for running Java applications on cloud-based environments. They are built with the Alpaquita Linux and Liberica JDK. Before using these images, let’s examine the benefits of their BellSoft constituents.
BellSoft 提供了几款针对在基于云的环境中运行 Java 应用程序而高度优化的映像。它们采用 Alpaquita Linux 和 Liberica JDK 构建。在使用这些映像之前,我们先来了解一下其 BellSoft 组成部分的优势。
4.1. Benefits of Alpaquita Linux
4.1.Alpaquita Linux 的优势
Alpaquita Linux is a lightweight operating system based on Alpine Linux. It’s tailor-made for Java and optimized for the deployment of cloud-native applications. It results in a base image size of 3.22 MB and requires a small amount of resources to run.
Alpaquita Linux 是基于 Alpine Linux 的轻量级操作系统。它专为 Java 量身定制,并针对云原生应用程序的部署进行了优化。它的基本映像大小为 3.22 MB,运行时只需少量资源。
Alpaquita Linux comes in two versions, one based on an optimized musl libc and the other on glib libc. Here, libc refers to the standard library for the C programming language, as specified in the ISO C standard. It provides macros, type definitions, and functions for several tasks.
Alpaquita Linux 有两个版本,一个基于优化的 musl libc ,另一个基于 glib libc 。在这里,libc 指的是 ISO C 标准中规定的 C 编程语言标准库。它为多项任务提供宏、类型定义和函数。
Besides being optimized for Java applications, Alpaquita Linux offers several security features for our deployment. These include networking features, custom build options, and process isolation. It also includes kernel hardening like kernel lockdown and kernel module signing.
除了针对 Java 应用程序进行优化外,Alpaquita Linux 还为我们的部署提供了多项安全功能。这些功能包括网络功能、自定义构建选项和进程隔离。它还包括内核锁定和内核模块签名等内核加固功能。
Further, Alpaquita Linux is optimized for deployment as it uses kernel module compression to reduce the size of packages. It delivers a reliable and fast stack to run applications with performance features like kernel optimizations and memory management.
此外,Alpaquita Linux 采用内核模块压缩技术来减小软件包的大小,从而优化了部署。它提供了一个可靠、快速的堆栈,可通过内核优化和内存管理等性能功能运行应用程序。
Alpaquita Linux only packages a small number of operating system components. However, we can install extra modules and additional packages from the Alpaquita APK repository. Most importantly, Alpaquita Linux has a four-year support lifecycle for its LTS versions.
Alpaquita Linux 仅打包了少量操作系统组件。不过,我们可以从 Alpaquita APK 资源库安装额外的模块和附加软件包。最重要的是,Alpaquita Linux 的 LTS 版本支持周期为四年。
4.2. Benefits of Liberica JDK
4.2.Liberica JDK 的优势
Liberica JDK is an open-source Java runtime for modern Java deployments. It comes from BellSoft, a key contributor to the OpenJDK, and promises a single runtime for cloud, server, and desktop use for Java applications. It’s also recommended for Spring-based Java applications.
Liberica JDK是面向现代 Java 部署的开源 Java 运行时。它由 OpenJDK 的主要贡献者 BellSoft 提供,并承诺为 Java 应用程序提供适用于云、服务器和桌面的单一运行时。它还被推荐用于基于 Spring 的 Java 应用程序。
Liberica JDK supports various architectures like x86 64/32 bit, ARM, PowerPC, and SPARC. It also supports several operating systems like Windows, macOS, and most Linux distributions. Moreover, it supports almost all versions of Java in use today.
Liberica JDK 支持各种架构,如 x86 64/32位、ARM、PowerPC 和 SPARC。它还支持多种操作系统,如 Windows、macOS 和大多数 Linux 发行版。此外,它还支持目前使用的几乎所有 Java 版本。
One of the critical advantages of Liberica JDK is that it’s pretty lightweight. The Liberica runtime container based on Alpaquita Linux for Java 17 is less than 70 MB. It promises better performance while reducing traffic, storage, memory consumption, and total costs.
Liberica JDK 的关键优势之一是非常轻量级。基于 Alpaquita Linux for Java 17 的 Liberica 运行时容器不到 70 MB。它承诺提供更好的性能,同时减少流量、存储、内存消耗和总成本。
It also features diverse tools for working with the JDK runtime. There is full-fledged access to tools for monitoring and updation. Further, users can also get access to the Liberica Administration Center (LAC), an enterprise tool for runtime monitoring, license control, and security updates.
它还具有多种工具,可与 JDK 运行时配合使用。用户可以全面访问用于监控和更新的工具。此外,用户还可以访问 Liberica 管理中心(LAC),这是一个用于运行时监控、许可证控制和安全更新的企业工具。
Liberica JDK is TCK-verified for Java SE specifications and thoroughly tested for exposure before every release. Moreover, BellSoft guarantees at least eight years of Liberica JDK lifetime with bug fixes, security patches, and other improvements as needed.
Liberica JDK通过了Java SE规范的TCK验证,并在每次发布前进行了彻底的暴露测试。此外,BellSoft保证 Liberica JDK 的使用寿命至少为八年,并根据需要提供错误修复、安全补丁和其他改进。
5. Creating the Container Image
5.创建容器映像
Now, we are ready to containerize our simple application using Alpaquita Linux and Liberica JDK. The first step is to choose a base image with these dependencies. We can always create our base image, but thankfully, BellSoft maintains several images on the Docker Hub to choose from.
现在,我们已经准备好使用 Alpaquita Linux 和 Liberica JDK 对我们的简单应用程序进行容器化。第一步是选择一个包含这些依赖项的基础镜像。我们可以随时创建自己的基础映像,不过值得庆幸的是,BellSoft 在 Docker Hub 上维护了多个映像供我们选择。
5.1. Choosing a Liberica Runtime Container
5.1.选择 Liberica 运行时容器
These are Alpaquita Linux images with different options of Liberica JDK lite and Liberica JRE to choose from. We can typically identify this from the tag, which may contain one of the following:
这些是 Alpaquita Linux 映像,有 Liberica JDK lite 和 Liberica JRE 的不同选项可供选择。我们通常可以从标签中识别出来,标签可能包含以下内容之一:
- jdk: Alpaquita Linux image with the Liberica JDK Lite version
- jdk-all: packages Liberica JDK that can be used to create a custom runtime with jlink tool
- jre: contains only the Liberica JRE for running Java applications
Here, the tag of the image reveals much other information about the image apart from the version of JDK it contains. Let’s look at the convention for the image tag used by BellSoft:
在这里,除了包含的 JDK 版本外,图像的 标记还揭示了图像的许多其他信息。让我们来看看 BellSoft 使用的图像标记惯例:
[JDK type]-Java version-[slim]-[OS release]-[libc type]-[date]
Here, the different parts of the tag tell a specific aspect of the image and help us choose the right now from many available images:
在这里,标签的不同部分说明了图像的特定方面,帮助我们从众多可用图像中选择合适的图像:
- JDK type: the type of JDK (JDK, jdk-all, and jre, as we’ve seen earlier)
- Java version: the version of Java to which the JDK conforms to
- slim: indicates if the image is a slim one
- OS version: the version of the OS (currently it’s only stream)
- libc type: the type of standard C library (glibc or musl, as we’ve seen earlier)
- date: the release date for the image
5.2. Containerizing Our Application
5.2.将应用程序容器化
Now, we’ve all the information in the image tag to choose the right one. For instance, if we want Java 17 with glibc for our application, we’ve to pick the tag “jdk-17-glibc“.
现在,我们已经掌握了图像标签中的所有信息,可以选择正确的标签。例如,如果我们的应用程序需要 Java 17 with glibc,我们就必须选择”jdk-17-glibc“标签。
Once we’ve chosen the correct base image tag, the next step is to create a Dockerfile to define how we want to create the container image for our application:
一旦我们选择了正确的基础镜像标签,下一步就是创建一个 Dockerfile,以定义如何为我们的应用程序创建容器镜像:
FROM bellsoft/liberica-runtime-container:jdk-17-glibc
VOLUME /tmp
ARG JAR_FILE=build/libs/java-bellsoft-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
This fairly simple Dockerfile states that we wish to begin with the mentioned Liberica runtime container and copy our application fat JAR. We also define the entry point with instructions to run our application once the container is instantiated.
这个相当简单的 Dockerfile 说明,我们希望从提及的 Liberica 运行时容器开始,并复制我们的应用程序胖 JAR。我们还定义了入口点,并说明容器实例化后如何运行我们的应用程序。
We should place this Dockerfile in the root of the application codebase directory. Then, we can use the following command to create the container image in our local repository:
我们应该把这个 Dockerfile 放在应用程序代码库目录的根目录下。然后,我们可以使用以下命令在本地仓库中创建容器镜像:
docker buildx build -t spring-bellsoft .
This would pull the base image from the registry, Docker Hub, by default and create the container image for our application. Then, we can run this image as a container:
默认情况下,这将从注册表 Docker Hub 中提取基础镜像,并为我们的应用程序创建容器镜像。然后,我们就可以将该镜像作为容器运行了:
docker run --name fibonacci -d -p 8080:8080 spring-bellsoft
Please note that we’ve mapped the local port 8080 with the container port 8080. Hence, we can access our application as we did earlier in the tutorial:
请注意,我们已将本地端口 8080 与容器端口 8080 进行了映射。因此,我们可以像教程前面那样访问我们的应用程序:
$ curl http://localhost:8080/api/v1/fibs?input=5
[0,1,1,2,3,5]
This concludes our effort to containerize the simple application we created earlier in the tutorial with Liberica runtime containers published by BellSoft. Of course, it would be interesting to try out more complex applications and other variations of Liberica runtime containers available to us.
至此,我们使用 BellSoft 发布的 Liberica 运行时容器对教程前面创建的简单应用程序进行容器化的工作就结束了。当然,尝试更复杂的应用程序和 Liberica 运行时容器的其他变体将是非常有趣的。
6. Conclusion
6.结论
In this tutorial, we went through the basics of creating a container for a simple Spring Boot-based Java application. We explored the option to choose BellSoft Liberica runtime containers to do so. In the process, we created a simple application and containerized it.
在本教程中,我们学习了为基于 Spring Boot 的简单 Java 应用程序创建容器的基础知识。我们探索了选择 BellSoft Liberica 运行时容器来实现这一目标。在此过程中,我们创建了一个简单的应用程序并将其容器化。
This helped us to understand the benefits of Alpaquita Linux and Liberica JDK, the constituents of the Liberica runtime containers. These are some of the core offerings from BellSoft, which is committed to optimizing Java applications for cloud-based environments.
这有助于我们了解 Alpaquita Linux 和 Liberica JDK(Liberica 运行时容器的组成部分)的优势。这些都是 BellSoft 的一些核心产品,BellSoft 致力于为基于云的环境优化 Java 应用程序。