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}"]
- 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}"
],
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"]