How to properly set and manage JVM heap size (-Xms, -Xmx) for a Spring Boot app running in Docker Compose?

FROM maven:3.9-eclipse-temurin-17 AS build

WORKDIR /app
COPY . .
RUN mvn install -DskipTests -s settings.xml

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
USER 1000
EXPOSE 8082
CMD [“java”, “-jar”, “app.jar”]

docker-compose.yml:

version: “3.8”

services:
  ware-service:
    image: ${DC_IMAGE_NAME}:${DC_IMAGE_TAG}
    ports:
      - 8082:8082
    environment:
      - SPRING_CLOUD_CONFIG_URI=http://config-service:8888
      - EUREKA_SERVICE_ADDRESS=http://registry-service:8761/eureka/
      - SERVER_PORT=8082
    networks:
      - ms-network
    restart: always

networks:
  ms-network:
    external:
      name: ms_network

Questions:

  1. What’s the best way to pass JVM heap options like -Xms512m -Xmx1024m to the container — should I modify the Dockerfile or set them at runtime (e.g., in docker-compose)?

  2. is my dockerfile good or it need some changes?

Two observabilities on your Docekrfile:

  • from what I remember spring-boot uses port 8080 by default. Is there a reason you change it to port 8082? It’s good practice to run applications with their default ports inside containers, and publish the host port of your choosing for the running container.
  • Your CMD uses the “exec form”, which does not allow using variables. You will want to use something like this:
CMD exec java $JAVA_OPTS -jar app.jar

Then you can use set the JAVA_OPTS environment variable in your compose file to set the options for the jvm.

What about setting the JAVA_TOOL_OPTIONS env variable? It is also used by the entrypoint of the image

__cacert_entrypoint.sh:        export JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS} -Djavax.net.ssl.trustStore=${JRE_CACERTS_PATH} -Djavax.net.ssl.trustStorePassword=changeit"

Since I am not a Java developer, I wasn’t sure if it was for the same purpose, but a stack overflow comment indicates it is, although that was about oracle java

Then you don’t need to change the CMD instruction.

should I add
ENV JAVA_OPTS=””

then CMD exec java $JAVA_OPTS -jar app.jar
or that ENV is not necessary

so with that docker run -e JAVA_OPTS and pass what I want

The ENV instruction in the Dockerfile just adds a default value. It could be a good idea to add to not have an undefined variable and to show that it can be set, but not strictly necessary.

Have you tried the other variable I mentioned? I’m curious if that works. official images usually don’t require changing the CMD or entrypoint for such a common parameter.

I didn’t check the image. My command might even not work properly if an entrypoint script is in place.