Docker develop rebuild action example

Rebuild is one of the three available action of Docker's hot container replacement feature deciding what to happen with the container. It rebuilds the service based on it's Dockerfile and restarts it with the newly created image.

Prerequisites

  • Installed Docker Compose version 2.22.0 or greater

If you already have Docker on your machine, please verify it's version:

docker compose version

Otherwise follow the official installation instructions.

Practical example

Presume, we are working on a backend of a containerized system. This backend is based on Java 17, so every time we change the source code, we must recompile it and deploy it into the container as well. It would be a tedious task, but luckily Docker comes with the rebuild action.

Our project looks like that (available on GitHub):

.
├── compose.yml
└── spring
    ├── Dockerfile
    ├── mvnw
    ├── mvnw.cmd
    ├── pom.xml
    ├── src
    │   ├── main
    │   │   ├── java
    │   │   │   └── com
    │   │   │       └── minthaka
    │   │   │           └── tutorial
    │   │   │               └── TutorialApplication.java
    │   │   └── resources
    │   │       └── application.yml
    │   └── test
    │       └── java
    │           └── com
    │               └── minthaka
    │                   └── tutorial
    │                       └── TutorialApplicationTests.java
    └── target

Here is compose.yml, where the rebuild action resides:

services:
  mysql:
    image: mysql:8.4.2
    restart: always
    hostname: mysql
    container_name: mysql
    environment:
        MYSQL_RANDOM_ROOT_PASSWORD: true
        MYSQL_USER: spring
        MYSQL_DATABASE: spring
        MYSQL_PASSWORD: password
    volumes:
    - mysql_data:/var/lib/mysql
    networks:
    - backend

  spring:
    build: ./spring
    restart: always
    hostname: spring
    container_name: spring
    environment:
      DATABASE: spring
      DATABASE_HOST: mysql
      DATABASE_USER: spring
      DATABASE_PASSWORD: password
    ports:
      - 80:8080
    networks:
      - backend
    depends_on:
      - mysql
    develop:
      # when source code changes, rebuild triggers
      watch:
      - path: ./spring/src
        action: rebuild

networks:
  backend:
    driver: bridge

volumes:
  mysql_data:

Next, our Dockerfile at the spring directory:

# source code get compiled with maven
FROM eclipse-temurin:17-jdk-jammy AS build

ENV HOME=/usr/app
ENV DATABASE=spring
ENV DATABASE_HOST=mysql
ENV DATABASE_USERNAME=spring
ENV DATABASE_PASSWORD=password

RUN mkdir -p $HOME
WORKDIR $HOME
ADD . $HOME
RUN chmod +x ./mvnw
RUN --mount=type=cache,target=/root/.m2 ./mvnw -f $HOME/pom.xml clean install

# compiled code get executed
FROM eclipse-temurin:17-jre-jammy 
ARG JAR_FILE=/usr/app/target/*.jar
COPY --from=build $JAR_FILE /app/runner.jar

EXPOSE 8080
ENTRYPOINT java -jar /app/runner.jar

You may noticed that spring depends on mysql. This can cause issues. Why?

Imagine you just moved your project into the server machine. spring is not yet built, so Docker is going to build it before starting any service. However spring contains tests that getting executed during maven install. Hence some tests may require mysql, they ultimately fail because mysql is not running at the moment. This cancels the build process. So how we fix it?

Simply run mysql first:

docker compose up -d mysql

Then run docker in develop mode:

docker compose watch

After spring is built for the first time, you can avoid running mysql separately.

Testing

You may notice the following in the terminal:

Watch enabled

That means probably everything works as it should.

Now edit TutorialApplication.java and check the terminal again:

Rebuilding service "spring" after changes were detected...
.
.
.
service "spring" successfully built

You may also check the effect via your browser by entering the following URL:

http://<ip-of-your-server>

After you are done with developing, stop the process with Ctrl+C and run the following to remove the unused containers:

docker compose down

Thank you for reading! Keep coding!