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
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
Share Improve this question edited Mar 26 at 18:19 Disteonne asked Mar 26 at 13:39 DisteonneDisteonne 893 silver badges12 bronze badges 5- why dont you just use environment variables? – muzzletov Commented Mar 26 at 18:40
- you dont need to do anything at the dockerfile, you just provide the environment variables and it works. – muzzletov Commented Mar 26 at 18:46
- @muzzletov Hello) Let's assume there are requirements to use env variables that are different from original like JDK_JAVA_OPTIONS or JAVA_TOOL_OPTIONS – Disteonne Commented Mar 26 at 18:56
- yes, you can do that. System.getenv("TEST_JAVA_TOOL_OPTIONS") – muzzletov Commented Mar 26 at 19:20
- @muzzletov, yes, I can technically. But that is not a case for me here. I am trying to figure out how to do that with “one string” variables notation with kubernetes – Disteonne Commented Mar 26 at 19:24
2 Answers
Reset to default 0In 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 }}
According to the Kubernetes docs, split the command array and the arguments array into command
and args
sections.
When you create a Pod, you can define a command and arguments for the containers that run in the Pod. To define a command, include the
command
field in the configuration file. To define arguments for the command, include theargs
field in the configuration file. The command and arguments that you define cannot be changed after the Pod is created.The command and arguments that you define in the configuration file override the default command and arguments provided by the container image. If you define args, but do not define a command, the default command is used with your new arguments.
spec:
containers:
- name: test-java-service
image: <your_image_name_here>
command:
- java
args:
- {{ .Values.TEST_JAVA_MEMORY_OPTS | quote }}
- {{ .Values.TEST_JAVA_OPTS | quote }}
- "-jar"
- java_j.jar
When Helm populates values, don't specify the quotes yourself, or else the values replacement string will be interpreted literally as that string. Instead, pipe the Helm value to quote
. Place quotes around any value that could be interpreted specially in YAML, such as values with -
characters, like your Java options.