Home > Software engineering >  How can i change heap size when i use docker-compose and dockerfile to create a javaproject?
How can i change heap size when i use docker-compose and dockerfile to create a javaproject?

Time:10-27

I wanna use docker-compose to scale heap size when i need, i failed, i need your help, please!!!

  • Dockerfile :
FROM openjdk:8-jdk
MAINTAINER whywhathow([email protected])
ENV \
JVM_GC="UseParallelGC"\
JVM_XMS="128m" \
JVM_XMX="256m"  \
NACOS_ADDR="127.0.0.1:8848" \
JAVA_OPTS="-Xms${JVM_XMS} -Xmx${JVM_XMX}-XX: ${JVM_GC} -Djava.security.egd=file:/dev/./urandom"\
PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.server-addr=${NACOS_ADDR} --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
COPY ./*.jar /app.jar
#EXPOSE 8080
ENTRYPOINT ["/bin/sh","-c","java  ${JAVA_OPTS} -jar app.jar ${PARAMS}"]
  1. docker-compose.yml
version: '3'
services:
  ruoyi-gateway:
    build:
      context: ./service/gateway/
    container_name: ruoyi-gateway
    image: ruoyi-gateway
    ports:
      - "8080:8080"
    environment:
      JVM_XMS: 256m
      JVM_XMX: 256m
      JVM_GC: UseG1GC

so, I believe my config file can work. I'm wrong, I find the problem, error message as list:

       "Mounts": [],
        "Config": {
            "Hostname": "7a5862c10b9b",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "8080/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "JVM_XMS=256m",
                "JVM_XMX=256m",
                "JVM_GC=UseG1GC",
                "PATH=/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "JAVA_HOME=/usr/local/openjdk-8",
                "LANG=C.UTF-8",
                "JAVA_VERSION=8u312",
                "NACOS_ADDR=121.41.120.209:8848",
                "JAVA_OPTS=-Xms -Xmx-XX:  -Djava.security.egd=file:/dev/./urandomPARAMS=--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.server-addr= --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
            ],
            "Cmd": null,
            "Image": "ruoyi-gateway",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/bin/sh",
                "-c",
                "java  ${JAVA_OPTS} -jar app.jar ${PARAMS}"
            ],

docker inspcet information

CodePudding user response:

A Dockerfile ENV directive can only refer to environment variables that are already defined. Without shell hackery, there's no way to define an environment variable that depends on the value some other variable will eventually have.

For the specific case of the JVM heap size, as of Java 8 update 131, the JVM knows how to see Docker memory limits. As of Java 8 update 190, the default maximum heap size is 25% of available memory, but you can change this, for example

ENV JAVA_OPTS="-XX:MaxRAMPercentage=75 ..." # but no -Xmx

and use the docker run -m option to set the container memory limit. If you set docker run -m 1g, for example, the JVM heap size will be 768 MiB.

If that's not an option, I would work around this by setting up the JVM options at execution time. Write a script that sets up $JAVA_OPTS, then runs some command that's passed to it as command-line parameters.

#!/bin/sh
# docker-entrypoint.sh

# Set JVM memory options if set as environment variables.
if [ -n "$JVM_XMS" ]; then
  JAVA_OPTS="$JAVA_OPTS -Xms$JVM_XMS"
fi
if [ -n "$JVM_XMX" ]; then
  JAVA_OPTS="$JAVA_OPTS -Xmx$JVM_XMX"
fi

# Then run the main container command.
exec "$@"

In the Dockerfile you don't need to set -Xmx in the default JVM options, since the entrypoint script will add it for you. You do need to name this script as the Docker ENTRYPOINT.

ENV ... \
    JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom" \
    ...
COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]         # must be JSON array form
CMD java ${JAVA_OPTS} -jar app.jar ${PARAMS} # Docker inserts `sh -c`

I might also consider using environment variables rather than command-line arguments for the various Spring settings. Spring accepts both, but it's much easier to incrementally set individual environment variables than to try to rewrite the $PARAMS list.

ENV ... \
    SERVER_PORT=8080 \
    SPRING_PROFILES_ACTIVE=prod \
    ...
CMD java $JAVA_OPTS -jar app.jar # without $PARAMS

As a final variation, if there are things you need to routinely pass as parameters, it's possible to embed the application call in the entrypoint script. This makes it harder to do things like get a debugging shell (docker run --rm -it your-image bash) but easier to pass parameters without repeating the java command (docker run -d your-image --option). In this setup, you'd end the entrypoint script with the java command, relaying any parameters passed to the script

exec java $JAVA_OPTS -jar app.jar "$@"

You would not need to mention the java command in the Dockerfile, but you would need to spell out the options in the CMD, which must be JSON-array form (one option to an array item). You cannot use environment variables or other shell substitutions with this setup.

# if this runs `java -jar app.jar`
ENTRYPOINT ["/docker-entrypoint.sh"]
# then include additional options here -- MUST be a JSON array
CMD ["--server.port=8080", "--spring.profiles.active=prod"]
  • Related