Dockerisation complète d’une application Full Stack Spring Boot & Angular
Une dockerisation complète permet de packager une application Full Stack composée de Spring Boot (backend Java) et Angular (frontend TypeScript) afin de garantir une exécution reproductible, simplifier le déploiement et standardiser l’environnement d’exécution.
Objectifs de la dockerisation
L’approche présentée ci-dessous vise à obtenir :
- Un conteneur backend exécutant Spring Boot via un JAR.
- Un conteneur frontend servant les fichiers statiques Angular via un serveur web.
- Une orchestration via Docker Compose (réseau, variables, ports).
- Une séparation claire des étapes de build et d’exécution.
Architecture recommandée
Le dépôt peut être structuré comme suit :
my-app/
├─ backend/
│ ├─ src/
│ └─ pom.xml
├─ frontend/
│ ├─ src/
│ ├─ angular.json
│ └─ package.json
├─ docker-compose.yml
└─ .env
Pré-requis techniques
Les outils suivants sont généralement nécessaires :
- Docker et Docker Compose
- Java pour Spring Boot (optionnel localement si le build se fait dans l’image)
- Node.js (optionnel localement si le build Angular se fait dans l’image)
Dockerfile du backend Spring Boot
Le Dockerfile cible une phase de construction (builder) puis une phase d’exécution minimale. L’exécutable sera un JAR fat (généré par Maven).
Exemple : backend/Dockerfile
# backend/Dockerfile
FROM maven:3.9.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn -B -DskipTests package
FROM eclipse-temurin:21-jre
WORKDIR /app
# Ajuster le nom du JAR selon la configuration Maven
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/app.jar"]
Le port 8080 est exposé. Pour un passage d’environnement (profil, configuration, base de données, etc.), Docker Compose peut injecter des variables via environment.
Dockerfile du frontend Angular
La bonne pratique consiste à construire le bundle Angular dans un conteneur Node, puis à servir les assets compilés avec un serveur léger (par exemple Nginx).
Exemple : frontend/Dockerfile
# frontend/Dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Serveur web minimal pour les fichiers statiques
FROM nginx:1.27-alpine
# Optionnel : fournir une configuration Nginx dédiée
# COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist/ /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Le chemin /app/dist/ dépend du nom du projet dans Angular. En cas de décalage, l’output doit être ajusté, par exemple : /app/dist/nom-du-projet/.
Configuration Docker Compose
Docker Compose permet de définir les services, les ports, le réseau et les variables. Une configuration fréquente consiste à exposer :
- Frontend sur 80 (via Nginx)
- Backend sur 8080 (Spring Boot)
Exemple : docker-compose.yml
services:
backend:
build:
context: ./backend
image: fullstack-backend:latest
environment:
- SPRING_PROFILES_ACTIVE=prod
ports:
- "8080:8080"
frontend:
build:
context: ./frontend
image: fullstack-frontend:latest
ports:
- "80:80"
depends_on:
- backend
L’URL du backend côté Angular doit être alignée avec l’architecture : http://localhost:8080 en exécution locale, ou une URL réseau interne (via le nom du service Docker) en environnement Compose.
Gestion des endpoints côté Angular
Dans une application typique, le frontend appelle le backend via une base URL. Une approche robuste consiste à utiliser un fichier de configuration ou des variables d’environnement.
Exemple : base URL configurable
Le code Angular peut lire une configuration (ex. environment.ts pour le build, ou bien une ressource runtime via un fichier servi par Nginx).
# Exemple conceptuel : environment.ts
export const environment = {
apiBaseUrl: 'http://localhost:8080'
};
En Compose, si le frontend et le backend communiquent entre conteneurs, la base URL peut devenir : http://backend:8080 (en remplaçant localhost par le nom du service).
Optimisations courantes
Réduction de la taille des images
Les multi-stages permettent de garder des images finales compactes. Pour Spring Boot, l’usage d’une image JRE au lieu d’une image Maven réduit le poids. Pour Angular, la phase de build reste dans Node et la phase d’exécution dans Nginx.
Build plus rapide via cache
L’ordre des instructions COPY dans les Dockerfile améliore souvent le cache. Les fichiers de dépendances (pom.xml, package*.json) sont copiés avant le reste du code, ce qui accélère les reconstructions.
Durcissement réseau et CORS
Lorsque l’Angular appelle Spring Boot, les règles CORS doivent être cohérentes. Un profil prod peut activer des configurations CORS adaptées à l’URL du frontend.
Exécution et tests
Lancement
docker compose up --build
Une fois les conteneurs démarrés :
- Le frontend devrait être accessible via http://localhost
- Le backend via http://localhost:8080
Vérification de la communication
La validation doit inclure :
- L’appel des endpoints backend depuis l’UI Angular
- Le bon chargement des assets statiques
- La cohérence de la configuration d’URL (localhost vs service Docker)
Déploiement vers un environnement de production
En production, plusieurs patterns existent : utilisation d’un reverse proxy (Traefik/Nginx), gestion de certificats TLS, et intégration d’un registre d’images. La structure Docker présentée facilite la promotion vers un cluster sans dépendre de l’environnement local.
Registre d’images et tag versionné
Une bonne pratique consiste à tagger les images avec un identifiant de version :
fullstack-backend:1.0.0
fullstack-frontend:1.0.0
Conclusion
La dockerisation complète d’une application Full Stack Spring Boot & Angular combine des Dockerfile multi-stages, une orchestration via Docker Compose et une gestion soignée des paramètres d’environnement. Ce schéma améliore la reproductibilité, simplifie le déploiement et réduit les risques liés aux différences de configuration.
À propos de l'auteur
Laty Gueye Samba est développeur Full Stack basé à Dakar, Sénégal. Spécialiste des écosystèmes Java / Spring Boot et Angular.
Contact : latygueyesamba@gmail.com | Dakar, Sénégal