Jib - 如何使用基础镜像中的环境变量

Jib - How to use environmental variables from base image

我有一个基础 java 图像,其中一些预定义 java_opts 作为环境变量。我如何在插件中使用它们?

                    <plugin>
                        <groupId>com.google.cloud.tools</groupId>
                        <artifactId>jib-maven-plugin</artifactId>
                        <version>1.8.0</version>
                        <configuration>
                            <from>
                                <image>${docker.registry}java:11</image>
                            </from>
                            <to>
                                <image>${docker.registry}portal-backend:${dockerfile.tag}</image>
                            </to>
                            <container>
                                <jvmFlags>
                                    # This will fail
                                    <jvmFlag>$JAVA_OPTS</jvmFlag>
                                </jvmFlags>
                            </container>
                        </configuration>
                    </plugin>

(在我开始之前:即使 $JAVA_OPTS 在编译时 运行 构建 Maven 时被扩展(显然它没有被扩展),<jvmFlag>$JAVA_OPTS<jvmFlag> 仍然会失败,因为包含多个 JVM 标志的 $JAVA_OPTS 的整个字符串值将作为 单个 参数传递给 java 二进制文件。例如,-Xms1024m -Xmx2048m应该作为两个单独的标志传递。包括空格作为单个参数的整个字符串不是有效的 JVM 标志。)


如果可能,让基本图像定义 JAVA_TOOL_OPTIONS(注意不是 JAVA_TOOL_OPTS 也不是 JAVA_OPTS)。大多数 JVM 将接受 JAVA_TOOL_OPTIONS。参见 for details. (Also note that, container runtimes (docker, Kubernetes, etc.) can always provide environment variables (and/or override whatever variables defined at build time as container configuration) at runtime. That is, you can dynamically set arguments at runtime。)


另一种选择是定义您自己的 <entrypoint> 以使用 shell。 (因此,您需要一个包含 shell 二进制文件(例如 /bin/bash)的基础镜像。请注意,Jib 3.0 之前的默认基础镜像是 Distroless and did not include a shell program. OTOH, Jib 3.0+ doesn't use Distroless。)

在这种方法中,您需要知道正确的 Java 运行 时间 class 路径和主要 class 以在您的 JVM 启动命令中使用。为了帮助解决这个问题,从 Jib >= 3.1 开始,Jib 在构建的图像中创建 two JVM argument files;它们将分别保存构建映像中的 class 路径和主要 class。

知道入口点,你可以写一个shell脚本(my-entrypoint.sh):

#!/bin/sh

# Assumes `java` is on PATH in the base image.
exec java $JAVA_OPTS \
  -cp $( cat /app/jib-classpath-file ) \
  $( cat /app/jib-main-class-file )

或者,如果您使用的是 Java 9+,您可以利用 @-argument 文件:

exec java $JAVA_OPTS -cp @/app/jib-classpath-file @/app/jib-main-class-file

my-entrypoint.sh 放在 <project root>/src/main/jib 下。这是 Jib 的 <extraDirectories> 特性的默认目录,Jib 会将 src/main/jib/my-entrypoint.sh 放在容器镜像的根目录下。然后将默认的<entrypoint>设置为这个脚本:

<container>
  <!-- Assumes you have /bin/sh as specified at the top of /my-entrypoint.sh. -->
  <entrypoint>/my-entrypoint.sh</entrypoint>
</container>
<!-- You also need to make the script executable. -->
<extraDirectories>
  <permissions>
    <permission>
      <file>/my-entrypoint.sh</file>
      <mode>755</mode>
    </permission>
  </permissions>
</extraDirectories>

或者,如果您如下调用 /bin/sh,则无需配置 <extraDirectories> 即可使文件可执行。这可能看起来不习惯;您通常会使脚本可执行并直接 运行 它。但这是完全有效的,实际执行上没有区别(只要/entrypoint.sh的shebang是一样的#!/bin/sh)。

<container>
  <entrypoint>
    <arg>/bin/sh</arg>
    <arg>/my-entrypoint.sh</arg>
  </entrypoint>
</container>

也可以在不创建脚本的情况下执行此操作(基本上是将整个脚本嵌入 pom.xml 并将其传递给 shell 程序)。在这种情况下,您不需要配置 <extraDirectories>.

          <container>
            <entrypoint>
              <arg>/bin/sh</arg>
              <arg>-c</arg>
              <arg>exec java $JAVA_OPTS -cp $( cat /app/jib-classpath-file ) $( cat /app/jib-main-class-file )</arg>
            </entrypoint>
          </container>

变量定义如下

选项 1:Java 系统属性(VM 参数)

-D 参数必须在 application.jar 之前,否则无法识别。

java -jar -Dspring.profiles.active=prod application.jar

选项 2:程序参数

java -jar application.jar --spring.profiles.active=prod --spring.config.location=c:\config

POM 更改: 当使用 jib 作为 maven 插件时 - 更改 spring 配置文件位置的加载:然后将 entryPoint 传递到容器内部,但似乎 jib 插件没有选择它。因此需要在 pom 中为位置的参数访问进行以下更改:

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>2.2.0</version>
    <configuration>
        <to>
            <image>image-url</image>
        </to>
        <container>
            <creationTime>${​​​​​​maven.build.timestamp}​​​​​​</creationTime>
            <mainClass>com.package.SpringBootMainClass</mainClass>
            <args>
                <arg>--spring.config.location=/demo/location/application.yml</arg>
            </args>
        </container>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>
</plugin>

pom 中的 Jib-maven 插件如何传递参数,只是展示了一种通过 pom 的方法,jib 不从 spring 应用程序的入口点获取参数,这就是为什么想到为相同的。如上答案没有。

我的解决方案是从 jib-maven-plugin 配置中完全删除 JVM 内存参数。相反,我为容器定义了 JAVA_TOOL_OPTIONS 环境变量(例如:JAVA_TOOL_OPTIONS='-Xss=512k')(例如:在 docker-compose 配置文件中)。

请注意,根本不需要在基础映像中定义此环境变量。