I would like to optimize my docker image using jib.
I have been using a Dockerfile like this:
FROM openjdk:8-jdk
ARG NAME
ADD $NAME app.jar
VOLUME /tmp
VOLUME /certificates
ENTRYPOINT exec java $JAVA_OPTIONS -jar app.jar
Now I am creating the image with mvn compile jib:dockerBuild but would like to know how to add the JAVA_OPTIONS to my application as I did in the past in the ENTRYPOINT of my old Dockerfile.
Thanks in advance
I assume that you are dynamically supplying an environment variable for some Java flags at runtime and you want your JVM to pick up the flags at runtime. (If your intention is to statically set the flags and bake them into the container image at image build-time, it should be done in a different way.)
Just set the desired flags in JAVA_TOOL_OPTIONS or JDK_JAVA_OPTIONS if Java 9+. Your JVM will automatically pick them up (although not all Java flags may not be supported with JAVA_TOOL_OPTIONS).
Related
For context, I'm building a java application compiled to GraalVM native image running on a distroless docker image in Kubernetes.
I've been trying to do something rather simple and hit a wall: I'd like to set custom heap size limits per environment via -XmxNNN. To do that, the options with which I'd like to run the application would be held in an environment variable. The problem arises due to the usage of a distroless image - which doesn't have bash and so ENTRYPOINT /application $OPTIONS doesn't work.
Is there an environment variable GraalVM supports on its own, or any other way of setting this?
I dont want to:
hardcode the values in the Docker image
hardcode the values by predefining them during native-image build
You could use busybox to get a shell inside a distroless container:
FROM gcr.io/distroless/base
...
COPY --from=amd64/busybox:1.31.1 /bin/busybox /busybox/busybox
RUN ["/busybox/busybox", "--install", "/bin"]
CMD ["/bin/sh", "-c", "java -version"]
You can find an example to this kind of Dockerfile here.
But I don't think this busybox shell is necessary needed.
Altough ENTRYPOINT /application $OPTIONS does not work, this will work ENTRYPOINT ["myapp", "arguments"]
Note that distroless images by default do not contain a shell. That means the Dockerfile ENTRYPOINT command, when defined, must be specified in vector form, to avoid the container runtime prefixing with a shell.
source: github
I'm not sure if it will work, but you could try setting the environment variable JAVA_TOOL_OPTIONS to the desired value:
JAVA_TOOL_OPTIONS=-XmxNNN
From the documentation:
This environment variable allows you to specify the initialization of
tools, specifically the launching of native or Java programming language
agents using the -agentlib or -javaagent options. In the following example
the environment variable is set so that the HPROF profiler is launched when > the application is started:
$ export JAVA_TOOL_OPTIONS="-agentlib:hprof"
This variable can also be used to augment the command line with other
options for diagnostic purposes. For example, you can supply the
-XX:OnError option to specify a script or command to be executed when a
fatal error occurs.
The GraalVM documentation itself provides an example of use as well, although in a different context.
Good day everyone.
I have a simple java-based cucumber application, that runs in Docker. I planing to specify which scenarios to run by using ENV for Cucumber tags.
My Dockerfile that able to run specified tags:
FROM maven:3.6.1-jdk-11
COPY target/cucumber-app.jar ./
CMD java -jar -Dcucumber.options='--tags #default' cucumber-app.jar
In this case, during docker run command all works perfectly.
I plan to set up a default scenario for not specified Tags and ability to set up special scenarios through ENV:
FROM maven:3.6.1-jdk-11
COPY target/cucumber-app.jar ./
ENV TAG '--tags #default'
CMD java -jar -Dcucumber.options=$TAG cucumber-app.jar
Unfortunately in this case after running docker container I got:
Error: could not open `default'
Possible you have any ideas why using ENV crash possibility to specify cucumber.options?
If you have a recent version of Cucumber rather then trying to squeeze command line options in through a system property via an environment variable, you can set the environment variable straight away. I.e:
ENV CUCUMBER_FILTER_TAGS '#Cucumber and not (#Gherkin or #Zucchini)'
CMD java -jar cucumber-app.jar
https://github.com/cucumber/cucumber-jvm/tree/main/core
I have a child image where I'm defining
ARG MX_HEAP_SET=1024
ARG MN_HEAP_SET=1024
ENV MX_HEAP_SET=${MX_HEAP_SET:-${MX_HEAP_SET}}
ENV MN_HEAP_SET=${MN_HEAP_SET:-${MN_HEAP_SET}}
ENV HEAP_SET="-Xmx${MX_HEAP_SET}m -Xms${MN_HEAP_SET}m"
ENV HEAP_SET=${HEAP_SET:-${HEAP_SET}}
and expecting to replace the default value of HEAP_SET which is placed in base image.
So, when I run the base image without any MX or MN value, then it works fine.
However as soon as I run the child image with docker run -e MX_HEAP_SET=2048, I still see the default value in container.
But as soon as I run docker run -e HEAP_SET="-Xmx2048m -Xms1024m" i see the change.
So, how can I implement same behavior with individual MAX and MIN parameters not as a string?
Is there other way to achieve this?
When you use below
ARG MX_HEAP_SET=1024
It means you are adding a build time argument. This can be overridden only during the docker build. What you need is rather startup bash file
/app/start.sh
#!/bin/sh
# export all variables from here on
set -a
MX_HEAP_SET=${MX_HEAP_SET:-1024}
MN_HEAP_SET=${MN_HEAP_SET:-1024}
MX_HEAP_SET=${SDC_MX_HEAP_SET:-${MX_HEAP_SET}}
MN_HEAP_SET=${SDC_MN_HEAP_SET:-${MN_HEAP_SET}}
HEAP_SET="-Xmx${MX_HEAP_SET}m -Xms${MN_HEAP_SET}m"
HEAP_SET=${HEAP_SET:-${HEAP_SET}}
exec "<yourstarting command>" $#
This will respect the environment variables the you give while running the image itself
But you need to make sure override your ENTRYPOINT or CMD to run /app/start.sh
exec is used in the end to make sure the running program replaces the shell process with itself
I am trying to integrate a javaagent for application monitoring. I'm using docker and I've setup an OpenJDK base image which is inherited by other application images.
Since javaagent requires a path to the jar file, for maintenance purposes I've defined the path in the base image as another env variable(AGENT_PATH) and I want to reuse the same env variable across all my app images. For some reason the environment variable isn't picked and the application container exits with error.
Base Image's Dockerfile
AGENT_PATH=/agent/agent.jar
This is how I've configured JAVA_TOOL_OPTIONS in application's Dockerfile.
JAVA_TOOL_OPTIONS="-javaagent:$AGENT_PATH + other JVM options"
This is the error message
Picked up JAVA_TOOL_OPTIONS: -javaagent:$AGENT_PATH
Error opening zip file or JAR manifest missing : $AGENT_PATH
Error occurred during initialization of VM
agent library failed to init: instrument
Why is AGENT_PATH not getting substituted properly ?
I've grepped through Hotspot implementation for understanding. I've found this.
This will depend on the Docker step. If you use RUN step the variables processing is not supported:
Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, RUN [ "echo", "$HOME" ] will not do variable substitution on $HOME. If you want shell processing then either use the shell form or execute a shell directly, for example: RUN [ "sh", "-c", "echo $HOME" ]. When using the exec form and executing a shell directly, as in the case for the shell form, it is the shell that is doing the environment variable expansion, not docker.
In dockerfiles, all directives require a certain codeword. Assigning an environment variable is no different from this and needs the ENV codeword (read here).
Using this, the excerpt of your dockerfile should read
ENV AGENT_PATH=/agent/agent.jar
I was facing the same issue where the environment variables set in the JAVA_TOOL_OPTIONS were not getting substituted. So I had to mention those variables as -D parameters along with java command.
java -Djavax.net.ssl.keyStorePassword=$KeyStore_Secret .....
You can check if that is the case by hardcoding the values in the JAVA_TOOL_OPTIONS and it should work. Meanwhile, I am still looking at the reason for this.
I am wondering if is possible to do the following...
I have a small application in java (and gradle)
I am trying to set it in a container, so I created the Dockerfile and worked fine UNTIL I have to set a parameter.
To run it locally on my IDLE I set these program arguments:
server application-local.yml
That actually loads a file with many properties, without this the app will fail.
On my Dockerfile I have this
FROM openjdk:8-jdk-alpine
USER root:root
ENV NAME test
LABEL maintainer="myself"
WORKDIR /opt/apps
COPY build/libs/myapp.jar /opt/apps/myapp.jar
EXPOSE 8080
CMD ["java", "myapp.jar"]
I was wondering if I could do the following:
CMD ["java", "-server:application-local.yml", "myapp.jar"]
but doesnt work, also I cannot do
java -jar myapp.jar -server:application-local.yml
simply doesnt do anything
Dont wanna do a gradleBuild because it is supposed to use java only at my docker image...
Any idea how to do this?
Edit:
So, I have done the following, move my application-local.yml to a folder I can copy and added this
COPY some-path/application-local.yml /opt/apps/local.yml
and moved the CMD for this
CMD ["java", "myapp.jar", "server", "local.yml"]
I still get the same error, basically cannot resolve the values from that yml file.
EDIT 2 ---
Basically what I cannot do is to figure out how to send the application.default.yml as configuration file, I realise also that the -server does not anything, is my config file the one I cannot load and is not present in the jar (normal behaviour)
When using the java command, order of the arguments matter
First you put the java options, like -server, then the -jar ... Or the class name in the case of running classes directly, and then the application arguments
The proper way to run your app is:
CMD ["java", "-jar", "myapp.jar", "server", "application-local.yml"]
Then you have another problem, you are only copying the final jar file to your docker container, so it can can't find the application-local.yml file, copy this also to your docker container
COPY build/libs/application-local.yml /opt/apps/application-local.yml