Retour aux articles

Automatiser le CI/CD d'une application Spring Boot/Angular avec GitLab et Docker

Automatiser le CI/CD d'une application Spring Boot/Angular avec GitLab et Docker | Laty Gueye Samba - Développeur Full Stack Dakar Sénégal, Expert Java Spring Boot Angular
```html

Automatiser le CI/CD d’une application Spring Boot/Angular avec GitLab et Docker

L’automatisation du cycle CI/CD améliore la qualité logicielle, accélère les déploiements et réduit les erreurs manuelles. Cet article décrit une approche robuste pour orchestrer des pipelines GitLab et des images Docker pour une application Spring Boot côté back-end et Angular côté front-end.

Objectifs et architecture cible

L’objectif consiste à :

  • Builder automatiquement l’application Angular pour produire des fichiers statiques.
  • Builder automatiquement le back-end Spring Boot (JAR) et le packager dans une image Docker.
  • Déployer de manière reproductible sur un environnement (staging/production).
  • Gérer des étapes distinctes : build, test et deploy.

Pré-requis

Les éléments suivants sont nécessaires :

  • GitLab avec un projet configuré et un registre de conteneurs (Container Registry).
  • Docker installé sur l’environnement d’exécution des jobs (Runner).
  • Un GitLab Runner configuré (souvent avec un mode Docker ou Kubernetes).
  • Une stratégie de versionnement (tag Git, variable d’artefact, ou numéro de build).

Organisation typique du dépôt

Une structure fréquemment utilisée :

/backend (Spring Boot)
/frontend (Angular)
Dockerfile
docker-compose.yml (optionnel)
.gitlab-ci.yml

Points clés de packaging

Une pratique courante consiste à servir le front Angular depuis le back-end (Spring Boot) ou depuis un conteneur web séparé. Pour simplifier la CI/CD, une approche monolithique Docker peut être adoptée : le conteneur final inclut les assets Angular et l’API Spring Boot.

Construire une image Docker multi-étapes

Un Dockerfile multi-stage permet d’optimiser la taille de l’image finale et de séparer les dépendances de build. Le front Angular est compilé, puis ses artefacts sont copiés dans l’image finale.

Exemple de Dockerfile (front + back)

L’exemple ci-dessous suppose que le front produit un dossier dist/ et que Spring Boot expose un dossier de ressources.

# -------------------------
# Stage 1: Build Angular
# -------------------------
FROM node:20-alpine AS frontend-build
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend ./
RUN npm run build -- --configuration production

# -------------------------
# Stage 2: Build Spring Boot
# -------------------------
FROM maven:3.9-eclipse-temurin-21 AS backend-build
WORKDIR /app
COPY backend/pom.xml ./
RUN mvn -q -DskipTests dependency:go-offline
COPY backend ./
RUN mvn -q -DskipTests package

# -------------------------
# Stage 3: Image finale
# -------------------------
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app

# Copie du JAR
COPY --from=backend-build /app/target/*.jar app.jar

# Copie des assets Angular (exemple : dans un dossier static)
# Adapter selon la configuration Spring Boot (resources/static)
COPY --from=frontend-build /app/dist/ /app/static/

EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/app.jar"]

Les chemins exacts peuvent varier selon les conventions du projet (ex : dist/<app>/, resources/static, etc.). L’essentiel est d’assurer une intégration cohérente des artefacts dans l’image finale.

Configurer GitLab CI/CD (.gitlab-ci.yml)

Le fichier .gitlab-ci.yml décrit les étapes du pipeline. Une configuration standard sépare : build (compilation), test (validation), puis deploy (déploiement).

Pipeline avec build & push Docker

L’exemple ci-dessous :

  • Compile et teste (au minimum côté back-end).
  • Construit une image Docker et la pousse dans le registre GitLab.
  • Déploie sur un environnement via docker compose (à adapter).

stages:
 - test
 - build
 - deploy

variables:
 DOCKER_TLS_CERTDIR: "/certs"
 IMAGE_NAME: "$CI_REGISTRY_IMAGE"

test_backend:
 stage: test
 image: maven:3.9-eclipse-temurin-21
 script:
  - cd backend
  - mvn -q test
 cache:
  paths:
  - /root/.m2/repository

build_docker:
 stage: build
 image: docker:27
 services:
  - docker:27-dind
 variables:
  DOCKER_HOST: "tcp://docker:2375/"
  DOCKER_TLS_CERTDIR: ""
 before_script:
  - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
 script:
  - docker build -t $IMAGE_NAME:$CI_COMMIT_SHORT_SHA .
  - docker push $IMAGE_NAME:$CI_COMMIT_SHORT_SHA
  - docker tag $IMAGE_NAME:$CI_COMMIT_SHORT_SHA $IMAGE_NAME:latest
  - docker push $IMAGE_NAME:latest

deploy_staging:
 stage: deploy
 image: docker:27
 script:
  - echo "Déploiement sur staging..."
  - export IMAGE_TAG=$CI_COMMIT_SHORT_SHA
  - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  - docker pull $IMAGE_NAME:$IMAGE_TAG
  - docker compose -f docker-compose.staging.yml up -d --remove-orphans
 environment:
  name: staging
 only:
  - main

deploy_production:
 stage: deploy
 image: docker:27
 script:
  - echo "Déploiement en production..."
  - export IMAGE_TAG=$CI_COMMIT_SHORT_SHA
  - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  - docker pull $IMAGE_NAME:$IMAGE_TAG
  - docker compose -f docker-compose.production.yml up -d --remove-orphans
 environment:
  name: production
 only:
  - tags

Les fichiers docker-compose.staging.yml et docker-compose.production.yml doivent référencer l’image et utiliser la variable de tag. Une alternative consiste à transmettre le tag via une variable d’environnement dans Compose.

Déploiement Docker Compose (exemple)

Le déploiement peut être piloté par docker compose. Exemple simplifié :

version: "3.9"
services:
 app:
  image: <registry>/<group>/<project>:${IMAGE_TAG}
  ports:
  - "8080:8080"
  environment:
  - SPRING_PROFILES_ACTIVE=staging

La configuration exacte dépend de l’architecture (base de données, variables sensibles, réseau, reverse proxy, etc.). Les secrets doivent être gérés via GitLab CI/CD variables et jamais en dur dans les fichiers.

Bonnes pratiques pour un CI/CD fiable

Versionner les artefacts et tracer les déploiements

Le tag $CI_COMMIT_SHORT_SHA permet une traçabilité directe. Pour renforcer le suivi, l’utilisation de tags Git (v1.2.3) est recommandée côté production.

Utiliser les caches Maven et Node

Le cache accélère les pipelines : Maven via /root/.m2/repository, et Node via un cache de ~/.npm ou de node_modules (selon la stratégie retenue).

Définir une stratégie de test

L’exécution des tests doit être “gate” avant le build Docker final si possible. Pour Angular, l’ajout d’un job npm test (ou l’exécution de lint) peut être pertinent.

Gérer les variables d’environnement et les secrets

Les variables CI/CD doivent être stockées dans l’interface GitLab (Settings > CI/CD). Les tokens et mots de passe ne doivent jamais être exposés dans le repository.

Optimisations avancées

Réduire le temps de build

Les optimisations typiques incluent :

  • Cache Docker BuildKit (si disponible dans l’environnement Runner).
  • Découpage en images intermédiaires ou couches plus stables.
  • Tests unitaires rapides avant des tests plus coûteux.

Déploiement “blue/green” ou “rolling”

Pour les environnements critiques, une stratégie progressive (redémarrage contrôlé, bascule contrôlée, health checks) améliore la disponibilité. La configuration dépend de l’infrastructure (reverse proxy, orchestrateur, registres, etc.).

Conclusion

Une combinaison GitLab CI/CD et Docker permet d’automatiser l’intégration et le déploiement d’un produit Spring Boot/Angular de façon reproductible. Une pipeline structurée en étapes test, build et deploy, couplée à une stratégie de versionnement et de sécurité des secrets, constitue une base solide pour la production.

À 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