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.
Related
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
SO I am trying to change the JVM heap memory percentage
I have added these two lines in my Dockerfile
ENV JAVA_OPTS="--XX:MinRAMPercentage=50.0 --XX:MaxRAMPercentage=80.0"
CMD ["--spring.profiles.active=${profile}","${JAVA_OPTS}"]
But when I check this command:(java -XX:+PrintFlagsFinal -version | grep -E "UseContainerSupport | InitialRAMPercentage | MaxRAMPercentage | MinRAMPercentage") on my docker container, it shows default values of the above parameter:
No environment variable expansion or other processing is done on exec form CMD (or ENTRYPOINT or RUN). Your application is getting invoked with literally the strings --spring.profiles.active=${profile} and ${JAVA_OPTS}, and you will see these including the ${...} markers in your Java program's main() function.
Docker's normal assumption here is that any expansion like this will be done in a shell, and shell form CMD will wrap its string in /bin/sh -c '...' so this happens. However, this setup isn't compatible with splitting ENTRYPOINT and CMD: due to the mechanics of how the two parts are combined neither part can be wrapped in a shell if you're using the "container as command" pattern where the CMD is just an argument list.
The easiest way to handle this is to ignore ENTRYPOINT entirely; put all of the command and arguments into CMD; and use the shell form rather than the exec form.
ENV JAVA_OPTS="--XX:MinRAMPercentage=50.0 --XX:MaxRAMPercentage=80.0"
# no ENTRYPOINT; shell form of CMD
CMD java ${JAVA_OPTS} -jar /app/app.jar --spring.profiles.default=${profile}
If you docker run a temporary debugging container on this image, it will see the environment variable but the command you provide will replace the image's CMD.
docker run --rm your-image \
/bin/sh -c 'echo $JAVA_OPTS'
# prints the environment setting
Correspondingly if you run a separate java, it won't see the options that are only provided in the image's CMD. (Similarly try running java -XX:MaxRamPercentage=80.0 in one terminal window, and java -XX:+PrintFlagsFinal with no other options in another window, and the second invocation won't see the JVM options from the first JVM; the same mechanics apply to Docker containers.)
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.
I am trying to run ignite in a Docker container (Mac OS X, Docker 1.9.1) as committed in git:
# Start from a Java image.
FROM java:7
# Ignite version
ENV IGNITE_VERSION 1.5.0-b1
WORKDIR /opt/ignite
ADD http://www.us.apache.org/dist/ignite/1.5.0-b1/apache-ignite-fabric-1.5.0-b1-bin.zip /opt/ignite/ignite.zip
# Ignite home
ENV IGNITE_HOME /opt/ignite/apache-ignite-fabric-1.5.0-b1-bin
RUN unzip ignite.zip
RUN rm ignite.zip
# Copy sh files and set permission
ADD ./run.sh $IGNITE_HOME/
RUN chmod +x $IGNITE_HOME/run.sh
CMD $IGNITE_HOME/run.sh
After building it locally to apache/ignite and running the image with following command, the container 'hangs'
docker run --expose=4700-4800 -it -p 47500-47600:47500-47600 -p 47100-47200:47100-47200 --net=host -e "CONFIG_URI=https://raw.githubusercontent.com/apache/ignite/master/examples/config/example-default.xml" apacheignite/ignite-docker
When connecting to the container (docker exec -ti apache/ignite /bin/bash) and running the command in verbose mode via bash, it hangs on org.apache.ignite.startup.cmdline.CommandLineRandomNumberGenerator:
bash -x /opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/bin/ignite.sh https://raw.githubusercontent.com/apache/ignite/master/examples/config/example-default.xml
Output where it hangs:
+ CP='/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-indexing/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-spring/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/licenses/*'
++ /usr/bin/java -cp '/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-indexing/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/ignite-spring/*:/opt/ignite/apache-ignite-fabric-1.5.0-b1-bin/libs/licenses/*' org.apache.ignite.startup.cmdline.CommandLineRandomNumberGenerator
Looking at the code of CommandLineRandomNumberGenerator, I don't see anything special, just one line to generate a UUID. Are there other things that are automatically started somehow that causes locking a threat so that the application cannot exit?
This seems to be a docker issue with java in general, see also:
https://github.com/docker/docker/issues/18180
Several solutions possible:
create a docker machine as follows and run it in here (cfr. https://github.com/docker/docker/issues/18180#issuecomment-162568282):
docker-machine create -d virtualbox --engine-storage-driver overlay overlaymachine
Add System.exit(0) explicit at the end of each main method (cfr. https://github.com/docker/docker/issues/18180#issuecomment-161129296)
Wait for next docker patched version (https://github.com/docker/docker/issues/18180#issuecomment-170656525)
I think it would be good practice (for now) to add System.exit to all main methods in Ignite since this is independent of alternative hacks on docker or linux in general (linux kernel need AUFS upgrade and many machine may lag behind before that). This way future Ignite version can safely be installed on older kernels also.
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.