I am using azul/zulu-openjdk-distroless:17.0.6 image and want to execute the java command with parameters but it fails at the runtime
Here is my docker image:
FROM alpine:3.17.3 as build-env
ARG DATADOG_VERSION=1.8.3
RUN wget https://github.com/DataDog/dd-trace-java/releases/download/v${DATADOG_VERSION}/dd-java-agent-${DATADOG_VERSION}.jar
FROM azul/zulu-openjdk-distroless:17.0.6
COPY --from=build-env dd-java-agent-*.jar javaagent.jar
COPY *-app/target/*.jar app.jar
ARG JAVA_AGENT="-javaagent:javaagent.jar"
CMD ["${JAVA_AGENT}", "-jar", "app.jar"]
I get the following error when I run it:
Error: Could not find or load main class ${JAVA_AGENT}
Caused by: java.lang.ClassNotFoundException: ${JAVA_AGENT}
I tried with ENV instead of ARG and ENTRYPOINT instead of CMD, none of them worked. I tried without the [] brackets but then I get another error:
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory: unknown.
If I put the value directly like CMD ["-javaagent:javaagent.jar", "-jar", "app.jar"] then it works but the container runs in a pipeline where the variable's value is coming from so I want to use variable. I would also use another one for JAVA_OPTS which is much harder to hardcode.
Is there any possibility to solve it somehow or the only solution is to hardcode the parameters?
Java 17 supports a
JDK_JAVA_OPTIONSenvironment variable to supply additional command-line options to the JVM. If you set this as an environment variable, you can override it when you run the image, and DockerfileENVto set it does do basic environment replacement.Note that
docker run -e JDK_JAVA_OPTIONS=...and other similar settings complely replace the preƫxisting value of this variable, so you'd have to repeat the-javaagent:...option.There are two forms of
CMD(andENTRYPOINTandRUN). Exec form uses the JSON-array syntax, but never does any sort of variable expansion or other processing; the list of strings in the JSON array is used directly as the list of words making up the command and its arguments. Shell form takes any string but is run through/bin/sh -c, and that shell does the expansion. If you have both anENTRYPOINTand aCMDthen both parts are separately wrapped insh -cif required, then combined together into a single command line.This combination of things puts several non-obvious restrictions on variable expansion. In your case, variable expansion requires a shell; Docker on its own does not replace environment variables in
CMDat all. Since your distroless image doesn't contain a shell, this won't work.The other implication of this rule is that, if you are using a shell-form
CMDto do variable expansion, it must be a complete shell command. In your case it looks like the base image declares aENTRYPOINT ["java"]; if you try to use a shell-formCMDthen the container will runjava sh -c '...'which will produce an unusual error (admittedly, not the one you're actually seeing).If you're passing this parameter as a command-line option in a distroless image, you have to hard-code it in the
CMD. You might be able toCOPYa non-fixed file intojavaagent.jar, so the filename will be fixed and the command-line option can be constant, but the contents of the file may not be.