当我使用 docker-compose 和 dockerfile 创建 javaproject 时,如何更改堆大小?
How can i change heap size when i use docker-compose and dockerfile to create a javaproject?
我想在需要时使用 docker-compose 来缩放堆大小,我失败了,我需要你的帮助!!!
- Docker 文件:
FROM openjdk:8-jdk
MAINTAINER whywhathow(whywhathow.fun@gmail.com)
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
所以,我相信我的配置文件可以工作。我错了,我发现了问题,错误信息如下:
"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
A Dockerfile ENV
指令只能引用已经定义的环境变量。没有 shell hackery,就无法定义依赖于其他变量最终具有的值的环境变量。
对于 JVM 堆大小的特定情况,截至 Java 8 更新 131,JVM 知道如何查看 Docker 内存限制。从 Java 8 update 190 开始,默认最大堆大小为可用内存的 25%,但您可以更改它,例如
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75 ..." # but no -Xmx
并使用docker run -m
选项设置容器内存限制。例如,如果设置 docker run -m 1g
,JVM 堆大小将为 768 MiB。
如果那不是一个选项,我会通过在执行时设置 JVM 选项来解决这个问题。编写一个脚本来设置 $JAVA_OPTS
,然后运行一些作为命令行参数传递给它的命令。
#!/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 "$@"
在 Docker 文件中,您不需要在默认 JVM 选项中设置 -Xmx
,因为入口点脚本会为您添加它。您确实需要将此脚本命名为 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`
我可能还会考虑对各种 Spring 设置使用环境变量而不是命令行参数。 Spring 两者都接受,但增量设置单个环境变量比尝试重写 $PARAMS
列表要容易得多。
ENV ... \
SERVER_PORT=8080 \
SPRING_PROFILES_ACTIVE=prod \
...
CMD java $JAVA_OPTS -jar app.jar # without $PARAMS
作为最后的变体,如果您需要定期将某些东西作为参数传递,则可以将应用程序调用嵌入入口点脚本中。这使得调试 shell (docker run --rm -it your-image bash
) 之类的事情变得更加困难,但无需重复 java
命令 (docker run -d your-image --option
) 即可更轻松地传递参数。在此设置中,您将使用 java
命令结束入口点脚本,中继传递给脚本的任何参数
exec java $JAVA_OPTS -jar app.jar "$@"
你不需要在Docker文件中提到java
命令,但你需要在CMD
中拼出选项,它必须是JSON-数组形式(数组项的一个选项)。您不能在此设置中使用环境变量或其他 shell 替换。
# 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"]
感谢David Maze帮助。
根据 David Maze 的回答,这是我的答案。
- 我的苍蝇结构:
-docker
|
--services
|
---demo
| |-docker-entrypoint.sh
| |-Dockerfile
|
-docker-compose.yml
- Dockerfile 作为列表:
FROM openjdk:8-jdk
MAINTAINER whywhathow(whywhathow.fun@gmail.com)
ENV \
JVM_GC="+UseConcMarkSweepGC"\
JVM_XMS="128m" \
JVM_XMX="256m" \
SERVER_PORT="8080" \
SPRING_PROFILES_ACTIVE="prod" \
NACOS_ADDR="127.0.0.1" \
JAVA_RANDOM="-Djava.security.egd=file:/dev/./urandom"
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}"]
# test shell
COPY ./docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
- docker-entrypoint.sh 作为列表
#!/bin/bash
# docker-entrypoint.sh
# link:
# print debug information
set -ex
#########################################################
# 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
# shellcheck disable=SC1072
if [ -n "$JVM_GC" ]; then
JAVA_OPTS="$JAVA_OPTS -XX:$JVM_GC"
fi
if [ -n "$JAVA_RANDOM" ]; then
JAVA_OPTS="$JAVA_OPTS $JAVA_RANDOM"
fi
#########################################################
# set params
#########################################################
# shellcheck disable=SC1073
if [ -n "$SERVER_PORT" ]; then
PARAMS="$PARAMS --server.port=$SERVER_PORT "
fi
if [ -n "$SPRING_PROFILES_ACTIVE" ]; then
PARAMS="$PARAMS --spring.profiles.active=$SPRING_PROFILES_ACTIVE "
fi
if [ -n "$NACOS_ADDR" ]; then
PARAMS="$PARAMS --spring.cloud.nacos.server-addr=$NACOS_ADDR"
fi
if [ -n "$OTHER_PARAMS" ]; then
PARAMS="$PARAMS $OTHER_PARAMS"
fi
# Then run the main container command.
exec java $JAVA_OPTS -jar app.jar $PARAMS
- docker-compose.yml:没有变化。
之后,您可以在docker-compose.yml中轻松管理您的项目详细信息。
提示:
如果您是 docker 和 shell 脚本中的新手,那么您应该观看这些内容。
- Dockfile:换行中没有评论
- shell:确保你的shell没有错误(不要像我一样忽略编辑器错误信息,那太愚蠢了。)
- if [-n "JVM_OPTIONS" ];然后
如果你像我一样在docker文件和shell脚本中出错,你应该注意你的命令。
docker-compose up demo
找到你的问题并解决它。
最后谢谢David Maze.
我想在需要时使用 docker-compose 来缩放堆大小,我失败了,我需要你的帮助!!!
- Docker 文件:
FROM openjdk:8-jdk
MAINTAINER whywhathow(whywhathow.fun@gmail.com)
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
所以,我相信我的配置文件可以工作。我错了,我发现了问题,错误信息如下:
"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
A Dockerfile ENV
指令只能引用已经定义的环境变量。没有 shell hackery,就无法定义依赖于其他变量最终具有的值的环境变量。
对于 JVM 堆大小的特定情况,截至 Java 8 更新 131,JVM 知道如何查看 Docker 内存限制。从 Java 8 update 190 开始,默认最大堆大小为可用内存的 25%,但您可以更改它,例如
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75 ..." # but no -Xmx
并使用docker run -m
选项设置容器内存限制。例如,如果设置 docker run -m 1g
,JVM 堆大小将为 768 MiB。
如果那不是一个选项,我会通过在执行时设置 JVM 选项来解决这个问题。编写一个脚本来设置 $JAVA_OPTS
,然后运行一些作为命令行参数传递给它的命令。
#!/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 "$@"
在 Docker 文件中,您不需要在默认 JVM 选项中设置 -Xmx
,因为入口点脚本会为您添加它。您确实需要将此脚本命名为 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`
我可能还会考虑对各种 Spring 设置使用环境变量而不是命令行参数。 Spring 两者都接受,但增量设置单个环境变量比尝试重写 $PARAMS
列表要容易得多。
ENV ... \
SERVER_PORT=8080 \
SPRING_PROFILES_ACTIVE=prod \
...
CMD java $JAVA_OPTS -jar app.jar # without $PARAMS
作为最后的变体,如果您需要定期将某些东西作为参数传递,则可以将应用程序调用嵌入入口点脚本中。这使得调试 shell (docker run --rm -it your-image bash
) 之类的事情变得更加困难,但无需重复 java
命令 (docker run -d your-image --option
) 即可更轻松地传递参数。在此设置中,您将使用 java
命令结束入口点脚本,中继传递给脚本的任何参数
exec java $JAVA_OPTS -jar app.jar "$@"
你不需要在Docker文件中提到java
命令,但你需要在CMD
中拼出选项,它必须是JSON-数组形式(数组项的一个选项)。您不能在此设置中使用环境变量或其他 shell 替换。
# 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"]
感谢David Maze帮助。 根据 David Maze 的回答,这是我的答案。
- 我的苍蝇结构:
-docker
|
--services
|
---demo
| |-docker-entrypoint.sh
| |-Dockerfile
|
-docker-compose.yml
- Dockerfile 作为列表:
FROM openjdk:8-jdk
MAINTAINER whywhathow(whywhathow.fun@gmail.com)
ENV \
JVM_GC="+UseConcMarkSweepGC"\
JVM_XMS="128m" \
JVM_XMX="256m" \
SERVER_PORT="8080" \
SPRING_PROFILES_ACTIVE="prod" \
NACOS_ADDR="127.0.0.1" \
JAVA_RANDOM="-Djava.security.egd=file:/dev/./urandom"
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}"]
# test shell
COPY ./docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
- docker-entrypoint.sh 作为列表
#!/bin/bash
# docker-entrypoint.sh
# link:
# print debug information
set -ex
#########################################################
# 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
# shellcheck disable=SC1072
if [ -n "$JVM_GC" ]; then
JAVA_OPTS="$JAVA_OPTS -XX:$JVM_GC"
fi
if [ -n "$JAVA_RANDOM" ]; then
JAVA_OPTS="$JAVA_OPTS $JAVA_RANDOM"
fi
#########################################################
# set params
#########################################################
# shellcheck disable=SC1073
if [ -n "$SERVER_PORT" ]; then
PARAMS="$PARAMS --server.port=$SERVER_PORT "
fi
if [ -n "$SPRING_PROFILES_ACTIVE" ]; then
PARAMS="$PARAMS --spring.profiles.active=$SPRING_PROFILES_ACTIVE "
fi
if [ -n "$NACOS_ADDR" ]; then
PARAMS="$PARAMS --spring.cloud.nacos.server-addr=$NACOS_ADDR"
fi
if [ -n "$OTHER_PARAMS" ]; then
PARAMS="$PARAMS $OTHER_PARAMS"
fi
# Then run the main container command.
exec java $JAVA_OPTS -jar app.jar $PARAMS
- docker-compose.yml:没有变化。
之后,您可以在docker-compose.yml中轻松管理您的项目详细信息。
提示: 如果您是 docker 和 shell 脚本中的新手,那么您应该观看这些内容。
- Dockfile:换行中没有评论
- shell:确保你的shell没有错误(不要像我一样忽略编辑器错误信息,那太愚蠢了。)
- if [-n "JVM_OPTIONS" ];然后
如果你像我一样在docker文件和shell脚本中出错,你应该注意你的命令。
docker-compose up demo
找到你的问题并解决它。 最后谢谢David Maze.