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
└── targetHere 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.jarYou 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 mysqlThen run docker in develop mode:
docker compose watchAfter spring is built for the first time, you can avoid running mysql separately.
Testing
You may notice the following in the terminal:
Watch enabledThat 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 builtYou 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!