【问题标题】:How to set JVM arguments when running mvn spring-boot:build-image command in Spring Boot 2.3.0 to generate a docker image?在 Spring Boot 2.3.0 中运行 mvn spring-boot:build-image 命令以生成 docker 映像时如何设置 JVM 参数?
【发布时间】:2020-09-03 09:41:16
【问题描述】:

我正在尝试使用最新版本的 Spring Boot (2.3.0) 构建 docker 映像。我现在必须创建一个映像,只需运行命令 mvn:spring-boot:build-image 。这将为我创建一个泊坞窗图像。在这种情况下如何设置 JVM 参数(最大、最小堆大小)?

【问题讨论】:

    标签: spring spring-boot docker jvm


    【解决方案1】:

    这些答案都不完全正确。这是撰写本文时的全部情况。

    重要的是要了解代码运行的两个不同时间:构建时和运行时。

    1. 您可以在构建时使用 Spring Boot 在 Maven 或 Gradle 配置中设置环境变量。您只需给它一个要设置的环境变量列表。见这里https://docs.spring.io/spring-boot/docs/2.3.x/maven-plugin/reference/html/#build-image-customization这些只会在构建时设置。不是你想要设置的东西,比如-Xmx

    2. 如果你想在运行时设置环境变量,那么它不是 Spring Boot 或 buildpacks 可以控制的。两者都不是失败,只是两者都没有参与实际运行您的应用程序映像/容器。

      要在运行时将 env 变量传递给您的应用映像/容器,您需要使用运行应用映像的任何工具,例如 Docker 或 Kubernetes。对于 Docker,它只是 docker run -e foo=bar ...。对于 Kubernetes,它位于 pod spec

      仅供参考。任何以 BPL_ 为前缀的 env 变量意味着它在运行时应用(L 用于启动,这就是 buildpack 所称的运行时环境)。因此,只有在您的应用运行时设置它们才有意义。

    3. 其他答案中提到的environment variables buildpack 是两者的混合体。如果您使用上面的选项 #1 设置 env 变量但以某种方式添加前缀,则此 buildpack 将看到它们并将它们转换为嵌入到图像中的 env 变量。这将具有在运行时设置它们的效果。

      如果您想在图像上设置默认值,这很有效。然后您的图像的用户不需要设置它们,除非他们需要偏离默认值您,图像作者设置。话虽如此,您永远不会想将它用于任何敏感或秘密的事情。这是因为 env 变量和值最终出现在图像中,因此任何有权访问图像的人都可以看到该值。

    回答问题:

    在这种情况下如何设置 JVM 参数(最大、最小堆大小)?

    1. 如果您想设置图像用户可以根据需要覆盖的默认值,那么您需要environment variables buildpack

      例如:

              <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
                  <configuration>
                      <image>
                          <env>
                              <BPE_APPEND_JAVA_TOOL_OPTIONS>-Xss256k</BPE_APPEND_JAVA_TOOL_OPTIONS>
                              <BPE_DELIM_JAVA_TOOL_OPTIONS> </BPE_DELIM_JAVA_TOOL_OPTIONS>
                          </env>
                      </image>
                      <layers>
                          <enabled>true</enabled>
                      </layers>
                  </configuration>
              </plugin>
      

      你会看到这样的输出:

      [INFO]     [creator]     Paketo Environment Variables Buildpack 3.1.1
      [INFO]     [creator]       https://github.com/paketo-buildpacks/environment-variables
      [INFO]     [creator]       Launch Configuration:
      [INFO]     [creator]         $BPE_<NAME>             prepend value to $NAME, delimiting with OS path list separator
      [INFO]     [creator]         $BPE_APPEND_<NAME>      append value to $NAME
      [INFO]     [creator]         $BPE_DEFAULT_<NAME>     set default value for $NAME
      [INFO]     [creator]         $BPE_DELIM_<NAME>       set delimeter to use when appending or prepending to $NAME
      [INFO]     [creator]         $BPE_OVERRIDE_<NAME>    set $NAME to value
      [INFO]     [creator]         $BPE_PREPEND_<NAME>     prepend value to $NAME
      [INFO]     [creator]       Environment Variables: Contributing to layer
      [INFO]     [creator]         Writing env.launch/JAVA_TOOL_OPTIONS.append
      

      当您运行映像的实例时,您设置的值应该传递给容器,除非用户覆盖它们。

      > docker run -it apps/maven
      Setting Active Processor Count to 6
      Calculating JVM memory based on 9057276K available memory
      Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx8699636K -XX:MaxMetaspaceSize=88839K -XX:ReservedCodeCacheSize=240M (Total Memory: 9057276K, Thread Count: 50, Loaded Class Count: 13271, Headroom: 0%)
      Adding 129 container CA certificates to JVM truststore
      Spring Cloud Bindings Enabled
      Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -Xss256k -XX:ActiveProcessorCount=6 -XX:MaxDirectMemorySize=10M -Xmx8699636K -XX:MaxMetaspaceSize=88839K -XX:ReservedCodeCacheSize=240M -Dorg.springframework.cloud.bindings.boot.enable=true
      
    2. 如果您想设置这些值,那么只需在运行时设置它们。例如:docker run -e JAVA_TOOL_OPTIONS '-Xss256k' ... 或像这样在您的 Kubernetes pod 规范中。

      apiVersion: v1
      kind: Pod
      metadata:
        name: my-cool-app
        labels:
          purpose: my-cool-app-label
      spec:
        containers:
        - name: my-cool-app
          image: my-cool-image
          env:
          - name: JAVA_TOOL_OPTIONS
            value: "-Xss256k"
      

      当容器运行时,您会看到类似的输出,Picked up JAVA_TOOL_OPTIONS: 将显示您设置的值,此示例中的 -Xss256k

    【讨论】:

    • 在运行时在 docker 或 kubernetes 中设置值似乎是可靠设置环境变量的唯一方法。您可以使用此示例控制 JAVA_TOOL_OPTIONS,但不能控制 BPL_JVM_THREAD_COUNT。这非常令人困惑,因为图像构建确实列出了Launch Configuration,但说配置实际上并不是应用程序的启动方式。我不清楚那里的信息实际上提供了什么价值。
    • Setting the values in runtime either in docker or kubernetes seems to be the only way to reliably set environment variables. -> 这取决于您要设置的内容。要认识到的最重要区别是构建和启动是分开的,并且您在构建时设置的内容不会在运行时设置,除非您也在那里设置(或使用环境变量 buildpack)。 BPL_* env 变量可以设置构建时间,buildpack 会承认(我同意这可能有点令人困惑),但它不会对它们做任何事情。您需要在启动时进行设置。
    【解决方案2】:

    正如@jeremyt 建议的那样,您可以使用BPE_OVERRIDE_BPL_JVM_THREAD_COUNT 构建变量覆盖此属性的值。示例:

    bootBuildImage {
        environment('BPE_OVERRIDE_BPL_JVM_THREAD_COUNT', '150')
    }
    

    遗憾的是,截至目前,BPE_DEFAULT_BPL_JVM_THREAD_COUNT 不起作用(该值被忽略)。 BPE_OVERRIDE_BPL_JVM_THREAD_COUNT 的缺点是它忽略了为运行时设置的环境变量(在 docker run 中)。

    【讨论】:

      【解决方案3】:

      重新构建环境变量

      我在 2020 年 11 月开始使用 Spring Boot 2.3 和 BuildPacks 时尝试设置 JVM 参数,但一无所获并放弃/搁置一边。

      两周前我再次拿起它,纯属偶然发现:https://github.com/paketo-buildpacks/environment-variables

      基本上,您在环境变量前面加上BPE_APPEND_,这会触发环境变量构建包将您的值追加到环境变量中。

      注意:JAVA_TOOL_OPTIONS 是你想要的,而不是 JAVA_OPTS

      我需要附加一个 Java 代理来监控我们的微服务,像 build.gradle sn-p 这样的东西起作用了:

      bootBuildImage {
        environment = [
          'BPE_DELIM_JAVA_TOOL_OPTIONS' : ' ',
          'BPE_APPEND_JAVA_TOOL_OPTIONS' : '-javaagent:my-java-agent.jar'
          ]
      }
      

      我使用 BPE_DELIM_JAVA_TOOL_OPTIONS 来确保在我的值附加之前将空格添加到 JAVA_TOOL_OPTIONS 的现有值(buildpack 还允许您覆盖或附加到现有值 - 请参阅他们的自述文件)。

      PS:我的值更像'-javaagent:my-java-agent-${some-dynamic-version}.jar',所以我需要双引号,但这使它成为一个不起作用的Gradle String,所以我不得不写这个"-javaagent:my-java-agent-${some-dynamic-version}.jar".toString()

      【讨论】:

      • 出于兴趣,您是如何将 my-java-agent jar 放到您的 docker 映像中的?您是否将其添加为依赖项或其他内容?
      • @PaulNUK 嗨,我必须将它添加为运行时依赖项,然后找出 jAR 的最终位置。
      【解决方案4】:

      截至今天,您无法在 spring-boot:build-image 中设置 JVM 参数。

      Spring boot 构建镜像在内部使用 Packeto,它接受 bellsoft-liberica GitHub 中提到的以下 4 个环境变量。

      "BP_JVM_VERSION" : "13.0.1",  
      "BPL_JVM_HEAD_ROOM" : "10",
      "BPL_JVM_LOADED_CLASS_COUNT" : "35", 
      "BPL_JVM_THREAD_COUNT" : "10"
      

      作为替代选项,您可以在运行映像时传递 JVM 参数。

      docker run -p 8080:8080 --env JAVA_OPTS="-Xmx300m -Xms200m" -t youImageName

      如果使用 Kubernetes,您可以在 deployment level 配置 JVM 选项。

          spec:
            containers:
            - name: yourapp
              image: image path
              ports:
              - containerPort: 8080
              env:
              - name: SPRING_PROFILES_ACTIVE
                value: "prod"    
              - name: BPL_JVM_HEAD_ROOM
                value: "2"  
              - name: BPL_JVM_LOADED_CLASS_COUNT
                value: "35"  
              - name: BPL_JVM_THREAD_COUNT
                value: "10"  
              - name: JAVA_OPTS
                value: >-
                      -XX:ReservedCodeCacheSize=40M
                      -XX:MaxMetaspaceSize=60M
                      -Xlog:gc
                      -Xms34m
                      -Xmx40m
                      -Xss256k
                      -XX:MaxRAM=150M
      
      

      Spring boot 存储库中有一个 GitHub 问题在讨论这个 Failed to change JVM arguments for buildpacked image

      【讨论】:

        猜你喜欢
        • 2021-03-31
        • 2021-05-15
        • 2021-12-04
        • 2022-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-17
        • 2021-09-08
        相关资源
        最近更新 更多