Broadleaf Microservices
  • v1.0.0-latest-prod

Docker Configuration

Introduction

Broadleaf’s starter projects include various modules that produce Docker images. The Docker build configuration in those modules follows what Broadleaf uses internally for its own sample images. However, this configuration is not intended for direct client use and should be replaced.

There are several reasons for this:

Clients should create their own Docker build configurations in ways that suit their needs. The Broadleaf sample configurations should merely be used as reference.

Find all Docker build configurations in the starter projects

For backend projects, Broadleaf’s Docker build configurations typically involve two main components: a Dockerfile and a pom.xml containing a docker profile that builds the image for it. This is because we prefer to build Docker images as part of the Maven lifecycle. For frontend projects, the process typically just involves a Dockerfile.

You can execute find . -name Dockerfile from the root of your starter project repository to get a list of all paths at which Dockerfiles are found.

Then, for backend projects, you can use those paths to also find the corresponding pom.xml in charge of building the image, since they are usually in the same directory.

Understand existing sample Docker build configuration

In an effort to support both ARM (arm64) and X86 (amd64) platforms, Broadleaf changed its Docker build processes starting with version 1.7.4 to output multi-platform images.

Multi-platform (versions 1.7.4 and beyond)

The sample Docker configurations in versions 1.7.4 and beyond use docker buildx (documented here by Docker) to build multi-platform images.

Prerequisites and limitations for multi-platform Docker builds

Prerequisites
  • The machine running the build process must have QEMU emulators installed for all target platforms, and they must be accessible to Docker. Usually, Docker Desktop comes with these emulators, but if your installation doesn’t, you can install them manually as documented here.

  • The machine running the build process must have created a new builder instance which uses the docker-container driver, and it should be set as the currently active builder instance.

    # Note - you only have to run this once on your machine, not for every project
    # This spins up a Docker container that runs the builder instance - the name doesn't matter
    docker buildx create --name "my-blc-multiplat-builder" --driver="docker-container" --bootstrap --use

    Without this, you would see an error like so:

    error: multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use")
Limitations
  • At this time, a local Docker registry does not support storing multi-platform images (this is a general Docker limitation). By default, the backend sample Docker build process (when engaged with mvn package instead of mvn deploy) produces multi-platform images and then discards the result. This means you can still locally engage the multi-platform build to test all platforms can be correctly built, it just won’t store the final images anywhere. The command may even emit a warning like this:

    WARNING: No output specified for docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

Frontend projects

Frontend projects just use a Dockerfile and are expected to be built directly with docker commands like docker buildx build (with additions like the --platform argument).

Note
In some cases, the Dockerfile may expect yarn build (or similar) to have been run already. You can review each Dockerfile for more information.

Backend projects

Backend projects have special Maven profiles (typically called docker) in their pom.xml which invoke docker buildx bake (documented here by Docker). This in turn leverages both a docker-bake.hcl file (sometimes commonly shared between multiple modules in a project) and a Dockerfile that together describe the build configuration.

Note
docker buildx bake was chosen for its maintainability advantages, as it allows complexities to be placed into the docker-bake.hcl file (documented here by Docker) and simplifies the configuration of the Maven profile.
Local development workaround

To bypass multi-platform Docker limitations and support local development requirements, the sample Maven profiles typically also expose a buildLocalDockerOnly property. By setting this to true (ex: mvn package -Pdocker -DbuildLocalDockerOnly=true), the configuration will only build the image for the architecture running the build process, and the image will be loaded into the local Docker registry (it’ll be available in docker images). This allows a developer to run their locally built image.

Single-platform (versions 1.7.3 and prior)

The sample Docker configurations in versions 1.7.3 and prior only support single-platform Docker builds to produce X86 images.

Note

To be absolutely clear, Broadleaf’s applications have always been platform-agnostic and themselves require no changes to work on other platforms such as ARM.

Java applications just require an ARM-compatible JRE/JDK (see Temurin releases), and frontend applications just require an ARM-compatible JavaScript runtime.

The 'lack of multi-platform support' in this context is specifically regarding the sample Docker images containing those applications.

Frontend projects

Frontend projects just use a Dockerfile and are expected to be built directly with docker commands like docker build.

Note
In some cases, the Dockerfile may expect yarn build (or similar) to have been run already. You can review each Dockerfile for more information.

Backend projects

Backend projects have special Maven profiles (typically called docker) in their pom.xml which invoke the Maven plugin dockerfile-maven-plugin. The plugin then builds the image from the specified Dockerfile.

This configuration is quite simple, and you can follow the dockerfile-maven-plugin docs to understand it more.

Replace existing sample Docker configuration

Due to differences in client needs and expectations, this section is purposefully not well-defined.

In some cases, clients may drop all sample Docker configuration in favor of their own custom procedures (ex: use completely different tooling to build the image such as Google Jib). In others, they may choose to just slightly tweak the configuration (ex: remove multi-platform support).

However, at a minimum, we suggest all clients at least make the following changes:

  • Replace the base image in all Dockerfiles to not use Broadleaf’s base image.

  • Change the image names/tags, as the defaults are unsuitable for clients (for example, they should target the client’s Docker registry instead of Broadleaf’s Docker registry)

Broadleaf Boot Layer Service Docker Base Image

By default, many of the starter projects have a Dockerfile whose base image is something like repository.broadleafcommerce.com:5001/broadleaf/boot-layer-service:…​-jre-…​ (ex: repository.broadleafcommerce.com:5001/broadleaf/boot-layer-service:11.0.14.1_1-jre-1).

This is a multi-platform base image used internally by Broadleaf to create sample images for its various projects.

Note
Versions before 1.7.4 may be using an older base image such as repository.broadleafcommerce.com:5001/broadleaf/boot-service-jdk11 or repository.broadleafcommerce.com:5001/broadleaf/boot-layer-service-jdk11. These are deprecated.

Broadleaf’s base images are not intended to be used by clients directly:

  • Updates to these images and new tags are not announced

  • Updates to these images are not guaranteed backwards compatible or stable

  • Use of the images requires authentication to the Broadleaf Docker registry

  • Use of an old base image may result in falling behind in security updates

We strongly advise clients create, use, and maintain their own base images instead of relying on Broadleaf’s base image.

For your reference only, below we have provided an example of source components used to create the Broadleaf base image. We build this image for multiple platforms using docker buildx.

  • Dockerfile

    # Used as a base image that other Spring Boot-based
    # docker containers can be based off of.
    #
    # This is an official image with multi-platform support.
    # OS is Ubuntu (at the time of writing, there is no multi-platform Alpine image)
    # Importantly, this supports 'linux/amd64' and 'linux/arm64/v8'
    # See https://hub.docker.com/_/eclipse-temurin
    FROM eclipse-temurin:11.0.14.1_1-jre
    
    VOLUME /tmp
    ADD ./supporting/run-app.sh run-app.sh
    RUN chmod u+x "run-app.sh"
    
    # Use the 'exec form' of entrypoint to ensure signals like 'KILL' are forwarded to the running process.
    # https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example
    ENTRYPOINT ["./run-app.sh"]
  • run-app.sh

    #!/bin/sh
    
    # Used as the 'entrypoint' script in base images to start a Spring Boot application.
    
    if [ "$DEBUG_PORT" ]; then
      export JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:$DEBUG_PORT"
    fi
    
    export JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"
    
    # Moved into a shell script because the above 'export' statements cannot be retrieved
    # between multiple statements in a Dockerfile
    echo "Starting Java with the arguments '$JAVA_OPTS'"
    
    # Use 'exec' to ensure the running process responds to signals like 'KILL'
    #
    # This command assumes the image will _not_ use a Spring Boot fat JAR and will instead
    # run something like 'java -Djarmode=layertools -jar app.jar extract' to pre-explode the JAR
    # contents and copy them directly.
    exec java $JAVA_OPTS org.springframework.boot.loader.JarLauncher