【发布时间】:2020-09-03 09:41:16
【问题描述】:
我正在尝试使用最新版本的 Spring Boot (2.3.0) 构建 docker 映像。我现在必须创建一个映像,只需运行命令 mvn:spring-boot:build-image 。这将为我创建一个泊坞窗图像。在这种情况下如何设置 JVM 参数(最大、最小堆大小)?
【问题讨论】:
标签: spring spring-boot docker jvm
我正在尝试使用最新版本的 Spring Boot (2.3.0) 构建 docker 映像。我现在必须创建一个映像,只需运行命令 mvn:spring-boot:build-image 。这将为我创建一个泊坞窗图像。在这种情况下如何设置 JVM 参数(最大、最小堆大小)?
【问题讨论】:
标签: spring spring-boot docker jvm
这些答案都不完全正确。这是撰写本文时的全部情况。
重要的是要了解代码运行的两个不同时间:构建时和运行时。
您可以在构建时使用 Spring Boot 在 Maven 或 Gradle 配置中设置环境变量。您只需给它一个要设置的环境变量列表。见这里https://docs.spring.io/spring-boot/docs/2.3.x/maven-plugin/reference/html/#build-image-customization。 这些只会在构建时设置。不是你想要设置的东西,比如-Xmx。
如果你想在运行时设置环境变量,那么它不是 Spring Boot 或 buildpacks 可以控制的。两者都不是失败,只是两者都没有参与实际运行您的应用程序映像/容器。
要在运行时将 env 变量传递给您的应用映像/容器,您需要使用运行应用映像的任何工具,例如 Docker 或 Kubernetes。对于 Docker,它只是 docker run -e foo=bar ...。对于 Kubernetes,它位于 pod spec。
仅供参考。任何以 BPL_ 为前缀的 env 变量意味着它仅在运行时应用(L 用于启动,这就是 buildpack 所称的运行时环境)。因此,只有在您的应用运行时设置它们才有意义。
其他答案中提到的environment variables buildpack 是两者的混合体。如果您使用上面的选项 #1 设置 env 变量但以某种方式添加前缀,则此 buildpack 将看到它们并将它们转换为嵌入到图像中的 env 变量。这将具有在运行时设置它们的效果。
如果您想在图像上设置默认值,这很有效。然后您的图像的用户不需要设置它们,除非他们需要偏离默认值您,图像作者设置。话虽如此,您永远不会想将它用于任何敏感或秘密的事情。这是因为 env 变量和值最终出现在图像中,因此任何有权访问图像的人都可以看到该值。
回答问题:
在这种情况下如何设置 JVM 参数(最大、最小堆大小)?
如果您想设置图像用户可以根据需要覆盖的默认值,那么您需要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
如果您想设置这些值,那么只需在运行时设置它们。例如: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。
【讨论】:
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 会承认(我同意这可能有点令人困惑),但它不会对它们做任何事情。您需要在启动时进行设置。
正如@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 中)。
【讨论】:
我在 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()。
【讨论】:
截至今天,您无法在 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
【讨论】: