JAVA_OPTS ineffective to set the -Xmx in a Java Docker image? - java

my understanding is that the maximum amount of Java memory in a Docker container depends on the Docker constraints and the JVM settings. However, the only change I can see in the Max Heap Size depends on the docker --memory parameter.
For example, here I'm starting a Java program (openjdk17) that prints the Max memory settings:
docker run -it -e JAVA_OPTS="-Xmx1g" --memory 2g javatest
Max Heap Size = maxMemory() = 536870912
Same, changing the JAVA_OPTS:
docker run -it -e JAVA_OPTS="-Xmx64mb" --memory 2g javatest
Max Heap Size = maxMemory() = 536870912
The Dockerfile:
FROM openjdk:17
COPY ./Example.class /tmp
WORKDIR /tmp
ENTRYPOINT ["java","Example"]
Is there any other env var that I can use to set the Max memory ?

I think the only way to make it work is to rewrite your ENTRYPOINT to include the JAVA_OPTS env variable. For example:
FROM openjdk:17
COPY ./Example.class /tmp
WORKDIR /tmp
ENTRYPOINT exec java $JAVA_OPTS Example

Related

JVM Heap Size Docker

I'm strugling trying to set the Heap size insise a docker container, I'm aware of similar questions but non of them seams to work for me, I'm sure I'm missing something.
My docker file look like this:
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/spring-boot-web.jar
WORKDIR /opt/app
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java" , "-XX:+UseContainerSupport" , "-XX:MaxRAMPercentage=50.0", "-XshowSettings" ,"-jar","app.jar"]
When I build and execute the image above with the following command:
docker run -m 2G -p 8080:8080 -t springtest
I get te following information due to -XshowSettings:
VM settings: Max. Heap Size (Estimated): 910.50M
After a few seconds my app start without a problem and then I decide to fetch information about the JVM inside the container with the command docker exec MyContainerId java -XshowSettings and I it prints :
VM settings: Max. Heap Size (Estimated): 455.50M
It's clear that the container start with 50% of Max Ram but after the app starts it reduces to the default (25%)
Maybe I have a wrong understanding of JVM and containers, can some one point me to the right direction.
Thank you.

How to pass Java options/variables to Springboot app in docker run command

I have a Spring Boot application which uses profiles to configure in different environments. I want to pass this profile information as a parameter to my docker run command. How do I go about doing it?
Here is my dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/demo-app-1.0-SNAPSHOT.jar
COPY ${JAR_FILE} /opt/lib/demo-app.jar
EXPOSE 80
# ENTRYPOINT ["java","-Dspring.profiles.active=dockerdev","-jar","/opt/lib/demo-app.jar"]
# Above line works, but not desired as profile will change in diff envs
ENTRYPOINT ["java","-jar","/opt/lib/demo-app.jar"]
I have tried the following, but, none works
docker run -p 8000:80 demo-app -Dspring.profiles.active=dockerdev
docker run -p 8000:80 demo-app --rm -e JAVA_OPTS='-Dspring.profiles.active=dockerdev'
Please help.
Clarification: I am using multiple profiles. Hence I do not want the active profile to be mentioned within the application or the docker file. Instead, I want to use the same application and docker file and run it in different environments, and pass the active profile to be used in the docker run command. Apologies if anything above did not clarify that.
Solution 1
You can override any property from your configuration by passing it to docker container using -e option. As explained in Externalized configuration the environment variable name should be uppercased and splitted using underscore. So for example to pass spring.profiles.active property you could use SPRING_PROFILES_ACTIVE environment variable during container run :
docker run -p 8000:80 -e SPRING_PROFILES_ACTIVE=dockerdev demo-app
And this variable should be picked automatically by Spring from environment.
Solution 2
Change Dockerfile to :
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/demo-app-1.0-SNAPSHOT.jar
# environment variable with default value
ENV SPRING_PROFILE=dev
COPY ${JAR_FILE} /opt/lib/demo-app.jar
EXPOSE 80
#run with environment variable
ENTRYPOINT java -Dspring.profiles.active=$SPRING_PROFILE jar /opt/lib/demo-app.jar
and then run the container passing the environment variable :
docker run -p 8000:80 --rm -e SPRING_PROFILE=dockerdev demo-app
Make use of application.properties in springboot to override any variables from outside. We heavily use this in our production environments.
You need to:
Change your ENTRYPOINT to:
ENTRYPOINT ["java","-jar","/opt/lib/demo-app.jar","--spring.config.additional-location=/application.properties"]
Create application.properties file with contents:
spring.profiles.active=dockerdev
You can also override any variables used in your springboot code using application.properties and can also override springboot specific variables as mentioned here.
Also change your docker run command to:
docker run -itd -v /path/to/application.properties:/application.properties image-name
So that application.properties from your host will get mounted
inside your docker container.
NOTE: If --spring.config.additional-location don't works then try --spring.config.location option.
Hope this helps.
JAVA_TOOL_OPTIONS maybe the right answer.
docker run -p 8000:80 -e JAVA_TOOL_OPTIONS='-Dspring.profiles.active=dockerdev' demo-app
People who are looking for the answer for non Spring (Plain Java Applications)
This is how to send System properties/arguments: Change the Dockerfile to
FROM openjdk:8-jdk-alpine
COPY target/demo-app-1.0-SNAPSHOT.jar demo-app.jar
EXPOSE 8080
ENTRYPOINT java -jar demo-app.jar
Build the image:
docker build -t demo-app .
Then run the docker container using following command:
docker run -e "JAVA_TOOL_OPTIONS=-Xms1024m -Xmx2048m -Dspring.profiles.active=dockerdev" -p 8080:8080 demo-app
you have to provide the JAVA_OPTS inside the docker file, example of a docker file is below.
FROM {{ env "DOCKER_REGISTRY" }}/asdf/osX-jre8:{{ env "BASE_IMAGE_VERSION" }}
ADD target/yourapp.jar /app.jar
#Environment vars
ENV NO_PREFIX true
ENV APP_NAME "xxx"
ENV APP_UUID "81b35e09-2a10-48c3-a091-xxxxxxxxx"
ENV HEALTH_CHECK_URL http://localhost:9000/health
ENV SERVICE_PORT 8080
ENV JAVA_OPTS "-Dsun.net.client.defaultConnectTimeout=2000 -Dsun.net.client.defaultReadTimeout=20000 -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/alloc/logs"
You should add the env variable JAVA_OPTS to your Dockerfile
FROM tomcat:8.5.47-jdk8-openjdk
LABEL build_date="2020-07-14" \
name="Ousama EL IDRISSI" \
version="1.0" \
description="Docker Image made by la7ya"
EXPOSE 8080
COPY ./target/la7yaman-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war
ENV JAVA_OPTS="-Dspring.profiles.active=docker-demo"
CMD ["catalina.sh", "run"]

How to set heap size for wildfly inside Docker container?

I am trying to increase heap size for wildfly in docker container. This is easily done by updating wildfly/bin/standalone.conf in a regular wildfly setup.
Our base docker image for wildfly has a default heapsize of 512 MB which is required to be 1GB in one of the web apps. One way to go is by simple text replace in the Docker file using sed command -
RUN sed -i -- 's/JAVA_OPTS="-Xms64m -Xmx512m -XX:MaxPermSize=256m/JAVA_OPTS="-Xms2048m -Xmx6144m -XX:MaxPermSize=256m/g' /path/standalone.conf
I wanted to know if there's another (cleaner) way to solve this?
When using docker-compose set environment variable as follows!
environment:
- JAVA_OPTS=-server -Xms512m -Xmx2048m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -XX:+UseAdaptiveSizePolicy -XX:MaxMetaspaceSize=1024m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true-Djava.net.preferIPv4Stack=true
do not use " (quotes)!
You can pass the value of the JAVA_OPTS environment variable in the command used to run the docker container:
docker run -it --env JAVA_OPTS="-server -Xms2048m -Xmx6144m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true" jboss/wildfly
Alternatively, you can extend the standard image by creating a Dockerfile containing:
FROM jboss/wildfly:latest
COPY standalone.conf $JBOSS_HOME/bin/
and placing your modified standalone.conf in the directory next to it.
Then you can build it:
docker build -t my/wildfly:latest .
and run it:
docker run my/wildfly
I suggest you to use JAVA_TOOL_OPTIONS rather than JAVA_OPTS .Because JVM directly understand JAVA_TOOL_OPTIONS.
I haven't tried it myself, but there is now (at least WF26) a variable JBOSS_JAVA_SIZING in standalone.conf, used as a subpart of JAVA_OPTS.
if [ "x$JBOSS_JAVA_SIZING" = "x" ]; then
JBOSS_JAVA_SIZING="-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m"
fi
if [ "x$JAVA_OPTS" = "x" ]; then
JAVA_OPTS="$JBOSS_JAVA_SIZING -Djava.net.preferIPv4Stack=true"
...
So you should be able to rewrite it through docker environment variables.

How to pass System property to docker containers?

So I know you can pass Environment variables to a docker container using -e like:
docker run -it -e "var=var1" myDockerImage
But I need to pass a System Property to a docker container, because this is how I run my JAR:
java -Denvironment=dev -jar myjar.jar
So how can I pass a -D System property in Docker? Like:
docker run -it {INSERT Denvironment here} myDockerImage
Use the variable you passed into the container on the java command:
docker run -it -e "ENV=dev" myDockerImage
java -Denvironment=$ENV -jar myjar.jar
One more way to do it, if running under Tomcat, is setting your system variables in your Dockerfile using ENV JAVA_OPTS like this:
ENV JAVA_OPTS="-Djavax.net.ssl.trustStore=C:/tomcatDev.jks -D_WS_URL=http://some/url/"
Hope it helps!
One can also use the following start.sh ENTRYPOINT for the Docker container, make sure to use the array syntax, e.g.:
Dockerfile:
...
ENTRYPOINT ["/start.sh"]
The actual start.sh script:
#!/bin/bash
export JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64"
exec $JAVA_HOME/bin/java -jar myjar.jar $#
Then you can just pass the Java system properties directly to your application as docker run container arguments:
docker run myDockerImage "-Dvar=var1"
Have a start.sh file, e.g.:
#!/usr/bin/env sh
exec java -Djava.security.egd=file:/dev/./urandom $* -jar /app.jar
In your Dockerfile:
...
COPY start.sh /start.sh
RUN chmod a+rx /start.sh
ENTRYPOINT ["/start.sh"]

TOMCAT 7, Can't change the heap size

I Have set the heap size of tomcat 7 by adding boot script:
export CATALINA_OPTS="-Xms1024m -Xmx248m"
I change /etc/init.d/tomcat7 :
if [ -z "$JAVA_OPTS" ]; then
JAVA_OPTS="-Djava.awt.headless=true -Xmx2048M -Xms1024M"
fi
I Reboot the computer and restart the Tomcat:
service tomcat7 restart
And verify the $CATALINA_OPTS Works:
> echo $CATALINA_OPTS
-Xms1024m -Xmx2048m
But when I go to the tomcat manager, I note that the heap has not changed.
Free memory: 38.02 MB Total memory: 123.75 MB Max memory: 123.75 MB
Please, i need help about this.
Check the setenv.sh in tomcat/bin, according to manual this should be the right place to put those params.
Another option, it depend on your OS tomcat package, may be that config param are overrided in /etc/conf.d/tomcat/ or /etc/tomcat. Just check your init script and your catalina.sh to find where your settings are overrided.
Btw if you run a ps -ef | grep tomcat you should see the full command line with arguments: this may give you an idea of how init script build the command, and so you can investigate where params are set.
Have you tried creating a setenv.sh script in the $CATALINA_HOME/bin directory with your options in it?
I find that setting JAVA_OPTS="-Xmx2048m -Xms1024m" in there works pretty well.

Categories

Resources