返回

构建静态链接或大部分静态链接的原生可执行文件

GraalVM 原生镜像默认构建动态链接的二进制文件:在构建时,它首先加载您的应用程序类和接口,然后通过动态链接过程将它们连接起来。

但是,您可以根据需要创建静态链接或大部分静态链接的原生可执行文件。

静态原生可执行文件 是一个静态链接的二进制文件,您可以在没有任何其他库依赖项的情况下使用它。静态原生可执行文件易于分发和部署在精简或无发行版容器(一个 scratch 容器)上。您可以通过静态链接到 musl-libc 来创建一个静态原生可执行文件,这是一个轻量级、快速且简单的 libc 实现。

大部分静态原生可执行文件 是一个二进制文件,它链接了原生可执行文件依赖的所有共享库(zlib、JDK 共享静态库),除了标准 C 库 libc 之外。这是对静态链接所有内容的另一种选择。此外,根据用户的代码,它可能链接 libstdc+libgcc。这种方法对于部署在无发行版容器镜像上非常有用。

本指南展示了如何利用原生镜像链接选项(包括完全动态、完全静态和大部分静态(除了 libc)来生成适合您部署场景的可执行文件。

先决条件和准备工作

  • Linux x64 操作系统
  • 用于 Java 17 或更高版本的 GraalVM 发行版
  • 64 位 musl 工具链、makeconfigure
  • 最新的 zlib

使用 SDKMAN! 安装 GraalVM 最简单的方法。有关其他安装选项,请访问 下载部分

要使用原生镜像创建静态链接的应用程序,您需要一个带有 zlib 库的 musl 工具链。为了获得最佳兼容性,请使用 musl-1.2.4 或更高版本。我们建议从 源代码 构建 musl,如下所示

# Specify an installation directory for musl:
export MUSL_HOME=$PWD/musl-toolchain

# Download musl and zlib sources:
curl -O https://musl.libc.org/releases/musl-1.2.4.tar.gz
curl -O https://zlib.net/fossils/zlib-1.2.13.tar.gz

# Build musl from source
tar -xzvf musl-1.2.4.tar.gz
pushd musl-1.2.4
./configure --prefix=$MUSL_HOME --static
# The next operation may require privileged access to system resources, so use sudo
sudo make && make install
popd

# Install a symlink for use by native-image
ln -s $MUSL_HOME/bin/musl-gcc $MUSL_HOME/bin/x86_64-linux-musl-gcc

# Extend the system path and confirm that musl is available by printing its version
export PATH="$MUSL_HOME/bin:$PATH"
x86_64-linux-musl-gcc --version

# Build zlib with musl from source and install into the MUSL_HOME directory
tar -xzvf zlib-1.2.13.tar.gz
pushd zlib-1.2.13
CC=musl-gcc ./configure --prefix=$MUSL_HOME --static
make && make install
popd

在设置好需求后,创建演示程序。

构建静态原生可执行文件

  1. 将以下源代码保存在名为 EnvMap.java 的文件中
     import java.util.Map;
    
     public class EnvMap {
         public static void main (String[] args) {
             var filter = args.length > 0 ? args[0] : "";
             Map<String, String> env = System.getenv();
             for (String envName : env.keySet()) {
                 if(envName.contains(filter)) {
                     System.out.format("%s=%s%n",
                                     envName,
                                     env.get(envName));
                 }
             }
         }
     }
    

    此应用程序遍历您的环境变量,并打印出包含作为命令行参数传递的字符 String 的环境变量。

  2. 编译应用程序
     javac EnvMap.java
    
  3. 通过运行以下命令来构建静态原生可执行文件
     native-image --static --libc=musl EnvMap
    

    这将生成一个具有静态链接系统库的原生可执行文件。使用 ./envmap 运行它。

    您可以使用 ldd 命令确认应用程序是完全静态链接的

     ldd EnvMap
    

    输出应为“不是动态可执行文件”。

构建大部分静态原生可执行文件

使用 GraalVM 原生镜像,您可以构建一个大部分静态的原生可执行文件,该文件静态链接除 libc 之外的所有内容。静态链接除 libc 之外的所有库可以确保您的应用程序拥有在任何 Linux libc 基于发行版上运行所需的所有库。

要构建大部分静态的原生可执行文件,请使用以下命令

native-image --static-nolibc [other arguments] <Class>

要为上述 EnvMap 演示构建大部分静态的原生可执行文件,请运行

native-image --static-nolibc EnvMap

这将生成一个原生可执行文件,该文件静态链接所有相关的库(包括 JDK 共享静态库),除了 libc 之外。这包括 zlib。此外,根据用户的代码,它可能链接 libstdc+libgcc。检查应用程序依赖哪些动态库的一种方法是使用原生可执行文件运行 ldd,例如 ldd envmap

常见问题解答

完全静态的原生可执行文件为您提供了最大的灵活性来选择基本容器镜像——它甚至可以在 scratch 镜像上运行。大部分静态的原生可执行文件需要一个提供 libc(特别是 glibc)的基本容器镜像,但没有其他要求。在这两种情况下,选择基本容器镜像通常取决于您的原生可执行文件的特定要求。

  • 小型 Java 容器 演示展示了如何编译简单的 Java 应用程序和简单的 Web 服务器,以使用各种轻量级基本镜像生成非常小的 Docker 容器镜像。
  • GraalVM 原生镜像、Spring 和容器化 交互式实验室用于构建 Spring Boot 应用程序的几乎静态可执行文件。

联系我们