I am working with Java application and I’m going to deploy it within container. I have prepared Dockerfile with
ENTRYPOINT ["java", "-jar", "java_j.jar"]
in my Java application. I have prepared some helm charts too.
Is it possible to use only one variable to specify all Java options interested by me in it to use it within container.args (Deployment.yaml)?
{root}/values.yaml:
TEST_JAVA_OPTS = "-XX:+UseSerialGC"
TEST_JAVA_MEMORY_OPTS = "-Xmx256m -XX:MetaspaceSize=64m"
{root}/templates/Deployment.yaml
{root}/templates/Deployment.yaml
...
spec:
containers:
- name: test-java-service
command:
- java
- '{{ .Values.TEST_JAVA_MEMORY_OPTS }}'
- '{{ .Values.TEST_JAVA_OPTS }}'
- -jar
- java_j.jar
...
For now it doesn’t work to me because each my application startup failes with Improperly specified VM option
. I guess it tries to give java entire string as one java option. That is wrong of course.
My purpose is to avoid a lot of variables for each java option and to let change it in Deployment directly (I know that there is a possibility to set environment variables in Dockerfile at ENTRYPOINT part but let assume this option is disabled for us)
Kubernetes version: 1.28.12
In your Helm chart, you need to split out the different low-level JVM settings into individual items in the command:
list. The easiest way to do this is to make the Helm-level settings be a list of options, and then you can iterate over it.
# values.yaml
jvmOptions:
- -XX:UseSerialGC
- -Xmx256m
- -XX:MetaspaceSize=64m
# templates/deployments.yaml
command:
- java
{{- range .Values.jvmOptions }}
- {{ toJson . }}
{{- end }}
- -jar
- java_j.jar
Since .Values.jvmOptions
is a list here, the template range
construct loops through it, setting .
to each item in turn. In the example here, I use the toJson
extension function to ensure each item is properly quoted as a string that fits on a single line.
Nothing would stop you from having multiple lists of option settings that you combined this way.
If you really want the JVM options as a space-separated string, then you need to split that string into words. There is a splitList
extension function (not mentioned in the Helm documentation but it's there) that can do this.
# values.yaml
jvmOptions: "-XX:UseSerialGC -Xmx256M -XX:MetaspaceSize=64m"
# templates/deployments.yaml
command:
- java
{{- range splitList " " .Values.jvmOptions }}
- {{ toJson . }}
{{- end }}
- -jar
- java_j.jar
The template part looks almost identical except for adding splitList
in. Note that this is a fairly naïve splitting; there's not going to be any support for quoting or embedding spaces inside a single option or any non-space whitespace.
Finally: note that the standard JVMs do support passing options in environment variables; see for example What is the difference between JDK_JAVA_OPTIONS and JAVA_TOOL_OPTIONS when using Java 11? You could just set this environment variable without trying to reconstruct command:
. (IME if you have a choice, managing Kubernetes manifests tends to be easier if you can set environment variables as opposed to using command-line options.)
# values.yaml
jvmOptions: "-XX:UseSerialGC -Xmx256M -XX:MetaspaceSize=64m"
# templates/deployments.yaml
env:
{{- with .Values.jvmOptions }}
- name: JDK_JAVA_OPTIONS
value: {{ toJson . }}
{{- end }}