构建原生可执行文件
先决条件
要完成本指南,您需要
-
大约 15 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
一个正常工作的容器运行时(Docker 或 Podman)
-
如果您想使用它,可以选择 Quarkus CLI
-
已安装并正确配置的 Mandrel 或 GraalVM
-
在《入门指南》中开发的应用程序的代码。
支持 C 中的原生编译
拥有可用的 C 开发环境意味着什么?
|
背景
构建原生可执行文件需要使用 GraalVM 的某个发行版。有三个发行版:Oracle GraalVM 社区版 (CE)、Oracle GraalVM 企业版 (EE) 和 Mandrel。Oracle 和 Mandrel 发行版之间的区别如下
-
Mandrel 是 Oracle GraalVM CE 的下游发行版。Mandrel 的主要目标是提供一种构建原生可执行文件的方法,该方法专门设计用于支持 Quarkus。
-
Mandrel 版本是从源自上游 Oracle GraalVM CE 代码库的代码库构建的,只有少量更改,但包含一些对 Quarkus 原生应用不必要的显著排除项。它们支持与 Oracle GraalVM CE 相同的构建原生可执行文件的功能,功能上没有重大更改。值得注意的是,它们不包含对多语言编程的支持。排除这些的原因是为了为主流 Quarkus 用户提供更好的支持级别。这些排除项也意味着与 Oracle GraalVM CE/EE 相比,Mandrel 在分发大小上有了显著的减小。
-
Mandrel 的构建方式与 Oracle GraalVM CE 略有不同,它使用了标准的 OpenJDK 项目。这意味着它无法利用 Oracle 为构建其自身的 GraalVM 下载版本所添加的一些小幅增强。这些增强功能被省略是因为上游 OpenJDK 不管理它们,也无法保证。这一点在一致性和安全性方面尤其重要。
-
建议使用 Mandrel 构建以 Linux 容器化环境为目标的原生可执行文件。这意味着鼓励 Mandrel 用户使用容器来构建其原生可执行文件。如果您正在为 amd64/x86 上的 macOS 构建原生可执行文件,您应该考虑使用 Oracle GraalVM,因为 Mandrel 目前不以该平台为目标。可以在Mandrel README 和Mandrel releases 中找到直接在裸金属 Linux、macOS (M 处理器) 或 Windows 上构建原生可执行文件的详细信息。
配置 GraalVM
此步骤仅用于生成以非 Linux 操作系统为目标的原生可执行文件。要生成以 Linux 为目标的原生可执行文件,您可以选择跳过此部分,而是使用构建器镜像。 |
如果您无法安装 GraalVM,可以使用多阶段 Docker 构建来在嵌入了 GraalVM 的 Docker 容器中运行 Maven。在本指南的结尾有如何执行此操作的说明。 |
需要 GraalVM for JDK 21。
-
如果您还没有安装 GraalVM,请安装。您有几种选择:
-
从https://github.com/graalvm/mandrel/releases或https://github.com/graalvm/graalvm-ce-builds/releases下载相应的存档,然后像解压任何其他 JDK 一样解压它。
-
使用特定于平台的安装工具,如sdkman、homebrew或scoop。我们推荐 GraalVM 的*社区版*。例如,使用
sdk install java 21-graalce
安装它。
-
-
配置运行时环境。将
GRAALVM_HOME
环境变量设置为 GraalVM 安装目录,例如export GRAALVM_HOME=$HOME/Development/mandrel/
在 macOS 上 (不支持基于 amd64/x86 的 Mac),将变量指向
Home
子目录export GRAALVM_HOME=$HOME/Development/graalvm/Contents/Home/
在 Windows 上,您必须通过控制面板来设置环境变量。
通过 scoop 安装将为您处理此问题。
-
(可选) 将
JAVA_HOME
环境变量设置为 GraalVM 安装目录。export JAVA_HOME=${GRAALVM_HOME}
-
(可选) 将 GraalVM
bin
目录添加到路径中export PATH=${GRAALVM_HOME}/bin:$PATH
使用 macOS 上的 GraalVM 时出现的问题
GraalVM 二进制文件尚未 (yet) 为 macOS 进行公证,如GraalVM issue中所述。这意味着在使用
使用以下命令递归删除 GraalVM 安装目录上的
|
解决方案
我们建议您遵循后续各节中的说明,分步打包应用程序。但是,您可以直接跳转到已完成的示例。
克隆 Git 存储库: git clone https://github.com/quarkusio/quarkus-quickstarts.git
,或下载存档。
解决方案位于 getting-started
目录中。
生成原生可执行文件
我们应用程序的原生可执行文件将包含应用程序代码、必需的库、Java API 和一个精简版的 VM。更小的 VM 基础可以提高应用程序的启动时间并生成最小的磁盘占用空间。
如果您已从之前的教程生成了应用程序,您可以在 pom.xml
中找到以下 Maven profile 部分
<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>
您可以使用 按照惯例, 您可以在下面的《配置原生可执行文件》部分找到有关如何配置原生镜像构建过程的更多信息。 |
我们使用 profile,因为您很快就会发现,打包原生可执行文件需要*几分钟*。您可以直接在命令行中传递 -Dquarkus.native.enabled=true 作为属性,但是使用 profile 更好,因为这允许运行原生镜像测试。
使用以下命令创建原生可执行文件
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
在 Windows 上打包时出现的问题
在打包之前,必须先初始化 Visual Studio 的 Microsoft Native Tools。您可以启动 Visual Studio Build Tools 安装的 另一个解决方案是编写一个脚本来为您完成此操作
|
除了常规文件外,构建还会生成 target/getting-started-1.0.0-SNAPSHOT-runner
。您可以使用以下命令运行它:./target/getting-started-1.0.0-SNAPSHOT-runner
。
Java 预览功能
依赖预览功能的 Java 代码需要特别注意。要生成原生可执行文件,这意味着需要将 |
测试原生可执行文件
生成原生可执行文件可能会导致一些问题,因此最好针对在原生文件中运行的应用程序运行一些测试。原因在《测试指南》中有解释。
要查看 GreetingResourceIT
在原生可执行文件上运行,请使用 ./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/ubi9-quarkus-mandrel-builder-image:jdk-21 -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=https://: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 秒让原生镜像启动,然后自动失败原生测试。此持续时间可以使用 |
此过程以前是通过 |
配置
默认情况下,集成测试会使用 prod
配置同时*构建*和*运行*原生可执行文件。
您可以使用 quarkus.test.native-image-profile
属性覆盖测试期间可执行文件*运行*的配置。可以通过将其添加到 application.properties
或添加到命令行来完成:./mvnw verify -Dnative -Dquarkus.test.native-image-profile=test
。您的以 %test.
为前缀的属性将在测试运行时使用。
您可以使用 quarkus.profile=test
属性覆盖可执行文件*构建*和*运行*的配置,例如 ./mvnw clean verify -Dnative -Dquarkus.profile=test
。当有需要处理的特定测试资源时,例如将测试数据导入数据库,这可能会很有用。
quarkus.native.resources.includes=version.txt
%test.quarkus.native.resources.includes=version.txt,import-dev.sql
%test.quarkus.hibernate-orm.schema-management.strategy=drop-and-create
%test.quarkus.hibernate-orm.sql-load-script=import-dev.sql
在 application.properties
中使用上述示例,您的 Hibernate ORM 管理的数据库将在 JVM 模式测试运行和原生模式测试运行期间都填充测试数据。生产可执行文件将只包含 version.txt
资源,不包含多余的测试数据。
使用 或者,如果您需要在运行针对使用
|
Java 预览功能
Java 预览功能
依赖预览功能的 Java 代码需要特别注意。要测试原生可执行文件,这意味着需要将 |
在未安装 GraalVM 的情况下创建 Linux 可执行文件
在继续之前,请确保拥有可用的容器运行时 (Docker, podman) 环境。如果您在 Windows 上使用 Docker,则应在 Docker Desktop 文件共享设置中共享项目的驱动器,然后重新启动 Docker Desktop。 |
很多时候,人们只需要为他们的 Quarkus 应用程序创建原生 Linux 可执行文件 (例如,为了在容器化环境中运行),并且希望避免安装正确的 GraalVM 版本来完成这项任务 (例如,在 CI 环境中,尽可能少地安装软件是一种常见做法)。
为此,Quarkus 提供了一种非常方便的方法,通过利用 Docker 或 podman 等容器运行时来创建原生 Linux 可执行文件。完成此任务的最简单方法是执行
quarkus build --native --no-tests -Dquarkus.native.container-build=true
# The --no-tests flag is required only on Windows and macOS.
./mvnw install -Dnative -DskipTests -Dquarkus.native.container-build=true
./gradlew build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true
默认情况下,Quarkus 会自动检测容器运行时。如果您想显式选择容器运行时,可以通过以下方式完成: 对于 Docker CLI
Maven
Gradle
对于 podman CLI
Maven
Gradle
这些是常规的 Quarkus 配置属性,因此如果您总是希望在容器中构建,建议您将这些属性添加到 |
使用容器运行时构建的可执行文件将是 64 位 Linux 可执行文件,因此根据您的操作系统,它可能不再可运行。
从 Quarkus 3.19+ 开始,用于构建原生可执行文件的*构建器*镜像基于 UBI 9。这意味着通过容器构建生成的原生可执行文件也将基于 UBI 9。因此,如果您计划构建容器,请确保您的 您可以通过设置
|
如果您在尝试使用容器构建创建原生可执行文件时看到针对应用程序 JAR 的以下无效路径错误,即使您的 JAR 已成功构建,您也很可能正在使用远程守护进程作为容器运行时。 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 在这种情况下,请使用参数 原因是,通过 |
使用 GraalVM 而不是 Mandrel 进行构建需要额外传递自定义构建器镜像参数 CLI
Maven
Gradle
请注意,上面的命令指向一个浮动标签。强烈建议使用浮动标签,以便您的构建器镜像保持最新和安全。如果您绝对必须,可以硬编码到特定的标签 (请参阅此处 (UBI 8) 和此处 (UBI 9) 查看可用标签),但请注意,您将无法获得安全更新,并且这是不受支持的。 |
创建容器
使用容器镜像扩展
从 Quarkus 应用程序创建容器镜像是最简单的方法是利用其中一个容器镜像扩展。
如果其中一个扩展程序存在,那么为原生可执行文件创建容器镜像基本上就是执行一个命令
./mvnw package -Dnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true
-
quarkus.native.container-build=true
允许在未安装 GraalVM 的情况下创建 Linux 可执行文件 (仅在您未在本地安装 GraalVM 或您的本地操作系统不是 Linux 时才需要)
如果您正在运行远程 Docker 守护进程,则需要将 有关详细信息,请参阅在未安装 GraalVM 的情况下创建 Linux 可执行文件。 |
-
quarkus.container-image.build=true
指示 Quarkus 使用最终的应用程序工件 (在这种情况下是原生可执行文件) 来创建容器镜像。
有关更多详细信息,请参阅《容器镜像指南》。
手动使用 micro 基础镜像
您可以使用 Quarkus Maven 插件生成的 JAR 在容器中运行应用程序。但是,在本节中,我们将重点介绍使用生成的原生可执行文件创建容器镜像。
当使用本地 GraalVM 安装时,原生可执行文件以您的本地操作系统 (Linux, macOS, Windows 等) 为目标。但是,由于容器可能不使用与您的操作系统生成的可执行文件相同的*可执行*格式,我们将指示 Maven 构建使用容器运行时 (如本节所述) 来生成可执行文件。
生成的executable将是64位Linux可执行文件,因此根据您的操作系统,它可能不再可运行。但是,这不成问题,因为我们将把它复制到容器中。项目生成在 src/main/docker
目录中提供了一个 Dockerfile.native-micro
,其内容如下:
FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root --chmod=755 target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
Quarkus Micro 镜像?
Quarkus Micro 镜像是提供运行原生应用程序所需依赖项的小型容器镜像。它基于 UBI Micro。这个基础镜像经过定制,可在容器中完美运行。 您可以在以下位置阅读有关 UBI 镜像的更多信息: UBI 镜像可以无限制使用。 此页面解释了当您的应用程序有特定要求时如何扩展 |
然后,如果您没有删除生成的原生可执行文件,您可以使用以下命令构建 docker 镜像:
docker build -f src/main/docker/Dockerfile.native-micro -t quarkus-quickstart/getting-started .
最后,使用以下命令运行它:
docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started
手动使用 minimal 基础镜像
项目生成还在 src/main/docker
目录中提供了一个 Dockerfile.native
,其内容如下:
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.5
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root --chmod=0755 target/*-runner /work/application
EXPOSE 8080
USER 1001
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
UBI minimal 镜像比上面提到的 micro 镜像要大。它包含更多实用程序,如 microdnf
包管理器。
使用多阶段 Docker 构建
上一节展示了如何使用 Maven 或 Gradle 构建原生可执行文件,但这要求您先创建原生可执行文件。此外,此原生可执行文件必须是 Linux 64 位可执行文件。
您可能希望直接在容器中构建原生可执行文件,而无需最终容器包含构建工具。这种方法可以通过多阶段 Docker 构建实现。
-
第一阶段使用 Maven 或 Gradle 构建原生可执行文件
-
第二阶段是一个最小镜像,复制生成的原生可执行文件
在从下面的 Dockerfile 构建容器镜像之前,您需要更新默认的 |
可以使用以下方法实现这样的多阶段构建:
用于使用 Maven 进行构建的示例 Dockerfile
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi9-quarkus-mandrel-builder-image:jdk-21 AS build
COPY --chown=quarkus:quarkus --chmod=0755 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.8.1:go-offline
COPY src /code/src
RUN ./mvnw package -Dnative
## Stage 2 : create the docker final image
FROM quay.io/quarkus/ubi9-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 包装器。Maven 包装器 (或 Gradle 包装器) 是提供特定版本 Maven/Gradle 的便捷方法。它避免了创建包含 Maven 和 Gradle 的基础镜像。要在您的项目中配置 Maven Wrapper,请使用:mvn wrapper:wrapper 。 |
将此文件保存在 src/main/docker/Dockerfile.multistage
中,因为它不包含在入门快速启动中。
用于使用 Gradle 进行构建的示例 Dockerfile
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi9-quarkus-mandrel-builder-image:jdk-21 AS build
USER root
RUN microdnf install findutils -y
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/ubi9-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
中。
docker build -f src/main/docker/Dockerfile.multistage -t quarkus-quickstart/getting-started .
最后,使用以下命令运行它:
docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started
如果您在原生可执行文件中需要 SSL 支持,您可以轻松地将必要的库包含在 Docker 镜像中。 有关更多信息,请参阅我们关于使用 SSL 与原生可执行文件的指南。 |
要使用 GraalVM CE 而不是 Mandrel,请将 |
使用 Distroless 基础镜像
Distroless 镜像支持是实验性的。 |
如果您正在寻找小型容器镜像,distroless 方法可以减小基础层的尺寸。distroless 的理念是使用一个单一的最小基础镜像,其中包含所有必需项,有时甚至包含应用程序本身。
Quarkus 提供了一个 distroless 基础镜像,您可以在 Dockerfile
中使用它。您只需要复制您的应用程序,然后就完成了。
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**。只需在此镜像之上添加您的应用程序,您就能获得一个微小的容器镜像。
Distroless 镜像在未经严格测试的情况下不应用于生产。
从头开始构建容器镜像
Scratch 镜像支持是实验性的。 |
构建完全静态链接的二进制文件支持使用仅包含最终原生可执行文件的 scratch 镜像。
用于从 scratch
构建镜像的多阶段 Dockerfile 示例
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi9-quarkus-graalvmce-builder-image:jdk-21 AS build
USER root
RUN microdnf install make gcc -y
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.8.1: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 镜像在未经严格测试的情况下不应用于生产。
musl 和 zlib 的版本可能需要更新才能满足 native-image 可执行文件的要求 (如果您使用原生镜像压缩,则还需要 UPX)。 |
压缩原生镜像
Quarkus 可以使用 UPX 压缩生成的原生可执行文件。有关 UPX 压缩文档的更多详细信息,请参阅此处。
分离 Java 和原生镜像编译
在某些情况下,您可能希望在单独的步骤中构建原生镜像。例如,在 CI/CD 管道中,您可能希望有一个步骤来生成将用于原生镜像生成的源代码,另一个步骤使用这些源代码来实际构建原生可执行文件。对于这种情况,您可以设置附加标志 quarkus.native.sources-only=true
。这将触发 Java 编译,就像您启动了原生编译 (-Dnative
) 一样,但在实际调用 GraalVM 的 native-image
之前停止。
$ ./mvnw clean package -Dnative -Dquarkus.native.sources-only=true
编译完成后,您将在 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
的文本文件。此文件包含传递给 GraalVM 的 native-image
命令的所有参数 (包括要编译的 JAR 的名称)。还创建了一个名为 graalvm.version
的文本文件,其中包含应使用的 GraalVM 版本。如果您已安装 GraalVM 并且其版本与此匹配,则可以通过执行以下命令来启动原生编译:
$ 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 的过程是类似的。
在容器中运行构建过程也是可能的
$ ./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 镜像名称。
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 | 将主机的 target/native-image 目录挂载到容器的 /work 。因此,生成的二进制文件也将写入此目录。 |
2 | 将工作目录切换到 /work ,我们已将其挂载在 <1> 中。 |
3 | 使用 native-builder.image 文件中的 docker 镜像。 |
4 | 调用 native-image 并将文件 native-image.args 的内容作为参数。我们还提供了一个附加参数,将进程的最大内存限制为 4 GB (这可能因正在构建的项目和构建它的机器而异)。 |
如果您在 Windows 机器上运行,请记住该二进制文件是在 Linux docker 容器中创建的。因此,该二进制文件将无法在主机 Windows 机器上执行。 |
CI/CD 管道的各个步骤的高层概述如下:
-
将执行
./mvnw …
命令的步骤的输出 (即target/native-image
目录) 注册为构建工件, -
在执行
native-image …
命令的步骤中要求此工件,以及 -
将执行
native-image …
命令的步骤的输出 (即匹配target/*runner
的文件) 注册为构建工件。
执行步骤 1 的环境只需要安装 Java 和 Maven (或 Gradle),而执行步骤 3 的环境只需要安装 GraalVM (包括 native-image
功能)。
根据 CI/CD 管道的最终所需输出,生成的二进制文件随后可用于创建容器镜像。
调试原生可执行文件
可以使用 gdb
等工具调试原生可执行文件。为了实现这一点,需要使用调试符号生成原生可执行文件。
调试符号生成仅在 Linux 上受支持。Windows 支持仍在开发中,而 macOS 不受支持。 |
要生成调试符号,请在生成原生可执行文件时添加 -Dquarkus.native.debug.enabled=true
标志。您将在原生可执行文件旁边找到一个 .debug
文件中的调试符号。
当 |
除了调试符号外,设置 -Dquarkus.native.debug.enabled=true
标志还会生成一个源文件缓存,用于在生成原生可执行文件期间解析的任何 JDK 运行时类、GraalVM 类和应用程序类。此源缓存对于原生调试工具非常有用,可以建立符号与匹配源代码之间的链接。它提供了一种方便的方法,在调试原生可执行文件时,仅将必要的源代码提供给调试器/IDE。
默认情况下,第三方 jar 依赖项 (包括 Quarkus 源代码) 的源代码不会添加到源缓存中。要包含这些,请确保首先调用 mvn dependency:sources
。此步骤是获取这些依赖项的源代码并将其包含在源缓存中所需的。
源缓存位于 target/sources
文件夹中。
如果从与
在 或者使用以下命令启动
例如:
|
有关调试原生镜像的更详细指南,请参阅《原生参考指南》。
使用监控选项
可以在原生可执行文件构建中添加监控选项,例如 JDK flight recorder、jvmstat、heap dumps、NMT (从 Mandrel 24.1 for JDK 23 开始) 和远程 JMX。只需在构建时提供一个逗号分隔的监控选项列表。
-Dquarkus.native.monitoring=<comma separated list of options>
监控选项 | 描述 | 可用性 |
---|---|---|
jfr |
包含 JDK Flight Recorder 支持 |
GraalVM CE 21.3 Mandrel 21.3 |
jvmstat |
添加 jvmstat 支持 |
GraalVM 22.3, GraalVM CE 17.0.7 Mandrel 22.3 Mandrel 23.0 (17.0.7) |
heapdump |
添加生成堆转储的支持 |
GraalVM 22.3, GraalVM CE 17.0.7 Mandrel 22.3 Mandrel 23.0 (17.0.7) |
jmxclient |
添加连接到 JMX 服务器的支持。 |
GraalVM for JDK 17/20 Mandrel 23.0 |
jmxserver |
添加接受来自 JMX 客户端连接的支持。 |
GraalVM for JDK 17/20 Mandrel 23.0 (17.0.7) |
nmt |
添加原生内存跟踪支持。 |
GraalVM for JDK 23 Mandrel 24.1 |
all |
添加所有监控选项。 |
GraalVM 22.3, GraalVM CE 17.0.7 Mandrel 22.3 Mandrel 23.0 (17.0.7) |
有关这些监控选项的更详细信息,请参阅 Quarkus Native Reference Guide。
配置原生可执行文件
有许多不同的配置选项可以影响原生可执行文件的生成方式。这些选项与任何其他配置属性一样,在 application.properties
中提供。
下面显示了这些属性
构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖
配置属性 |
类型 |
默认 |
||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
布尔值 |
|
|||||||||||||||||||||
布尔值 |
|
|||||||||||||||||||||
逗号分隔的附加参数,用于传递给构建过程。如果参数包含 环境变量: 显示更多 |
字符串列表 |
|||||||||||||||||||||
逗号分隔的附加参数,用于传递给构建过程。参数将附加到通过 环境变量: 显示更多 |
字符串列表 |
|||||||||||||||||||||
是否应启用 HTTP URL 处理程序,允许您执行 URL.openConnection() 来处理 HTTP URL 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
是否应启用 HTTPS URL 处理程序,允许您执行 URL.openConnection() 来处理 HTTPS URL 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
java.awt.headless JVM 选项的默认值。切换此选项会影响 awt 库的链接。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
定义文件编码,如 原生镜像运行时使用主机 (即构建时) 的 环境变量: 显示更多 |
字符串 |
|
||||||||||||||||||||
是否应将所有字符集添加到原生可执行文件中。 请注意,某些扩展 (例如 Oracle JDBC 驱动程序) 也会考虑此设置,以在扩展级别启用对所有字符集的支持。 这会增加镜像大小。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
字符串 |
|
|||||||||||||||||||||
|
||||||||||||||||||||||
字符串 |
||||||||||||||||||||||
是否应在运行之前等待调试器附加以进行本地镜像构建。这是一个高级选项,通常仅供熟悉 GraalVM 内部的人员使用。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
当使用 docker 和 debug-build-process 为 true 进行构建时,是否应发布调试端口 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
布尔值 |
|
|||||||||||||||||||||
如果原生镜像失败,是否应创建基于 JVM 的“备用镜像”。不推荐这样做,因为这在功能上与仅在 JVM 中运行应用程序相同。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
是否应自动注册所有 META-INF/services 条目 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
布尔值 |
|
|||||||||||||||||||||
此构建是否应使用容器运行时进行。除非还设置了 container-runtime,否则默认使用 docker。如果 docker 不可用或它是 podman 的别名,则 podman 将作为默认值使用。 环境变量: 显示更多 |
布尔值 |
|||||||||||||||||||||
显式配置选项,用于为 Linux 生成原生位置无关可执行文件 (PIE)。如果系统支持 PIE 生成,则默认行为是出于性能原因禁用它。但是,某些系统只能运行位置无关的可执行文件,因此此选项可启用此类原生可执行文件的生成。 环境变量: 显示更多 |
布尔值 |
|||||||||||||||||||||
为特定机器类型生成指令。在 AMD64 上默认为 环境变量: 显示更多 |
字符串 |
|||||||||||||||||||||
此构建是否使用远程 docker 守护进程进行。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
用于进行镜像构建的 docker 镜像。它可以是 注意: 可用的构建器镜像使用 UBI 8 和 UBI 9 基础镜像,例如
您需要注意,如果您使用基于 UBI9 的构建器镜像并计划构建容器,则必须确保容器中使用的基础镜像也是 UBI9。 环境变量: 显示更多 |
字符串 |
|
||||||||||||||||||||
构建期间拉取构建器镜像的策略。 默认为 'always',它将始终拉取最新的镜像;当 (浮动) 标签更新时,这有助于保持与修复同步。 使用 'missing' 仅在本地缺少镜像时拉取;这在构建使用过时镜像是可以接受且带宽可能有限的开发环境中很有用。 使用 'never' 在本地缺少镜像时失败构建。 环境变量: 显示更多 |
|
|
||||||||||||||||||||
用于进行基于镜像的构建的容器运行时 (例如 docker)。如果设置了此项,则始终执行容器构建。 环境变量: 显示更多 |
|
|||||||||||||||||||||
要传递给容器运行时的选项 环境变量: 显示更多 |
字符串列表 |
|||||||||||||||||||||
启用各种监控选项。值应该是逗号分隔的。
环境变量: 显示更多 |
|
|||||||||||||||||||||
布尔值 |
|
|||||||||||||||||||||
是否应报告带有完整堆栈跟踪的异常 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
是否应在运行时报告错误。这是一个更宽松的设置,但不推荐这样做,因为它意味着您的应用程序可能会在运行时失败,如果无意中使用了不受支持的功能。 请注意,使用此标志可能会由于 `ClassNotFoundException` 而导致构建时失败。原因很可能是 Quarkus 扩展已将其优化掉或实际上不需要它。在这种情况下,您应该将提供缺失类的相应依赖项显式添加为项目依赖项。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
如果原生镜像已存在,则不构建。 这对于您已经构建了镜像并希望使用 Quarkus 将其部署到某处很有用。 请注意,这无法检测现有镜像是否已过时,如果您修改了源代码或配置并想要新镜像,则不得使用此标志。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
一个逗号分隔的 glob 列表,用于匹配应添加到原生镜像的资源路径。 在所有平台上都使用斜杠 ( 默认情况下,不包含任何资源。 示例:假设您的源代码树中有
文件 支持的 glob 功能
请注意,在通过
这三个级别都使用反斜杠 ( 请注意,Quarkus 扩展通常会自行包含它们所需的资源。此选项对于内置功能不够的情况很有用。 环境变量: 显示更多 |
字符串列表 |
|||||||||||||||||||||
一个逗号分隔的 glob 列表,用于匹配*不应*添加到原生镜像的资源路径。 在所有平台上都使用斜杠 ( 有关 glob 语法的详细信息,请参阅 默认情况下,不排除任何资源。 示例:假设您的源代码树中有
资源 环境变量: 显示更多 |
字符串列表 |
|||||||||||||||||||||
如果启用了调试并且生成了调试符号。符号将在单独的 .debug 文件中生成。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
为 GraalVM Dashboard 生成报告文件。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
在生成的 json 配置文件中包含原因条目。 环境变量: 显示更多 |
布尔值 |
|
||||||||||||||||||||
压缩级别在 [1, 10] 之间。10 表示*最佳*。 更高的压缩级别需要更多时间来压缩可执行文件。 环境变量: 显示更多 |
整数 |
|||||||||||||||||||||
允许将额外的参数传递给 UPX 命令行 (例如 --brute)。参数用逗号分隔。 参数的完整列表可以在 https://github.com/upx/upx/blob/devel/doc/upx.pod 中找到。 环境变量: 显示更多 |
字符串列表 |
|||||||||||||||||||||
Quarkus 构建生成的配置文件,使用原生镜像代理,默认情况下是信息性的。换句话说,生成的配置文件显示在构建日志中,但未应用。当此选项设置为 true 时,生成的配置文件将被应用于原生镜像构建过程。 启用此选项时应小心,因为它可能使原生镜像配置和/或行为依赖于其他不明显的因素。例如,如果原生镜像代理生成的配置是通过运行 JVM 单元测试生成的,则禁用测试可能会导致生成不同的原生镜像配置,进而可能错误地配置原生可执行文件或以意想不到的方式影响其行为。 环境变量: 显示更多 |
布尔值 |
|
下一步是什么?
本指南介绍了为您的应用程序创建原生 (二进制) 可执行文件的过程。它提供了一个具有快速启动时间和低内存消耗的应用程序。但是,还有更多内容。
我们建议继续进行部署到 Kubernetes 和 OpenShift的旅程。