Spring Boot en production : Checklist de déploiement

12 min readPar SpringCraft

Ton application Spring Boot fonctionne parfaitement en local. Tu es prêt à la déployer en production !

Mais attends... As-tu pensé à :

  • Sécuriser tes endpoints ?
  • Configurer les logs pour la production ?
  • Optimiser les performances ?
  • Mettre en place du monitoring ?

Déployer en production sans préparation, c'est comme sauter en parachute sans vérifier le parachute. Ça peut marcher... ou pas.

Dans cet article, nous allons voir tout ce qu'il faut vérifier avant de déployer en production. Cette checklist t'évitera 99% des problèmes courants.

Contexte technique

Versions utilisées :

  • Spring Boot 3.2+
  • Java 17+
  • Spring Security pour la sécurité
  • Spring Boot Actuator pour le monitoring
  • Micrometer pour les métriques

Sommaire


Sécurité

✅ Checklist Sécurité

1. Activer HTTPS

Pourquoi ? Sans HTTPS, toutes les données (mots de passe, tokens, etc.) circulent en clair sur le réseau.

Comment ?

# application-prod.yml
server:
  port: 443
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: ${SSL_KEYSTORE_PASSWORD}
    key-store-type: PKCS12

Alternative : Utilisez un reverse proxy (Nginx, Traefik) qui gère le SSL.

2. Configurer Spring Security

Minimum requis :

@Configuration
@EnableWebSecurity
public class SecurityConfig {
 
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()  // Endpoints publics
                .requestMatchers("/actuator/health").permitAll()  // Health check
                .anyRequest().authenticated()  // Tout le reste nécessite une authentification
            )
            .oauth2ResourceServer(oauth2 -> oauth2.jwt());  // Si vous utilisez JWT
 
        return http.build();
    }
}

Conseil : Utilisez OAuth2/JWT pour l'authentification des API REST.

3. Valider TOUTES les entrées utilisateur

Mauvais :

@PostMapping("/users")
public User createUser(@RequestBody CreateUserRequest request) {
    // Pas de validation, accepte n'importe quoi
    return userService.createUser(request);
}

Bon :

@PostMapping("/users")
public User createUser(@Valid @RequestBody CreateUserRequest request) {
    // @Valid active la validation automatique
    return userService.createUser(request);
}

4. Protéger contre les injections SQL

Mauvais :

String query = "SELECT * FROM users WHERE email = '" + email + "'";  // Injection SQL possible !

Bon :

@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);  // Paramètre sécurisé

Encore mieux : Utilisez Spring Data JPA qui protège automatiquement.

Optional<User> findByEmail(String email);  // Sécurisé par défaut

5. Ne JAMAIS exposer les secrets dans le code

Mauvais :

spring:
  datasource:
    password: SuperMotDePasseSecret123  # 🚨 Visible dans Git !

Bon :

spring:
  datasource:
    password: ${DATABASE_PASSWORD}  # Variable d'environnement

6. Configurer CORS correctement

Mauvais :

@CrossOrigin(origins = "*")  // Accepte TOUTES les origines !

Bon :

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                    .allowedOrigins("https://monsite.com", "https://www.monsite.com")
                    .allowedMethods("GET", "POST", "PUT", "DELETE")
                    .allowCredentials(true);
            }
        };
    }
}

7. Désactiver les endpoints sensibles

# application-prod.yml
spring:
  h2:
    console:
      enabled: false  # Jamais en production !
 
management:
  endpoints:
    web:
      exposure:
        include: health,info  # Seulement les endpoints nécessaires

Configuration

✅ Checklist Configuration

1. Profil de production actif

Vérifiez que le profil prod est bien actif :

export SPRING_PROFILES_ACTIVE=prod

Ou dans le script de démarrage :

java -jar app.jar --spring.profiles.active=prod

2. Désactiver ddl-auto

CRITIQUE : Ne JAMAIS utiliser create-drop ou update en production.

# application-prod.yml
spring:
  jpa:
    hibernate:
      ddl-auto: none  # ⚠️ Très important !

Pourquoi ?

  • create-drop supprime toutes les données au redémarrage
  • update peut corrompre la base en production

Solution : Utilisez Flyway ou Liquibase pour gérer les migrations.

3. Configurer les timeouts

spring:
  datasource:
    hikari:
      connection-timeout: 30000  # 30 secondes
      maximum-pool-size: 20
      minimum-idle: 5

4. Désactiver les logs SQL

spring:
  jpa:
    show-sql: false  # Ralentit l'application

5. Configuration du serveur

server:
  port: ${SERVER_PORT:8080}
  shutdown: graceful  # Graceful shutdown
  tomcat:
    threads:
      max: 200
      min-spare: 10

Base de données

✅ Checklist Base de données

1. Utiliser une vraie base de données

Mauvais :

# En production avec H2 en mémoire = DÉSASTRE !
spring:
  datasource:
    url: jdbc:h2:mem:testdb

Bon :

spring:
  datasource:
    url: ${DATABASE_URL}
    driver-class-name: org.postgresql.Driver

2. Pool de connexions optimisé

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      max-lifetime: 1800000  # 30 minutes
      connection-timeout: 30000
      idle-timeout: 600000  # 10 minutes

Calcul du pool : max_pool_size = nombre_de_threads_tomcat / nombre_de_services

3. Migrations versionnées

Utilisez Flyway ou Liquibase.

Exemple avec Flyway :

<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>
-- src/main/resources/db/migration/V1__initial_schema.sql
CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email VARCHAR(100) NOT NULL UNIQUE,
    name VARCHAR(100) NOT NULL,
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP
);

4. Sauvegardes automatiques

Configurez des sauvegardes automatiques de votre base :

  • Fréquence : Quotidienne minimum, idéalement plusieurs fois par jour
  • Rétention : Au moins 7 jours
  • Testez les restaurations régulièrement

5. Indexes sur les colonnes fréquemment requêtées

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_id ON orders(user_id);

Comment savoir quels index créer ?

  • Analysez les requêtes lentes avec EXPLAIN ANALYZE
  • Indexez les colonnes dans les WHERE, JOIN, ORDER BY

Logs et monitoring

✅ Checklist Logs

1. Configurer les niveaux de logs

# application-prod.yml
logging:
  level:
    root: WARN  # Logs minimaux
    com.springcraft: INFO  # Votre code en INFO
    org.springframework: WARN
    org.hibernate: WARN
  file:
    name: /var/log/springcraft/application.log
    max-size: 10MB
    max-history: 30  # Garde 30 jours

Pourquoi pas DEBUG en prod ?

  • Les logs DEBUG sont très verbeux
  • Ralentissent l'application
  • Remplissent rapidement le disque

2. Logs structurés (JSON)

Utilisez un format JSON pour faciliter l'analyse :

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>7.3</version>
</dependency>
<!-- logback-spring.xml -->
<configuration>
    <appender name="JSON" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/var/log/springcraft/application.log</file>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
 
    <root level="INFO">
        <appender-ref ref="JSON"/>
    </root>
</configuration>

3. Activer Spring Boot Actuator

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: when-authorized
  metrics:
    export:
      prometheus:
        enabled: true

Endpoints utiles :

  • /actuator/health : État de l'application
  • /actuator/metrics : Métriques (mémoire, CPU, requêtes, etc.)
  • /actuator/prometheus : Métriques au format Prometheus

4. Monitoring avec Prometheus + Grafana

  1. Prometheus : Collecte les métriques
  2. Grafana : Visualise les métriques

Dashboard Grafana recommandé : Spring Boot 2.1 Statistics (ID : 10280)

5. Alertes

Configurez des alertes pour :

  • ❌ Application down
  • 💥 Taux d'erreur > 5%
  • 🐌 Temps de réponse > 2 secondes
  • 💾 Mémoire > 80%
  • 💿 Disque > 90%

Performance

✅ Checklist Performance

1. Activer le cache

spring:
  cache:
    type: redis  # Ou caffeine pour un cache local
@Service
public class UserService {
 
    @Cacheable(value = "users", key = "#id")
    public UserDTO getUserById(Long id) {
        // Résultat mis en cache
        return userRepository.findById(id)...
    }
 
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        // Invalide le cache
        userRepository.deleteById(id);
    }
}

2. Optimiser les requêtes JPA

Problème N+1 :

Mauvais :

List<User> users = userRepository.findAll();  // 1 requête
for (User user : users) {
    user.getOrders().size();  // N requêtes (1 par utilisateur) !
}

Bon :

@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders")
List<User> findAllWithOrders();  // 1 seule requête

3. Pagination

Ne renvoyez jamais tous les résultats d'un coup :

@GetMapping("/users")
public Page<UserDTO> getAllUsers(Pageable pageable) {
    return userService.getAllUsers(pageable);
}

Utilisation : GET /api/users?page=0&size=20

4. Compression des réponses

server:
  compression:
    enabled: true
    mime-types: application/json,application/xml,text/html,text/xml,text/plain

5. Configuration JVM

java -Xms512m -Xmx2g \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -jar app.jar

Explication :

  • -Xms512m : Heap initial de 512 Mo
  • -Xmx2g : Heap max de 2 Go
  • -XX:+UseG1GC : Utilise le garbage collector G1 (recommandé)
  • -XX:MaxGCPauseMillis=200 : Pause GC max de 200ms

Résilience

✅ Checklist Résilience

1. Health checks

@Component
public class DatabaseHealthIndicator implements HealthIndicator {
 
    @Autowired
    private DataSource dataSource;
 
    @Override
    public Health health() {
        try {
            dataSource.getConnection().close();
            return Health.up().build();
        } catch (Exception e) {
            return Health.down().withException(e).build();
        }
    }
}

2. Retry automatique

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
@Service
public class ExternalApiService {
 
    @Retryable(
        value = { RestClientException.class },
        maxAttempts = 3,
        backoff = @Backoff(delay = 1000)
    )
    public String callExternalApi() {
        // Retry automatique en cas d'échec
        return restTemplate.getForObject("https://api.example.com/data", String.class);
    }
}

3. Circuit breaker

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
@Service
public class ExternalApiService {
 
    @CircuitBreaker(name = "externalApi", fallbackMethod = "fallback")
    public String callExternalApi() {
        return restTemplate.getForObject("https://api.example.com/data", String.class);
    }
 
    public String fallback(Exception e) {
        return "Service temporairement indisponible";
    }
}

4. Graceful shutdown

server:
  shutdown: graceful
 
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

Effet : Quand vous arrêtez l'application, Spring attend que toutes les requêtes en cours se terminent (max 30s).


Tests

✅ Checklist Tests

1. Couverture de code > 80%

Utilisez JaCoCo pour mesurer la couverture :

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.10</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Générer le rapport : mvn jacoco:report

2. Tests unitaires pour la logique métier

Minimum : Testez tous vos services.

3. Tests d'intégration pour les endpoints

Testez au moins les endpoints critiques (création, authentification, etc.).

4. Tests de charge (si forte volumétrie)

Utilisez JMeter, Gatling ou k6 pour simuler du trafic.


Documentation

✅ Checklist Documentation

1. README complet

Incluez :

  • Description du projet
  • Comment installer les dépendances
  • Comment lancer en local
  • Comment déployer
  • Variables d'environnement requises

2. Documentation API

Utilisez Swagger/OpenAPI :

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.2.0</version>
</dependency>

Accès : http://localhost:8080/swagger-ui.html

3. Diagrammes d'architecture

Créez au moins :

  • Schéma de l'architecture globale
  • Diagramme de la base de données

Déploiement

✅ Checklist Déploiement

1. CI/CD configuré

Automatisez le déploiement avec GitHub Actions, GitLab CI, Jenkins, etc.

Exemple GitHub Actions :

name: Deploy to Production
 
on:
  push:
    branches: [main]
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
      - name: Build
        run: mvn clean package
      - name: Deploy
        run: ./deploy.sh

2. Blue/Green ou Canary deployment

Ne déployez jamais directement en production. Utilisez :

  • Blue/Green : Deux environnements identiques, switch instantané
  • Canary : Déploiement progressif (10% du trafic, puis 50%, puis 100%)

3. Rollback facile

Gardez toujours la possibilité de revenir à la version précédente en 1 clic.


Post-déploiement

✅ Checklist Post-déploiement

1. Smoke tests

Vérifiez immédiatement après le déploiement :

  • L'application démarre
  • Les endpoints critiques fonctionnent
  • La base de données est accessible

2. Monitoring des logs

Surveillez les logs pendant les premières heures pour détecter des erreurs.

3. Alertes configurées

Vérifiez que vous recevez les alertes (email, Slack, PagerDuty, etc.).


Checklist complète (résumé)

Sécurité

  • HTTPS activé
  • Spring Security configuré
  • Validation sur tous les endpoints
  • Pas d'injection SQL
  • Secrets externalisés
  • CORS configuré correctement

Configuration

  • Profil prod actif
  • ddl-auto: none
  • Timeouts configurés
  • Logs SQL désactivés

Base de données

  • Base de données persistante (pas H2)
  • Pool de connexions optimisé
  • Migrations versionnées (Flyway/Liquibase)
  • Sauvegardes automatiques
  • Indexes créés

Logs et Monitoring

  • Logs en niveau INFO/WARN
  • Actuator activé
  • Prometheus/Grafana configuré
  • Alertes configurées

Performance

  • Cache activé
  • Requêtes JPA optimisées
  • Pagination activée
  • Compression activée
  • JVM configurée

Résilience

  • Health checks configurés
  • Retry activé
  • Circuit breaker configuré
  • Graceful shutdown activé

Tests

  • Couverture > 80%
  • Tests unitaires
  • Tests d'intégration
  • Tests de charge (si nécessaire)

Documentation

  • README complet
  • Documentation API (Swagger)
  • Diagrammes d'architecture

Déploiement

  • CI/CD configuré
  • Blue/Green ou Canary
  • Rollback facile

Post-déploiement

  • Smoke tests effectués
  • Logs surveillés
  • Alertes testées

Pour aller plus loin

Félicitations ! Vous avez maintenant une checklist complète pour déployer en production en toute sérénité. 🎉

📚 Série d'articles complémentaires

  1. Comment structurer un projet Spring Boot - Les fondations
  2. Tests dans Spring Boot : Guide complet - Testez avant de déployer
  3. Configuration multi-environnements - Séparez dev/test/prod
  4. Gestion des exceptions dans Spring Boot - Gérez les erreurs proprement
  5. CRUD complet avec Spring Boot - Un exemple complet

🎯 Points clés à retenir

  1. Sécurisez tout : HTTPS, secrets, validation
  2. Monitorer : Logs, métriques, alertes
  3. Optimisez : Cache, pagination, requêtes
  4. Testez : Unitaire, intégration, charge
  5. Automatisez : CI/CD, déploiement, rollback
  6. Documentez : README, API, architecture

Déployer en production, ce n'est pas juste lancer l'application. C'est s'assurer qu'elle fonctionne bien, qu'elle est sécurisée, qu'elle performe, et qu'on peut la débugger facilement.

Bon déploiement ! 🚀