【问题标题】:Jib - How to use environmental variables from base imageJib - 如何使用基础镜像中的环境变量
【发布时间】:2020-04-08 23:06:39
【问题描述】:

我有一个基本的 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>

【问题讨论】:

    标签: maven jib


    【解决方案1】:
    推荐的答案 Google Cloud

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


    如果可能,让基本映像定义JAVA_TOOL_OPTIONS(注意不是JAVA_TOOL_OPTS 也不是JAVA_OPTS)。大多数 JVM 都会使用 JAVA_TOOL_OPTIONS。有关详细信息,请参阅https://stackoverflow.com/a/58715040/1701388。 (另请注意,容器运行时(docker、Kubernetes 等)始终可以在运行时提供环境变量(和/或覆盖在构建时定义为容器配置的任何变量)。也就是说,您可以 dynamically set arguments at runtime。)


    另一种选择是定义您自己的&lt;entrypoint&gt; 以使用shell。 (因此,您需要一个包含 shell 二进制文件的基本映像(例如 /bin/bash)。请注意,Jib 3.0 之前的默认基本映像是 Distroless,并且不包含 shell 程序。OTOH,Jib 3.0+ doesn't use Distroless。)

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

    知道了入口点,就可以写一个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 放在&lt;project root&gt;/src/main/jib 下。这是 Jib 的 &lt;extraDirectories&gt; 功能的默认目录,Jib 会将 src/main/jib/my-entrypoint.sh 放置在容器镜像的根目录中。然后将默认的&lt;entrypoint&gt;设置为这个脚本:

    <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,则不必配置&lt;extraDirectories&gt; 以使文件可执行。这可能看起来不习惯;您通常会使脚本可执行并直接运行它。但这是完全有效的,在实际执行上并没有什么区别(只要/entrypoint.sh的shebang和#!/bin/sh一样)。

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

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

              <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_TOOL_OPTIONS 环境变量。您无需在基础 Docker 映像中定义即可使用它。
    【解决方案2】:

    变量定义如下

    选项 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 config 中使用的环境变量无关...
    • Jib-maven plugin in pom how to pass the arguments ,只是通过 pom 展示了一种方式,jib 不会从 spring 应用程序的入口点获取参数,这就是为什么要考虑提供另一种方式的原因.如上答案没有。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-06
      • 2021-07-11
      • 1970-01-01
      • 2020-01-20
      • 2022-12-29
      • 2017-08-26
      • 2019-08-12
      • 2017-08-31
      相关资源
      最近更新 更多