Building a Native Executable
本指南涵盖:
This guide covers:
-
Compiling the application to a native executable
-
Packaging the native executable in a container
-
Debugging native executable
本指南内容是基于 Getting Started Guide 中开发的应用程序。
This guide takes as input the application developed in the Getting Started Guide.
Prerequisites
include::{includes}/prerequisites.adoc[]* working C development environment* Getting Started Guide 中开发的应用程序代码。
Unresolved directive in building-native-image.adoc - include::{includes}/prerequisites.adoc[] * A configuring-c-development * The code of the application developed in the Getting Started Guide.
Supporting native compilation in C
拥有一个可工作的 C 开发环境意味着什么? What does having a working C developer environment mean?
# dnf (rpm-based) sudo dnf install gcc glibc-devel zlib-devel libstdc++-static # Debian-based distributions: sudo apt-get install build-essential libz-dev zlib1g-dev
xcode-select --install
|
Background
构建本机可执行文件需要使用 GraalVM 的发行版。发行版有三种:Oracle GraalVM 社区版 (CE)、Oracle GraalVM 企业版 (EE) 和 Mandrel。Oracle 和 Mandrel 发行版之间的区别如下:
Building a native executable requires using a distribution of GraalVM. There are three distributions: Oracle GraalVM Community Edition (CE), Oracle GraalVM Enterprise Edition (EE) and Mandrel. The differences between the Oracle and Mandrel distributions are as follows:
-
Mandrel is a downstream distribution of the Oracle GraalVM CE. Mandrel’s main goal is to provide a way to build native executables specifically designed to support Quarkus.
-
Mandrel releases are built from a code base derived from the upstream Oracle GraalVM CE code base, with only minor changes but some significant exclusions that are not necessary for Quarkus native apps. They support the same capabilities to build native executables as Oracle GraalVM CE, with no significant changes to functionality. Notably, they do not include support for polyglot programming. The reason for these exclusions is to provide a better level of support for the majority of Quarkus users. These exclusions also mean Mandrel offers a considerable reduction in its distribution size when compared with Oracle GraalVM CE/EE.
-
Mandrel is built slightly differently to Oracle GraalVM CE, using the standard OpenJDK project. This means that it does not profit from a few small enhancements that Oracle have added to the version of OpenJDK used to build their own GraalVM downloads. These enhancements are omitted because upstream OpenJDK does not manage them, and cannot vouch for. This is particularly important when it comes to conformance and security.
-
Mandrel is recommended for building native executables that target Linux containerized environments. This means that Mandrel users are encouraged to use containers to build their native executables. If you are building native executables for macOS, you should consider using Oracle GraalVM instead, because Mandrel does not currently target this platform. Building native executables directly on bare metal Linux or Windows is possible, with details available in the Mandrel README and Mandrel releases.
Configuring GraalVM
仅在针对非 Linux 操作系统生成原生可执行文件时才需要此步骤。对于针对 Linux 生成原生可执行文件,你可以选择跳过此部分,而 use a builder image。 This step is only required for generating native executables targeting non-Linux operating systems. For generating native executables targeting Linux, you can optionally skip this section and container-runtime instead. |
如果你无法安装 GraalVM,则可以使用多阶段 Docker 构建在嵌入 GraalVM 的 Docker 容器内运行 Maven。the end of this guide 中对此进行了说明。 If you cannot install GraalVM, you can use a multi-stage Docker build to run Maven inside a Docker container that embeds GraalVM. There is an explanation of how to do this at multistage-docker. |
需要 GraalVM {graalvm-version}。
GraalVM {graalvm-version} is required.
-
Install GraalVM if you haven’t already. You have a few options for this:
-
Download the appropriate archive from [role="bare"]https://github.com/graalvm/mandrel/releases or [role="bare"]https://github.com/graalvm/graalvm-ce-builds/releases, and unpack it like you would any other JDK.
-
Use platform-specific installer tools like sdkman, homebrew, or scoop. We recommend the community edition of GraalVM. For example, install it with
sdk install java 21-graalce
.
-
-
Configure the runtime environment. Set
GRAALVM_HOME
environment variable to the GraalVM installation directory, for example:[source, bash]
export GRAALVM_HOME=$HOME/Development/mandrel/
在 macOS 上(Mandrel 不支持),将变量指向 Home
子目录:
On macOS (not supported by Mandrel), point the variable to the Home
sub-directory:
export GRAALVM_HOME=$HOME/Development/graalvm/Contents/Home/
在 Windows 上,您需要通过控制面板进行设置环境变量。
On Windows, you will have to go through the Control Panel to set your environment variables.
通过 Scoop 安装将自动完成上述操作。 Installing via scoop will do this for you. |
-
(Optional) Set the
JAVA_HOME
environment variable to the GraalVM installation directory.[source, bash]
export JAVA_HOME=${GRAALVM_HOME}
-
(Optional) Add the GraalVM
bin
directory to the path[source, bash]
export PATH=${GRAALVM_HOME}/bin:$PATH
Issues using GraalVM with macOS
正如 GraalVM issue 中所述,GraalVM 二进制文件尚未对 macOS 进行公证。这意味着在使用 GraalVM binaries are not (yet) notarized for macOS as reported in this GraalVM issue. This means that you may see the following error when using
作为一种变通办法,请使用以下命令递归删除 GraalVM 安装目录中的 Use the following command to recursively delete the
|
Solution
我们建议您按照下一章节中的说明逐步打包应用程序。不过,您可以直接转至完成的示例。
We recommend that you follow the instructions in the next sections and package the application step by step. However, you can go right to the completed example.
克隆 Git 存储库: git clone {quickstarts-clone-url}
,或下载 {quickstarts-archive-url}[存档]。
Clone the Git repository: git clone {quickstarts-clone-url}
, or download an {quickstarts-archive-url}[archive].
该解决方案位于 getting-started
目录中。
The solution is located in the getting-started
directory.
Producing a native executable
我们应用程序的本机可执行文件将包含应用程序代码、必需的库、Java API 以及精简版的 VM。较小的 VM 基础可缩短应用程序的启动时间,并生成最小的磁盘占用。
The native executable for our application will contain the application code, required libraries, Java APIs, and a reduced version of a VM. The smaller VM base improves the startup time of the application and produces a minimal disk footprint.
如果您已从前一个教程生成了应用程序,您可以在 pom.xml
中找到以下 Maven 配置文件部分:
If you have generated the application from the previous tutorial, you can find in the pom.xml
the following Maven profile section:
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>
</profile>
</profiles>
你可以使用 You can provide custom options for the 另一个可能性是在你的 Another possibility is to include the 你可以在下面的 Configuring the Native Executable 部分中找到有关如何配置原生镜像构建过程的更多信息。 You can find more information about how to configure the native image building process in the Configuring the Native Executable section below. |
我们使用一个配置文件是因为,你很快就会看到,打包原生可执行文件需要 few 分钟。你可以直接将 -Dquarkus.native.enabled=true 作为命令行上的一个属性传递,但是最好使用一个配置文件,因为这允许原生镜像测试也可以运行。
We use a profile because, you will see very soon, packaging the native executable takes a few minutes. You could just pass -Dquarkus.native.enabled=true as a property on the command line, however it is better to use a profile as this allows native image tests to also be run.
使用以下命令创建本机可执行文件:
Create a native executable using:
Unresolved directive in building-native-image.adoc - include::{includes}/devtools/build-native.adoc[]
Issues with packaging on Windows
Microsoft Visual Studio 的本机工具必须在打包之前初始化。你可以通过启动随 Visual Studio 构建工具安装的 The Microsoft Native Tools for Visual Studio must first be initialized before packaging.
You can do this by starting the 另一种解决方案是编写脚本为你执行此操作: Another solution is to write a script to do this for you:
|
除了常规文件外,该构建还生成了 target/getting-started-1.0.0-SNAPSHOT-runner
。你可以使用以下命令运行它:./target/getting-started-1.0.0-SNAPSHOT-runner
。
In addition to the regular files, the build also produces target/getting-started-1.0.0-SNAPSHOT-runner
.
You can run it using: ./target/getting-started-1.0.0-SNAPSHOT-runner
.
Java preview features
依赖于预览功能的 Java 代码需要特别注意。要生成原生可执行文件,这意味着 Java code that relies on preview features requires special attention.
To produce a native executable, this means that the |
Build fully static native executables
完全静态的原生可执行文件支持是实验性的。
Fully static native executables support is experimental.
在 Linux 上,可以打包一个不依赖于任何系统共享库的原生可执行文件。在 native-image
调用中,需要满足 some system requirements 并使用其他构建参数,最小参数为 -Dquarkus.native.additional-build-args="--static","--libc=musl"
。
On Linux it’s possible to package a native executable that doesn’t depend on any system shared library.
There are some system requirements to be fulfilled and additional build arguments to be used along with the native-image
invocation, a minimum is -Dquarkus.native.additional-build-args="--static","--libc=musl"
.
编译完全静态的二进制文件是通过静态链接 musl 而不是 glibc
来完成的,并且不应在没有严格测试的情况下在生产中使用。
Compiling fully static binaries is done by statically linking musl instead of glibc
and should not be used in production without rigorous testing.
Testing the native executable
生成原生可执行文件可能会导致一些问题,因此针对在原生文件中运行的应用程序运行一些测试也是一个好主意。原因在 Testing Guide 中进行了说明。
Producing a native executable can lead to a few issues, and so it’s also a good idea to run some tests against the application running in the native file. The reasoning is explained in the Testing Guide.
若要查看针对原生可执行文件运行的 GreetingResourceIT
,请使用 ./mvnw verify -Dnative
:
To see the GreetingResourceIT
run against the native executable, use ./mvnw verify -Dnative
:
$ ./mvnw verify -Dnative
...
Finished generating 'getting-started-1.0.0-SNAPSHOT-runner' in 22.0s.
[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildRunner] docker run --env LANG=C --rm --user 1000:1000 -v /home/zakkak/code/quarkus-quickstarts/getting-started/target/getting-started-1.0.0-SNAPSHOT-native-image-source-jar:/project:z --entrypoint /bin/bash quay.io/quarkus/ubi-quarkus-mandrel-builder-image:{mandrel-flavor} -c objcopy --strip-debug getting-started-1.0.0-SNAPSHOT-runner
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 70686ms
[INFO]
[INFO] --- maven-failsafe-plugin:3.0.0-M7:integration-test (default) @ getting-started ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.getting.started.GreetingResourceIT
Executing "/home/zakkak/code/quarkus-quickstarts/getting-started/target/getting-started-1.0.0-SNAPSHOT-runner -Dquarkus.http.port=8081 -Dquarkus.http.ssl-port=8444 -Dtest.url=http://localhost:8081 -Dquarkus.log.file.path=/home/zakkak/code/quarkus-quickstarts/getting-started/target/quarkus.log -Dquarkus.log.file.enable=true -Dquarkus.log.category."io.quarkus".level=INFO"
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-05-05 10:55:52,068 INFO [io.quarkus] (main) getting-started 1.0.0-SNAPSHOT native (powered by Quarkus 3.0.2.Final) started in 0.009s. Listening on: http://0.0.0.0:8081
2023-05-05 10:55:52,069 INFO [io.quarkus] (main) Profile prod activated.
2023-05-05 10:55:52,069 INFO [io.quarkus] (main) Installed features: [cdi, rest, smallrye-context-propagation, vertx]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.99 s - in org.acme.getting.started.GreetingResourceIT
...
默认情况下,Quarkus 会等待 60 秒,让原生镜像在自动使原生测试失败之前启动。此持续时间可通过 By default, Quarkus waits for 60 seconds for the native image to start before automatically failing the native tests. This
duration can be changed using the |
此过程以前使用 @NativeImageTest
注释完成。 @NativeImageTest
已被 @QuarkusIntegrationTest
取而代之,它提供了 @NativeImageTest
的测试功能的超集。有关 @QuarkusIntegrationTest
的更多信息可在 Testing Guide 中找到。
This procedure was formerly accomplished using the @NativeImageTest
annotation. @NativeImageTest
was replaced by @QuarkusIntegrationTest
which provides a superset of the testing
capabilities of @NativeImageTest
. More information about @QuarkusIntegrationTest
can be found in the Testing Guide.
Profiles
默认情况下,集成测试既使用 build 又使用 run 原生可执行文件,并使用 prod
配置文件。
By default, integration tests both build and run the native executable using the prod
profile.
你可以在测试过程中使用 quarkus.test.native-image-profile
属性来覆盖可执行文件的配置文件 runs。通过将其添加到 application.properties
中或附加到命令行中:./mvnw verify -Dnative -Dquarkus.test.native-image-profile=test
。你的 %test.
前缀属性将在测试运行时使用。
You can override the profile the executable runs with during the test using the quarkus.test.native-image-profile
property.
Either by adding it to application.properties
or by appending it to the command line:
./mvnw verify -Dnative -Dquarkus.test.native-image-profile=test
.
Your %test.
prefixed properties will be used at the test runtime.
你可以在 built 和 runs 中覆盖可执行文件的配置文件,并使用 quarkus.profile=test
属性,例如 ./mvnw clean verify -Dnative -Dquarkus.profile=test
。如果有一些特定的需要处理的测试资源,例如将测试数据导入数据库,则这可能派得上用场。
You can override the profile the executable is built with and runs with using the quarkus.profile=test
property, e.g.
./mvnw clean verify -Dnative -Dquarkus.profile=test
. This might come handy if there are test specific resources to be processed,
such as importing test data into the database.
quarkus.native.resources.includes=version.txt
%test.quarkus.native.resources.includes=version.txt,import-dev.sql
%test.quarkus.hibernate-orm.database.generation=drop-and-create
%test.quarkus.hibernate-orm.sql-load-script=import-dev.sql
通过 application.properties
中的前述示例,你的 Hibernate ORM 管理的数据库将在 JVM 模式测试运行期间和原生模式测试运行期间用测试数据填充。生产可执行文件将仅包含 version.txt
资源,不会有冗余的测试数据。
With the aforementioned example in your application.properties
, your Hibernate ORM managed database will be populated with test
data both during the JVM mode test run and during the native mode test run. The production
executable will contain only the version.txt
resource, no superfluous test data.
使用 -Dquarkus.profile=test
构建的可执行文件不适合进行生产部署。它包含你的测试资源文件和设置。完成测试后,必须使用默认的 prod
配置文件重新构建可执行文件。
The executable built with -Dquarkus.profile=test
is not suitable for production deployment.
It contains your test resources files and settings. Once the testing is done, the executable would have to be built again,
using the default, prod
profile.
或者,如果你需要在针对使用 prod
配置文件构建的原生可执行文件运行测试时指定特定的属性,一种选择是将这些属性放在文件 src/test/resources/application-nativeit.yaml
中,并使用 QUARKUS_CONFIG_LOCATIONS
环境变量从 failsafe
插件配置中引用它。例如:
Alternatively, if you need to specify specific properties when running tests against the native executable
built using the prod
profile, an option is to put those properties in file src/test/resources/application-nativeit.yaml
, and refer to it from the failsafe
plugin configuration using the QUARKUS_CONFIG_LOCATIONS
environment variable. For instance:
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
<environmentVariables>
<QUARKUS_CONFIG_LOCATIONS>./src/test/resources/application-nativeit.yaml</QUARKUS_CONFIG_LOCATIONS>
</environmentVariables>
</configuration>
</execution>
</executions>
</plugin>
Java preview features
Java preview features
依赖于预览功能的 Java 代码需要特别注意。要测试原生可执行文件,这意味着需要将 Java code that relies on preview features requires special attention.
To test a native executable, this means that the |
Excluding tests when running as a native executable
以这种方式运行测试时,唯一真正以原生方式运行的是你的应用程序端点,你只能通过 HTTP 调用对其进行测试。你的测试代码实际上并没有以原生方式运行,因此,如果你正在测试不调用你的 HTTP 端点的代码,则将其作为原生测试的一部分运行可能不是一个好主意。
When running tests this way, the only things that actually run natively are your application endpoints, which you can only test via HTTP calls. Your test code does not actually run natively, so if you are testing code that does not call your HTTP endpoints, it’s probably not a good idea to run them as part of native tests.
如果你像我们上面建议的那样在 JVM 和原生执行之间共享你的测试类,你可以使用 @DisabledOnIntegrationTest
注释标记某些测试,以便在针对原生镜像进行测试时跳过这些测试。
If you share your test class between JVM and native executions like we advise above, you can mark certain tests
with the @DisabledOnIntegrationTest
annotation in order to skip them when testing against a native image.
使用 Using |
Testing an existing native executable
也可以针对已经构建的原生可执行文件重新运行测试。要执行此操作,请运行 ./mvnw test-compile failsafe:integration-test -Dnative
。这将发现现有的原生镜像,并使用 failsafe 针对它运行测试。
It is also possible to re-run the tests against a native executable that has already been built. To do this run
./mvnw test-compile failsafe:integration-test -Dnative
. This will discover the existing native image and run the tests against it using failsafe.
如果进程由于某种原因找不到原生镜像,或者你想要测试不再位于目标目录中的原生镜像,则可以使用 -Dnative.image.path=
系统属性指定可执行文件。
If the process cannot find the native image for some reason, or you want to test a native image that is no longer in the
target directory you can specify the executable with the -Dnative.image.path=
system property.
Creating a Linux executable without GraalVM installed
在继续之前,请确保拥有一个可正常工作的容器运行时(Docker、podman)环境。如果你在 Windows 上使用 Docker,则应在 Docker Desktop 文件共享设置中共享你的项目的驱动器,并重启 Docker Desktop。
Before going further, be sure to have a working container runtime (Docker, podman) environment. If you use Docker on Windows you should share your project’s drive at Docker Desktop file share settings and restart Docker Desktop.
通常,人们只需要为他们的 Quarkus 应用程序创建一个原生 Linux 可执行文件(例如为了在容器化环境中运行),并且希望避免安装适当的 GraalVM 版本来完成此任务(例如,在 CI 环境中,尽可能少地安装软件是惯例)。
Quite often one only needs to create a native Linux executable for their Quarkus application (for example in order to run in a containerized environment) and would like to avoid the trouble of installing the proper GraalVM version in order to accomplish this task (for example, in CI environments it’s common practice to install as little software as possible).
为此,Quarkus 提供了一种非常便捷的方法来创建原生 Linux 可执行文件,方法是利用容器运行时,例如 Docker 或 podman。完成该任务最简单的方法是执行:
To this end, Quarkus provides a very convenient way of creating a native Linux executable by leveraging a container runtime such as Docker or podman. The easiest way of accomplishing this task is to execute:
Unresolved directive in building-native-image.adoc - include::{includes}/devtools/build-native-container.adoc[]
默认情况下,Quarkus 会自动检测容器运行时。如果你想显式选择容器运行时,你可以使用: By default, Quarkus automatically detects the container runtime. If you want to explicitly select the container runtime, you can do it with: 对于 Docker: For Docker: include::{includes}/devtools/build-native-container-parameters.adoc[]:!build-additional-parameters: Unresolved directive in building-native-image.adoc - include::{includes}/devtools/build-native-container-parameters.adoc[] :!build-additional-parameters: 对于 podman: For podman: include::{includes}/devtools/build-native-container-parameters.adoc[]:!build-additional-parameters: Unresolved directive in building-native-image.adoc - include::{includes}/devtools/build-native-container-parameters.adoc[] :!build-additional-parameters: 这些是常规的 Quarkus 配置属性,因此如果你总是想在容器中构建,建议将它们添加到 These are regular Quarkus config properties, so if you always want to build in a container
it is recommended you add these to your |
如果您在尝试使用容器构建创建本机可执行文件时看到应用程序 JAR 的以下无效路径错误,即使 JAR 已成功构建,则您很可能正在对容器运行时使用远程守护程序。 If you see the following invalid path error for your application JAR when trying to create a native executable using a container build, even though your JAR was built successfully, you’re most likely using a remote daemon for your container runtime. Error: Invalid Path entry getting-started-1.0.0-SNAPSHOT-runner.jar Caused by: java.nio.file.NoSuchFileException: /project/getting-started-1.0.0-SNAPSHOT-runner.jar 在这种情况下,使用 In this case, use the parameter 出现这种情况的原因在于,通过 The reason for this is that the local build driver invoked through |
如果要使用 GraalVM 而非 Mandrel 进行构建,则需要另外传递自定义构建器映像参数: Building with GraalVM instead of Mandrel requires a custom builder image parameter to be passed additionally: include::{includes}/devtools/build-native-container-parameters.adoc[]:!build-additional-parameters: Unresolved directive in building-native-image.adoc - include::{includes}/devtools/build-native-container-parameters.adoc[] :!build-additional-parameters: 请注意,上述命令指向浮动标签。强烈建议使用浮动标签,以便使构建器映像保持最新并安全。如果您必须,可以硬编码为特定标签(参见 here 以获取可用标签),但请注意,您将不会通过这种方式获得安全更新,并且它不受支持。 Please note that the above command points to a floating tag. It is highly recommended to use the floating tag, so that your builder image remains up-to-date and secure. If you absolutely must, you may hard-code to a specific tag (see here for available tags), but be aware that you won’t get security updates that way and it’s unsupported. |
Creating a container
Using the container-image extensions
到目前为止,创建 Quarkus 应用程序容器映像的简单方法是利用容器映像扩展之一。
By far the easiest way to create a container-image from your Quarkus application is to leverage one of the container-image extensions.
如果其中一个扩展程序存在,则为原生可执行文件创建一个容器映像本质上是执行以下命令的问题:
If one of those extensions is present, then creating a container image for the native executable is essentially a matter of executing a single command:
./mvnw package -Dnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true
-
quarkus.native.container-build=true
allows for creating a Linux executable without GraalVM being installed (and is only necessary if you don’t have GraalVM installed locally or your local operating system is not Linux)
如果您正在运行远程 Docker 守护程序,您需要使用 If you’re running a remote Docker daemon, you need to replace 有关更多详细信息,请参阅 Creating a Linux executable without GraalVM installed 。 See tip-quarkus-native-remote-container-build for more details. |
-
quarkus.container-image.build=true
instructs Quarkus to create a container-image using the final application artifact (which is the native executable in this case)
更多详情,请参阅 Container Image guide。
See the Container Image guide for more details.
Manually using the micro base image
你可以使用 Quarkus Maven 插件生成的 JAR,在容器中运行应用程序。然而,本节重点介绍如何使用生成的本地可执行文件创建容器镜像。
You can run the application in a container using the JAR produced by the Quarkus Maven Plugin. However, in this section we focus on creating a container image using the produced native executable.
使用本地 GraalVM 安装时,本地可执行文件面向本地操作系统(Linux、macOS、Windows 等)。然而,由于容器可能不会使用与操作系统生成的相同的 executable 格式,我们将会指示 Maven 构建通过利用容器运行时来生成一个可执行文件(如 this section 中描述的):
When using a local GraalVM installation, the native executable targets your local operating system (Linux, macOS, Windows etc). However, as a container may not use the same executable format as the one produced by your operating system, we will instruct the Maven build to produce an executable by leveraging a container runtime (as described in container-runtime):
生成的执行文件将是一个 64 位 Linux 可执行文件,因此,根据操作系统,它可能不再可运行。然而,这不是问题,因为我们将它复制到容器。项目生成了 src/main/docker
目录中的 Dockerfile.native-micro
,其内容如下:
The produced executable will be a 64-bit Linux executable, so depending on your operating system it may no longer be runnable.
However, it’s not an issue as we are going to copy it to a container.
The project generation has provided a Dockerfile.native-micro
in the src/main/docker
directory with the following content:
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Quarkus Micro Image?
Quarkus 微镜像是一个小容器镜像,它提供了运行本地应用程序所需的正确依赖关系集。它基于 UBI Micro。这个基础镜像已经定制成非常适合在容器中工作。 The Quarkus Micro Image is a small container image providing the right set of dependencies to run your native application. It is based on UBI Micro. This base image has been tailored to work perfectly in containers. 你可以在以下内容中了解有关 UBI 镜像的更多信息: You can read more about UBI images on: UBI 镜像可以用在没有任何限制的情况下。 UBI images can be used without any limitations. This page 中解释了当你应用程序有特定要求时,如何扩展 This page explains how to extend the |
然后,如果你没有删除生成的本地可执行文件,你可以用以下内容构建 Docker 镜像:
Then, if you didn’t delete the generated native executable, you can build the docker image with:
docker build -f src/main/docker/Dockerfile.native-micro -t quarkus-quickstart/getting-started .
最后,用以下内容运行它:
And finally, run it with:
docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started
Manually using the minimal base image
项目生成了 src/main/docker
目录中的 Dockerfile.native
,其内容如下:
The project generation has also provided a Dockerfile.native
in the src/main/docker
directory with the following content:
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.10
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application
EXPOSE 8080
USER 1001
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
UBI 最小镜像比上面提到的微镜像大。它包含更多的实用程序,如 microdnf
包管理器。
The UBI minimal image is bigger than the micro one mentioned above.
It contains more utilities such as the microdnf
package manager.
Using a multi-stage Docker build
上一节向你展示了怎样使用 Maven 或 Gradle 构建本地可执行文件,但是它要求你首先创建本地可执行文件。此外,这个本地可执行文件必须是 Linux 64 位可执行文件。
The previous section showed you how to build a native executable using Maven or Gradle, but it requires you to have created the native executable first. In addition, this native executable must be a Linux 64 bits executable.
你可能希望直接在容器中构建本地可执行文件,而不用拥有一个包含构建工具的最终容器。这种方法可以使用多阶段 Docker 构建来实现:
You may want to build the native executable directly in a container without having a final container containing the build tools. That approach is possible with a multi-stage Docker build:
-
The first stage builds the native executable using Maven or Gradle
-
The second stage is a minimal image copying the produced native executable
在从下列 Dockerfiles 构建容器图像之前,需要更新默认的 .dockerignore
文件,因为该文件将过滤掉除 target
目录之外的所有内容。为了在容器内构建,需要复制 src
目录。因此,编辑 .dockerignore
并删除 *
行。
Before building a container image from the Dockerfiles shown below, you need to update the default .dockerignore
file, as it filters everything except the target
directory. In order to build inside a container, you need to copy the src
directory. Thus, edit your .dockerignore
and remove the *
line.
多阶段构建可通过以下步骤实现:
Such a multi-stage build can be achieved as follows:
用于构建 Maven 的示例 Dockerfile:
Sample Dockerfile for building with Maven:
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi-quarkus-mandrel-builder-image:{mandrel-flavor} AS build
COPY --chown=quarkus:quarkus mvnw /code/mvnw
COPY --chown=quarkus:quarkus .mvn /code/.mvn
COPY --chown=quarkus:quarkus pom.xml /code/
USER quarkus
WORKDIR /code
RUN ./mvnw -B org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline
COPY src /code/src
RUN ./mvnw package -Dnative
## Stage 2 : create the docker final image
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY --from=build /code/target/*-runner /work/application
# set up permissions for user `1001`
RUN chmod 775 /work /work/application \
&& chown -R 1001 /work \
&& chmod -R "g+rwX" /work \
&& chown -R 1001:root /work
EXPOSE 8080
USER 1001
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
多阶段 Docker 构建会从主机复制 Maven wrapper。Maven wrapper(或 Gradle wrapper)是提供特定 Maven/Gradle 版本的便捷方式。它避免了使用 Maven 和 Gradle 创建基础镜像的情况。在项目中供应 Maven Wrapper,使用: |
This multi-stage Docker build copies the Maven wrapper from the host machine.
The Maven wrapper (or the Gradle wrapper) is a convenient way to provide a specific version of Maven/Gradle.
It avoids having to create a base image with Maven and Gradle.
To provision the Maven Wrapper in your project, use: |
将此文件保存在 src/main/docker/Dockerfile.multistage
中,因为它未包含在快速上手指南中。
Save this file in src/main/docker/Dockerfile.multistage
as it is not included in the getting started quickstart.
用于构建 Gradle 的示例 Dockerfile:
Sample Dockerfile for building with Gradle:
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi-quarkus-mandrel-builder-image:{mandrel-flavor} AS build
USER root
RUN microdnf install findutils
COPY --chown=quarkus:quarkus gradlew /code/gradlew
COPY --chown=quarkus:quarkus gradle /code/gradle
COPY --chown=quarkus:quarkus build.gradle /code/
COPY --chown=quarkus:quarkus settings.gradle /code/
COPY --chown=quarkus:quarkus gradle.properties /code/
USER quarkus
WORKDIR /code
COPY src /code/src
RUN ./gradlew build -Dquarkus.native.enabled=true
## Stage 2 : create the docker final image
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY --from=build /code/build/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
如果在项目中使用 Gradle,可以使用此示例 Dockerfile。将它保存在 src/main/docker/Dockerfile.multistage
中。
If you are using Gradle in your project, you can use this sample Dockerfile. Save it in src/main/docker/Dockerfile.multistage
.
docker build -f src/main/docker/Dockerfile.multistage -t quarkus-quickstart/getting-started .
最后,运行:
And, finally, run it with:
docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started
如果在本机可执行文件中需要 SSL 支持,可以轻松地在 Docker 镜像中包含必要的库。 If you need SSL support in your native executable, you can easily include the necessary libraries in your Docker image. 请参阅 our Using SSL With Native Executables guide 以了解更多信息。 Please see our Using SSL With Native Executables guide for more information. |
若要使用 GraalVM CE 代替 Mandrel,将 To use GraalVM CE instead of Mandrel, update the |
Using a Distroless base image
Distroless 镜像支持为实验性功能。
Distroless image support is experimental.
如果您正在寻找小型容器镜像, distroless 方法会减小基本层的尺寸。 distroless 的理念是使用单一且最小的基础镜像,包含所有需求甚至有时包含应用程序本身。
If you are looking for small container images, the distroless approach reduces the size of the base layer. The idea behind distroless is the usage of a single and minimal base image containing all the requirements, and sometimes even the application itself.
Quarkus 提供了可以在 Dockerfile
中使用的 distroless 基础镜像。您只需复制您的应用程序即可完成:
Quarkus provides a distroless base image that you can use in your Dockerfile
.
You only need to copy your application, and you are done:
FROM quay.io/quarkus/quarkus-distroless-image:2.0
COPY target/*-runner /application
EXPOSE 8080
USER nonroot
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Quarkus 提供 quay.io/quarkus/quarkus-distroless-image:2.0
镜像。它包含运行本机可执行文件所需的软件包,并且仅 9Mb。只需将您的应用程序添加到此镜像上即可获得一个微小的容器镜像。
Quarkus provides the quay.io/quarkus/quarkus-distroless-image:2.0
image.
It contains the required packages to run a native executable and is only 9Mb.
Just add your application on top of this image, and you will get a tiny container image.
在没有严格测试的情况下,不应在生产中使用 distroless 镜像。
Distroless images should not be used in production without rigorous testing.
Build a container image from scratch
Scratch 镜像支持为实验性功能。
Scratch image support is experimental.
构建完全静态链接二进制文件支持使用包含结果原生可执行文件的 scratch image。
Building fully statically linked binaries enables the usage of a scratch image containing solely the resulting native executable.
用于从 `scratch`构建映像的示例多阶段 Dockerfile:
Sample multistage Dockerfile for building an image from scratch
:
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi-quarkus-graalvmce-builder-image:{graalvm-flavor} AS build
USER root
RUN microdnf install make gcc
COPY --chown=quarkus:quarkus mvnw /code/mvnw
COPY --chown=quarkus:quarkus .mvn /code/.mvn
COPY --chown=quarkus:quarkus pom.xml /code/
RUN mkdir /musl && \
curl -L -o musl.tar.gz https://more.musl.cc/11.2.1/x86_64-linux-musl/x86_64-linux-musl-native.tgz && \
tar -xvzf musl.tar.gz -C /musl --strip-components 1 && \
curl -L -o zlib.tar.gz https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz && \
mkdir zlib && tar -xvzf zlib.tar.gz -C zlib --strip-components 1 && \
cd zlib && ./configure --static --prefix=/musl && \
make && make install && \
cd .. && rm -rf zlib && rm -f zlib.tar.gz && rm -f musl.tar.gz
ENV PATH="/musl/bin:${PATH}"
USER quarkus
WORKDIR /code
RUN ./mvnw -B org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline
COPY src /code/src
RUN ./mvnw package -Dnative -DskipTests -Dquarkus.native.additional-build-args="--static","--libc=musl"
## Stage 2 : create the final image
FROM scratch
COPY --from=build /code/target/*-runner /application
EXPOSE 8080
ENTRYPOINT [ "/application" ]
在没有严格测试的情况下,不应在生产中使用擦除镜像。
Scratch images should not be used in production without rigorous testing.
musl 和 zlib 的版本可能需要更新以满足原生镜像可执行文件要求(如果您使用原生镜像压缩,则还需要更新 UPX)。 |
The versions of musl and zlib may need to be updated to meet the native-image executable requirements (and UPX if you use native image compression). |
Compress native images
Quarkus 可以使用 UPX 压缩生成的原生可执行文件。有关 UPX Compression documentation 的更多详细信息。
Quarkus can compress the produced native executable using UPX. More details on UPX Compression documentation.
Separating Java and native image compilation
在某些情况下,您可能需要单独执行一个步骤来构建原生镜像。例如,在 CI/CD 管道中,您可能需要执行一个步骤来生成原生镜像生成的源,同时执行另一个步骤来使用这些源实际构建原生可执行程序。对于此用例,您可以设置附加标记 quarkus.native.sources-only=true
。这将执行 Java 编译,就像您启动原生编译一样(-Dnative
),但是会在触发对 GraalVM 的 native-image
的实际调用之前停止。
In certain circumstances, you may want to build the native image in a separate step.
For example, in a CI/CD pipeline, you may want to have one step to generate the source that will be used for the native image generation and another step to use these sources to actually build the native executable.
For this use case, you can set the additional flag quarkus.native.sources-only=true
.
This will execute the java compilation as if you had started native compilation (-Dnative
), but stops before triggering the actual call to GraalVM’s native-image
.
$ ./mvnw clean package -Dnative -Dquarkus.native.sources-only=true
编译完成后,您可以在 target/native-sources
中找到构建工件:
After compilation has finished, you find the build artifact in target/native-sources
:
$ cd target/native-sources
$ ls
getting-started-1.0.0-SNAPSHOT-runner.jar graalvm.version lib native-image.args
从上面的输出中可以看到,除了生成的 jar 文件和相关的 lib 目录之外,还创建了一个名为 native-image.args
的文本文件。此文件保存了所有参数(包括要编译的 JAR 的名称)以传递给 GraalVM 的 native-image
命令。还创建了一个名为 graalvm.version
的文本文件,其中保存了应使用的 GraalVM 版本。如果您安装了与该版本匹配的 GraalVM,则可以通过执行以下操作来启动原生编译:
From the output above one can see that, in addition to the produced jar file and the associated lib directory, a text file named native-image.args
was created.
This file holds all parameters (including the name of the JAR to compile) to pass along to GraalVM’s native-image
command.
A text file named graalvm.version
was also created and holds the GraalVM version that should be used.
If you have GraalVM installed and it matches this version, you can start the native compilation by executing:
$ cd target/native-sources
$ native-image $(cat native-image.args)
...
$ ls
native-image.args
getting-started-1.0.0-SNAPSHOT-runner
getting-started-1.0.0-SNAPSHOT-runner.build_artifacts.txt
getting-started-1.0.0-SNAPSHOT-runner.jar
Gradle 的流程是类似的。
The process for Gradle is analogous.
还可以在容器中运行构建流程:
Running the build process in a container is also possible:
$ ./mvnw clean package -Dquarkus.native.enabled=true -Dquarkus.native.sources-only=true -Dquarkus.native.container-build=true
-Dquarkus.native.container-build=true
将生成一个名为 native-builder.image
的其他文本文件,其中包含用于构建原生镜像的 Docker 镜像名称。
-Dquarkus.native.container-build=true
will produce an additional text file named native-builder.image
holding the docker image name to be used to build the native image.
cd target/native-sources
docker run \
-it \
--user $(id -ur):$(id -gr) \
--rm \
-v $(pwd):/work \(1)
-w /work \(2)
--entrypoint /bin/sh \
$(cat native-builder.image) \(3)
-c "native-image $(cat native-image.args) -J-Xmx4g"(4)
1 | Mount the host’s directory target/native-image to the container’s /work . Thus, the generated binary will also be written to this directory. |
2 | Switch the working directory to /work , which we have mounted in <1>. |
3 | Use the docker image from the file native-builder.image . |
4 | Call native-image with the content of file native-image.args as arguments. We also supply an additional argument to limit the process’s maximum memory to 4 Gigabytes (this may vary depending on the project being built and the machine building it). |
如果您在 Windows 机器上运行,请记住,该二进制文件是在 Linux Docker 容器中创建的。因此,二进制文件在主机 Windows 机器上不可执行。
If you are running on a Windows machine, please keep in mind that the binary was created within a Linux docker container. Hence, the binary will not be executable on the host Windows machine.
CI/CD 管道的各个步骤的一般概述如下:
A high level overview of what the various steps of a CI/CD pipeline would look is the following:
-
Register the output of the step executing
./mvnw …
command (i.e. directorytarget/native-image
) as a build artifact, -
Require this artifact in the step executing the
native-image …
command, and -
Register the output of the step executing the
native-image …
command (i.e. files matchingtarget/*runner
) as build artifact.
执行步骤 1
的环境只需安装 Java 和 Maven(或 Gradle),而执行步骤 3
的环境只需安装 GraalVM(包括 native-image
功能)。
The environment executing step 1
only needs Java and Maven (or Gradle) installed, while the environment executing step 3
only needs a GraalVM installation (including the native-image
feature).
根据 CI/CD 管道期望的最终所需输出,所生成的二进制文件可用于创建容器映像。
Depending on what the final desired output of the CI/CD pipeline is, the generated binary might then be used to create a container image.
Debugging native executable
可以使用诸如 gdb
的工具对本地可执行文件进行调试。为此,需要使用调试符号来生成本地可执行文件。
Native executables can be debugged using tools such as gdb
.
For this to be possible native executables need to be generated with debug symbols.
仅在 Linux 上支持调试符号生成。Windows 支持仍在开发中,而 macOS 不支持。 |
Debug symbol generation is only supported on Linux. Windows support is still under development, while macOS is not supported. |
要生成调试符号,请在生成原生可执行文件时添加 -Dquarkus.native.debug.enabled=true
标志。您将在原生可执行文件旁边的 .debug
文件中找到该原生可执行文件的调试符号。
To generate debug symbols,
add -Dquarkus.native.debug.enabled=true
flag when generating the native executable.
You will find the debug symbols for the native executable in a .debug
file next to the native executable.
The generation of the
当 When |
除了调试符号之外,设置 -Dquarkus.native.debug.enabled=true
标志还可生成源文件缓存,用于在生成原生可执行文件过程中解析的任何 JDK 运行时类、GraalVM 类和应用程序类。此源缓存对原生调试工具很有用,可建立符号与其匹配的源代码之间的链接。它提供了一种便捷的方式,仅向调试器/IDE 提供必需的源,以便调试原生可执行文件。
Aside from debug symbols,
setting -Dquarkus.native.debug.enabled=true
flag generates a cache of source files
for any JDK runtime classes, GraalVM classes and application classes resolved during native executable generation.
This source cache is useful for native debugging tools,
to establish the link between the symbols and matching source code.
It provides a convenient way of making just the necessary sources available to the debugger/IDE when debugging a native executable.
默认情况下,不会向源缓存中添加第三方 jar 依赖项的源,包括 Quarkus 源代码。要包含这些源,请确保首先调用 mvn dependency:sources
。此步骤是必需的,以便提取这些依赖项的源并将其包含在源缓存中。
Sources for third party jar dependencies, including Quarkus source code,
are not added to the source cache by default.
To include those, make sure you invoke mvn dependency:sources
first.
This step is required in order to pull the sources for these dependencies,
and get them included in the source cache.
源缓存位于 target/sources
文件夹中。
The source cache is located in the target/sources
folder.
如果从与 If running
或使用以下命令启动 in the 例如, Or start
如果从与 e.g.,
|
有关调试原生映像的更详细指南,请参阅 Native Reference Guide。
For a more detailed guide about debugging native images please refer to the Native Reference Guide.
Using Monitoring Options
可以将监控选项(如 JDK 飞行记录器、jvmstat、堆转储和远程 JMX(Mandrel 23 中的实验性功能))添加到原生可执行文件版本中。只需在构建时提供您希望包含的监控选项的逗号分隔列表。
Monitoring options such as JDK flight recorder, jvmstat, heap dumps, and remote JMX (experimental in Mandrel 23) can be added to the native executable build. Simply supply a comma separated list of the monitoring options you wish to include at build time.
-Dquarkus.native.monitoring=<comma separated list of options>
Monitoring Option | Description | Availability As Of |
---|---|---|
jfr |
Include JDK Flight Recorder support |
GraalVM CE 21.3 Mandrel 21.3 |
jvmstat |
Adds jvmstat support |
GraalVM 22.3, GraalVM CE 17.0.7 Mandrel 22.3 Mandrel 23.0 (17.0.7) |
heapdump |
Adds support for generating heap dumps |
GraalVM 22.3, GraalVM CE 17.0.7 Mandrel 22.3 Mandrel 23.0 (17.0.7) |
jmxclient |
Adds support for connections to JMX servers. |
GraalVM for JDK 17/20 Mandrel 23.0 |
jmxserver |
Adds support for accepting connections from JMX clients. |
GraalVM for JDK 17/20 Mandrel 23.0 (17.0.7) |
all |
Adds all monitoring options. |
GraalVM 22.3, GraalVM CE 17.0.7 Mandrel 22.3 Mandrel 23.0 (17.0.7) |
请参阅 Quarkus Native 参考指南,了解有关这些监控选项的更详细信息。
Please see the Quarkus Native Reference Guide for more detailed information on these monitoring options.
Configuring the Native Executable
有很多不同的配置选项可能会影响本机可执行文件的生成方式。这些配置选项已在 application.properties
中提供,与任何其他配置属性相同。
There are a lot of different configuration options that can affect how the native executable is generated.
These are provided in application.properties
the same as any other config property.
属性如下所示:
The properties are shown below:
Unresolved directive in building-native-image.adoc - include::{generated-dir}/config/quarkus-core_quarkus.native.adoc[]
What’s next?
本指南介绍了为应用程序创建一个本机(二进制)可执行文件。它提供了一个展示了快速启动时间和消耗较少内存的应用程序。不过,还要做更多的事情。
This guide covered the creation of a native (binary) executable for your application. It provides an application exhibiting a swift startup time and consuming less memory. However, there is much more.
我们建议继续使用 deployment to Kubernetes and OpenShift 进行后续操作。
We recommend continuing the journey with the deployment to Kubernetes and OpenShift.