Objectif : démarche complète permettant de builder, tester, tagger puis publier une image Docker du microservice Spring Boot demodock sur Docker Hub.
L’arborescence du projet est la suivante :
guillaume@rocket:~/Développement/demodock$ ls
HELP.md mvnw mvnw.cmd pom.xml README.md src target
src/ : code source de l’applicationpom.xml : descripteur Maven (dépendances, build)mvnw / .mvn/ : wrapper Maven (optionnel dans cette procédure ; Maven système est utilisé)target/ : artefacts de build (JAR, classes compilées, etc.)Avant toute construction d’image, s'assurer que Docker est installé, que le daemon répond, et que le couple client/serveur est cohérent.
docker version)Commande :
docker version
But :
Sortie :
Client: Docker Engine - Community
Version: 29.1.3
API version: 1.52
Go version: go1.25.5
Git commit: f52814d
Built: Fri Dec 12 14:49:32 2025
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 29.1.3
API version: 1.52 (minimum version 1.44)
Go version: go1.25.5
Git commit: fbf3ed2
Built: Fri Dec 12 14:49:32 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v2.2.1
GitCommit: dea7da592f5d1d2b7755e3a161be07f43fad8f75
runc:
Version: 1.3.4
GitCommit: v1.3.4-0-gd6d73eb8
docker-init:
Version: 0.19.0
GitCommit: de40ad0
docker info)Commande :
docker info
But :
overlay2)Sortie :
Client: Docker Engine - Community
Version: 29.1.3
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.30.1
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v5.0.0
Path: /usr/libexec/docker/cli-plugins/docker-compose
Server:
Containers: 15
Running: 0
Paused: 0
Stopped: 15
Images: 26
Server Version: 29.1.3
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: systemd
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
CDI spec directories:
/etc/cdi
/var/run/cdi
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: dea7da592f5d1d2b7755e3a161be07f43fad8f75
runc version: v1.3.4-0-gd6d73eb8
init version: de40ad0
Security Options:
apparmor
seccomp
Profile: builtin
cgroupns
Kernel Version: 6.14.0-37-generic
Operating System: Ubuntu 24.04.3 LTS
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 31.2GiB
Name: rocket
ID: a80e2778-d998-428d-a7df-f90fe0f0fd58
Docker Root Dir: /var/lib/docker
Debug Mode: false
Experimental: false
Insecure Registries:
::1/128
127.0.0.0/8
Live Restore Enabled: false
Firewall Backend: iptables
Avant de dockeriser, vérifier que l’application compile et génèrer un JAR exécutable Spring Boot.
mvn -v)Commande :
mvn -v
But :
Sortie :
Apache Maven 3.8.7
Maven home: /usr/share/maven
Java version: 17.0.17, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: fr_FR, platform encoding: UTF-8
OS name: "linux", version: "6.14.0-37-generic", arch: "amd64", family: "unix"
mvn clean package)Commande :
mvn clean package
But :
target/target/demodock-0.0.1-SNAPSHOT.jar (repackagé Spring Boot)Sortie :
[INFO] --------------------------< fr.ev1:demodock >---------------------------
[INFO] Building demodock 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] Deleting /home/guillaume/Développement/demodock/target
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO] Compiling 3 source files with javac [debug parameters release 17] to target/classes
[INFO] Running fr.ev1.demodock.DemodockApplicationTests
...
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
...
[INFO] Building jar: /home/guillaume/Développement/demodock/target/demodock-0.0.1-SNAPSHOT.jar
[INFO] Replacing main artifact ... with repackaged archive, adding nested dependencies in BOOT-INF/.
[INFO] BUILD SUCCESS
.dockerignoreCréer un fichier .dockerignore à la racine du projet afin de réduire le contexte envoyé au daemon Docker (build plus rapide, image plus propre).
Fichier : .dockerignore
Contenu :
target
.git
.idea
.project
.classpath
.settings
.DS_Store
*.iml
But :
target/ (build locaux)Dockerfile (multi-stage) et expliquer sa logiqueUtiliser un Dockerfile multi-stage :
DockerfileFichier : Dockerfile (à la racine)
Contenu :
# =========================
# Stage 1 — Build (Maven)
# =========================
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /workspace
# On copie d'abord le pom pour profiter du cache Docker
COPY pom.xml .
RUN mvn -q -DskipTests dependency:go-offline
# Puis on copie les sources
COPY src src
RUN mvn -q -DskipTests clean package
# =========================
# Stage 2 — Runtime (JRE)
# =========================
FROM eclipse-temurin:17-jre
WORKDIR /app
# Bonnes pratiques runtime
ENV TZ=Europe/Paris
ENV JAVA_OPTS=""
# On copie le jar buildé
COPY --from=build /workspace/target/*.jar /app/app.jar
# Port Spring (ton server.port=8080)
EXPOSE 8080
# Healthcheck (si /health répond en 200)
HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=5 CMD curl -fsS http://localhost:8080/health || exit 1
# Démarrage
ENTRYPOINT ["sh","-c","java $JAVA_OPTS -jar /app/app.jar"]
FROM maven:3.9-eclipse-temurin-17 AS build : image de build contenant Maven + JDK 17COPY pom.xml . puis dependency:go-offline : mise en cache des dépendances MavenCOPY src src : copie le code applicatifmvn ... clean package : compile le projet et construit un JAR Spring BootFROM eclipse-temurin:17-jre : image runtime contenant uniquement le JRE (plus légère)COPY --from=build ... app.jar : embarque uniquement l’artefact finalEXPOSE 8080 : documente le port écoutéHEALTHCHECK ... /health : permet à Docker/Compose de savoir si le conteneur est sainENTRYPOINT ... java -jar : démarre le microservicedocker build)Commande :
docker build -t demodock:local .
But :
demodock:localSortie :
[+] Building 4.2s (15/15) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 949B 0.0s
=> [internal] load metadata for docker.io/library/eclipse-temurin:17-jre 0.4s
=> [internal] load metadata for docker.io/library/maven:3.9-eclipse-temu 0.4s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 104B 0.0s
=> [build 1/6] FROM docker.io/library/maven:3.9-eclipse-temurin-17@sha25 0.0s
=> [stage-1 1/3] FROM docker.io/library/eclipse-temurin:17-jre@sha256:fc 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 983B 0.0s
=> CACHED [stage-1 2/3] WORKDIR /app 0.0s
=> CACHED [build 2/6] WORKDIR /workspace 0.0s
=> CACHED [build 3/6] COPY pom.xml . 0.0s
=> CACHED [build 4/6] RUN mvn -q -DskipTests dependency:go-offline 0.0s
=> CACHED [build 5/6] COPY src src 0.0s
=> [build 6/6] RUN mvn -q -DskipTests clean package 3.4s
=> [stage-1 3/3] COPY --from=build /workspace/target/*.jar /app/app.jar 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:1954f437c4e6d74640cf2c787a1738f38a9307062b787 0.0s
=> => naming to docker.io/library/demodock:local 0.0s
docker images)Commande :
docker images | grep demodock
But :
demodock:local existeSortie :
WARNING: This output is designed for human readability. For machine-readable output, please use --format.
demodock:local 1954f437c4e6 286MB 0B
docker run)Commande :
docker run --rm -p 8080:8080 --name demodock demodock:local
But :
--rm : supprimer automatiquement le conteneur à l’arrêt-p 8080:8080 : publier le port conteneur 8080 sur le port hôte 8080--name demodock : nommer le conteneurdemodock:local : image sourceSortie observée :
:: Spring Boot :: (v4.0.1)
2025-12-25 15:16:53 INFO fr.ev1.demodock.DemodockApplication - Starting DemodockApplication v0.0.1-SNAPSHOT using Java 17.0.17 with PID 7 (/app/app.jar started by root in /app)
2025-12-25 15:16:53 INFO fr.ev1.demodock.DemodockApplication - No active profile set, falling back to 1 default profile: "default"
2025-12-25 15:16:54 INFO o.s.boot.tomcat.TomcatWebServer - Tomcat initialized with port 8080 (http)
2025-12-25 15:16:54 INFO o.a.catalina.core.StandardService - Starting service [Tomcat]
2025-12-25 15:16:54 INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/11.0.15]
2025-12-25 15:16:54 INFO o.s.b.w.c.s.WebApplicationContextInitializer - Root WebApplicationContext: initialization completed in 907 ms
2025-12-25 15:16:54 INFO o.s.b.a.e.web.EndpointLinksResolver - Exposing 2 endpoints beneath base path '/actuator'
2025-12-25 15:16:54 INFO o.s.boot.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path '/'
2025-12-25 15:16:54 INFO fr.ev1.demodock.DemodockApplication - Started DemodockApplication in 2.029 seconds (process running for 2.4)
2025-12-25 15:16:57 INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-12-25 15:16:57 INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
2025-12-25 15:16:57 INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms
Validation fonctionnelle (attendue) :
http://localhost:8080/http://localhost:8080/healthCommandes :
docker tag demodock:local suntux57420/demodock:1.0.0
docker tag demodock:local suntux57420/demodock:latest
But :
demodock:local à deux tags destinés au push :
1.0.0) : traçabilitélatest) : usage démo / “dernière version”docker login)Commande :
docker login -u gu***me***_***@***.ev1.fr
But :
Sortie :
i Info → A Personal Access Token (PAT) can be used instead.
To create a PAT, visit https://app.docker.com/settings
Password:
WARNING! Your credentials are stored unencrypted in '/home/guillaume/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/
Login Succeeded
Point d’attention :
~/.docker/config.json.1.0.0Commande :
docker push suntux57420/demodock:1.0.0
But :
1.0.0 vers docker.io/suntux57420/demodockSortie :
The push refers to repository [docker.io/suntux57420/demodock]
4833ed484f78: Pushed
85c35138184f: Pushed
d1d6e1a741f5: Mounted from suntux57420/eventshare
9eb195841e36: Mounted from library/eclipse-temurin
f7389bca3ee5: Mounted from library/eclipse-temurin
0c934f67f30c: Mounted from library/eclipse-temurin
e8bce0aabd68: Mounted from library/eclipse-temurin
1.0.0: digest: sha256:16decca6ac7316ec6dadc5efa7121eb8543b160b36d1c19467e573166355e2ba size: 1786
latestCommande :
docker push suntux57420/demodock:latest
But :
latest pointant vers la même imageSortie :
The push refers to repository [docker.io/suntux57420/demodock]
4833ed484f78: Layer already exists
85c35138184f: Layer already exists
d1d6e1a741f5: Layer already exists
9eb195841e36: Layer already exists
f7389bca3ee5: Layer already exists
0c934f67f30c: Layer already exists
e8bce0aabd68: Layer already exists
latest: digest: sha256:16decca6ac7316ec6dadc5efa7121eb8543b160b36d1c19467e573166355e2ba size: 1786
Layer already exists : les couches sont déjà dans le registre (push précédent), seul le tag est mis à jourdigest identique : même contenu d’image, tags différentsUne fois publiée, l’image est accessible via :
suntux57420/demodock:latest
Exemple (sur une autre machine) :
docker pull suntux57420/demodock:latest
docker run --rm -p 8080:8080 --name demodock suntux57420/demodock:latest
docker version, docker info)mvn clean package).dockerignore est en place (contexte propre)Dockerfile multi-stage est prêtdocker build -t demodock:local .)docker run ...)1.0.0, latest)docker login)docker push ...)suntux57420/demodock:latest