1

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

5
  • why dont you just use environment variables? Commented Mar 26 at 18:40
  • you dont need to do anything at the dockerfile, you just provide the environment variables and it works. 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 Commented Mar 26 at 18:56
  • yes, you can do that. System.getenv("TEST_JAVA_TOOL_OPTIONS") 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 Commented Mar 26 at 19:24

2 Answers 2

1

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 }}
Sign up to request clarification or add additional context in comments.

2 Comments

David, hello! Thank you for your answer. I am sure it will work because I tried the same at initial stage with splitList but. How do you think there is no the other way to do it without splitting and ranging? I am afraid it would be not okay for optimization. Maybe it's okay for single application but if we are talking about bulk deploy (more then I dont know..50 application) it can take some time to parse and range just to prepare arguments
You're just doing a simple O(n) loop over a list and doing basic string manipulation; compared even with the cost of sending the rendered Kubernetes manifest to the API server, this is basically free (doubly so on modern hardware).
0

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 the args 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.

5 Comments

Undortunatelly this way of solution doesnt work :( I did what you mensioned but still have the same issue with Improperly specified VM option
How does it not work? What is the error you're getting here?
Error in my logs still the same: Improperly specified VM option 'UseSerialGC -Xmx256m -XX:MetaspaceSize=64m' Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit I did what you mentioned: changed quotation and seperated comman and args. It was almost like 'copy and past' and still doesnt work
The Java option has a + in it. Try -XX:+UseSerialGC. download.java.net/java/early_access/loom/docs/specs/man/…
Of course I did. All the values are the same as I wrote above: TEST_JAVA_OPTS = "-XX:+UseSerialGC" TEST_JAVA_MEMORY_OPTS = "-Xmx256m -XX:MetaspaceSize=64m". I believe it takes the 1st one specified in args sees '-XX' remove it and thinks that entire string it's an option. UPD: thank you for noticement, there was a typo in my description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.