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!