System Design

Comment j'aborde la conception de systemes microservices — decompose a travers un projet reel : une plateforme bancaire composee de 10 services Spring Boot sur AWS.

gitlab.com/bank-platform — lisons ensemble ce qui est implemente, pas ce qu'on suppose.

// Production Probe

Environnement de production reel — pas de staging, pas de simulation. L'instance EC2 tourne en mode economie (s'eteint quand inactive). Si vous tapez et que rien ne repond, c'est simplement coupe. Tentez votre chance ci-dessous.

PROBE — http://54.227.143.246:8081/actuator/healthinstance: i-YCOTMNWW

/* This is a live production probe. // The EC2 instance runs on economy mode — it boots on-demand and shuts down after use. // No uptime guarantee, just raw honesty. */

Press the probe button to send a live GET request
to the production health endpoint.

Ready

Avant de commencer

Dans cette section, je prends un projet existant et je le decompose. Pas de theorie pure — chaque choix d'architecture vient d'un fichier reel (README, Dockerfile, CI/CD). Quand je specule, je le dis. Le reste est documente dans les liens ci-dessus.

01

Architecture Microservices

Le systeme repose sur 10 services independants, chacun responsable d'un domaine metier precis. Ils communiquent soit de maniere synchrone (HTTP via gateway), soit asynchrone (Kafka pour les events de decouplage).

Synch REST via Gateway

bank-auth (:8081), bank-account (:8083), notification (:8084), reporting (:8085)

Asynchrone Kafka

bank-audit-service, bank-fraud-detection-service, bank-notification

Support

bank-config-service (12-Factor), bank-batch-service (lots)

02

API Gateway — le garde-frontiere

Toutes les requetes passent par Spring Cloud Gateway (:8080) — le seul point d'entree expose. Elle ne se limite pas au routage :

  • JWT globalRS256 — valide via Keycloak JWKS, routes publiques (/login, /register) exclues
  • Rate LimitingBucket4j — ex : 5 req/min par IP sur /api/auth
  • Circuit BreakerResilience4j — fallback immediat si un service est down
  • Correlation IDX-Correlation-ID propage de bout en bout dans les logs
/api/auth/** → :8081  |  /api/accounts/** → :8083  |  /api/notifications/** → :8084  |  /api/reports/** → :8085
03

Communication Inter-services

Synchrone — le client appelle un service via la gateway. Un service peut aussi en appeler un autre directement sur son port.

Asynchrone — Kafka comme bus d'evenements. bank-auth-service emet user.registered, les consumers (audit, fraude, notification) reagissent independamment. Decouplage & resilience.

04

Securite — IAM avec Keycloak

Keycloak comme serveur IAM/SSO. Connecte a PostgreSQL en JDBC pour persister les realms. Les tokens JWT RS256 sont valides asymetriquement au niveau de la gateway via le endpoint JWKS.

Point notable : en cas d'erreur entre l'insertion JPA et la creation du compte Keycloak, un deleteKeycloakUser() assure la coherence — pas de session serveur, tout est stateless.

Rate limiting sur les routes sensibles : protection brute-force sur /api/auth/**.

05

Docker & Docker Compose

Le Dockerfile multi-stage (bank-auth-service) :

Stage 1 — build

maven:3.9-eclipse-temurin-21
→ mvn package -DskipTests

Stage 2 — runtime

eclipse-temurin:21-jre-alpine
→ COPY --from=build app.jar

Image Alpine finale (JRE uniquement — pas de JDK). Le docker-compose.aws.yml orchestre postgres:15, keycloak:23.0 (avec realm import), Kafka + Zookeeper (Confluent 7.5.0), et bank-auth-service depuis ECR.

06

CI/CD — de commit a prod

Le pipeline bank-auth-service a 5 stages :

buildmvn packagetestmvn test + Postgres 15 Dockerdocker-buildDockerfile → GitLab Registrypush-ecraws ecr get-login-passworddeploytrigger infrastructure repo

Le job infrastructure/deploy-aws SSH sur EC2, git pull sur le repo infrastructure, login ECR, puis docker compose down + pull + up. Automatise de bout en bout — zero deploiement a la main.

// Flux entrant (api-gateway)

graph TD Client["Client (mobile / web)"] --> Gateway["API Gateway"]:::gateway Gateway -- HTTP --> Auth["bank-auth"]:::logic Gateway -- HTTP --> Account["bank-account"]:::logic %% Flux de production vers Kafka Auth -.->|Events| Kafka[/"Kafka (events cluster)"/]:::storage Account -.->|Events| Kafka %% Flux de consommation (Le coeur du système) Kafka --> Notif["Notification Service"]:::logic Kafka --> Audit["Audit Service"]:::logic Kafka --> Fraud["Fraud Detection"]:::security Kafka --> Report["Reporting Service"]:::logic classDef gateway fill:#1A1816,stroke:#D95A38,stroke-width:2px,color:#D95A38; classDef logic fill:#1A1816,stroke:#79B8E8,color:#79B8E8; classDef storage fill:#1A1816,stroke:#8DB67A,color:#8DB67A; classDef security fill:#1A1816,stroke:#B392D4,color:#B392D4;
System_Architecture_V2.0

// Flux entrant (api-gateway)

flowchart TD Client["Client / Postman"] --> Gateway["API Gateway :8080<br/>OAuth2 RS (RS256)"]:::gateway Gateway -- "1. Inscription" --> AuthService["Auth Service<br/>:8081"]:::logic AuthService -- "2. Create User (REST)" --> Keycloak["Keycloak<br/>:8180"]:::security Keycloak -- "JDBC" <--> DB[("PostgreSQL<br/>authdb")]:::storage AuthService -- "3. Publish UserCreated" --> Kafka[/"Kafka (events)"/]:::storage Kafka --> Notif["Notification Service<br/>:8082"]:::logic classDef gateway fill:#1A1816,stroke:#D95A38,stroke-width:2px,color:#D95A38; classDef logic fill:#1A1816,stroke:#79B8E8,color:#79B8E8; classDef security fill:#1A1816,stroke:#B392D4,color:#B392D4; classDef storage fill:#1A1816,stroke:#8DB67A,color:#8DB67A;
System_Architecture_V2.0

Les 4 piliers de l'architecture

API Gateway

Spring Cloud Gateway, Java 21, Spring Boot 4

JWT global (routes publiques exclues)Bucket4jResilience4jX-Correlation-ID
Microservices

REST derriere la gateway ; Kafka pour les evenements

bank-auth-servicebank-account-servicenotification-servicebank-reporting-serviceaudit / fraude (consumers)
Donnees

PostgreSQL 15, profils utilisateur cote auth

authdbKeycloak JDBCJPA / Hibernate
Securite

Keycloak , OAuth2, rate limit sur /api/auth

RS256JWKSevents Kafka user.registered

Ce que le code fait cote infra

Une gateway

Tout le trafic externe passe par Spring Cloud Gateway : JWT, rate limit, circuit breaker, correlation ID.

Services derriere

Routage par path : /api/auth, /api/accounts, /api/notifications, /api/reports. Auth et metier separes.

Donnees & IAM

PostgreSQL 15 (authdb), Keycloak sur le meme Postgres en dev/prod via compose. Tokens JWT RS256 cote gateway.

Keycloak

Realm importe au demarrage. Pas de session serveur : validation JWKS. Rollback manuel si incoherence JPA / IAM.

GitOps

Pipeline GitLab : build, image ECR, SSH vers EC2, git pull sur infrastructure, docker compose up. Pas de deploiement a la main.

Compose sur AWS

docker-compose.aws.yml : Postgres, Keycloak, Kafka/Zookeeper, image bank-auth-service depuis ECR.

Deploiement (infrastructure)

.gitlab-ci.yml (extrait)

Job deploy-aws : SSH vers la VM, git pull sur le repo infrastructure, login ECR, docker compose sur docker-compose.aws.yml.

deploy-aws:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client aws-cli
    - eval $(ssh-agent -s) && ssh-add $SSH_PRIVATE_KEY
  script:
    - ssh -o StrictHostKeyChecking=no ubuntu@${EC2_HOST} "
        export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} &&
        export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} &&
        cd /home/ubuntu/infrastructure &&
        git pull origin main &&
        aws ecr get-login-password ... | docker login ... ${AWS_ECR_REGISTRY} &&
        docker compose -f docker-compose.aws.yml down &&
        docker compose -f docker-compose.aws.yml pull &&
        docker compose -f docker-compose.aws.yml up -d &&
        docker system prune -af"
  only:
    - main

docker-compose.aws.yml (apercu)

Postgres, Keycloak (realm import), image auth depuis ECR, Kafka + Zookeeper. Aligne avec le fichier du repo.

services:
  postgres:        postgres:15
  keycloak:        quay.io/keycloak/keycloak:23.0
    command: start-dev --import-realm
    volumes: ./realm-export.json:/opt/keycloak/.../import/realm.json

  bank-auth-service:
    image: ${AWS_ECR_REGISTRY}/bank-auth-service:latest
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/authdb
      KEYCLOAK_ISSUER_URI: http://keycloak:8080/realms/bank-app
      SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
    depends_on: [postgres, keycloak, kafka]

  zookeeper:  confluentinc/cp-zookeeper:7.5.0
  kafka:      confluentinc/cp-kafka:7.5.0
    KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092

volumes:
  postgres_data:

Explorer le projet

Chaque service a son propre README, son Dockerfile et son pipeline CI. Les diagrams ci-dessus viennent directement de cette documentation.

gitlab.com/bank-platform

// COMM_LINK_ONLINE

Prêt pour la
prochaine mission ?_

STATUS: Disponible · Open to all France
ZONE: Bordeaux — France entière
>[ Initier_Contact ]