Pourquoi Deployer Spring Boot avec Docker ?
Le déploiement d'une application Spring Boot avec Docker est une pratique courante dans l'industrie moderne de la développement logiciel. Le Docker permet une meilleure portabilité, facilité de déploiement et sécurité des applications. En effet, grâce à Docker, vous pouvez empaqueter votre application Java en un conteneur léger, qui peut être exécuté sur n'importe quel environnement qui supporte Docker.
Un cas d'utilisation concret est l'environnement cloud : les services tels que AWS Elastic Beanstalk, Google Cloud Run et Azure App Service offrent une intégration native avec Docker. Cela permet aux développeurs de déployer rapidement leurs applications sans se préoccuper des infrastructures sous-jacentes.
Prerequis
- Connaissance Java et Spring Boot
- Java Development Kit (JDK) 11 ou plus récent
- Apache Maven 3.x
- Docker Engine 20.10 ou plus récent
- Un IDE comme IntelliJ IDEA, Eclipse ou VSCode
Concepts fondamentaux
Dockerfile
Un Dockerfile est un fichier texte qui contient des instructions pour construire une image Docker. Voici la structure d'un Dockerfile simple :
## Utilise une image Java de base comme l'image parente
FROM openjdk:17-jdk-slim
## Défini le répertoire de travail dans le conteneur
WORKDIR /app
## Copie les fichiers du projet vers le répertoire de travail
COPY target/your-application.jar /app/your-application.jar
## Expose le port d'écoute de l'application (par exemple 8080)
EXPOSE 8080
## Démarre l'application lors du démarrage du conteneur
CMD ["java", "-jar", "your-application.jar"]
docker-compose.yml
Le fichier docker-compose.yml permet de définir et d'exécuter plusieurs services Docker. C'est particulièrement utile pour les applications qui dépendent de plusieurs microservices.
version: '3'
services:
app:
build: .
ports:
- "8080:8080"
depends_on:
- db
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: yourdb
MYSQL_USER: user
MYSQL_PASSWORD: password
Docker Hub
Docker Hub est une plateforme en ligne qui permet de stocker, partager et déployer des images Docker. Il est utile pour publier vos propres images et les utiliser dans différents environnements.
Mise en pratique : projet fil rouge
Nous allons créer un mini-projet complet : une application Spring Boot simple qui expose une API REST pour gérer des tâches. Cette application sera ensuite déployée sur Docker.
Etape 1: Créer le projet
Créer un nouveau projet Spring Boot via Spring Initializr en choisissant les options suivantes :
- Project: Maven Project
- Language: Java
- Spring Boot: 2.7.x
- Project Metadata:
- Group: com.example
- Artifact: taskmanager
- Name: taskmanager
- Description: Demo project for Task Manager API
- Package name: com.example.taskmanager
- Packaging: Jar
- Java: 11 or later
- Dependencies: Spring Web, H2 Database
Etape 2: Créer le modèle de données
Créez un fichier Task.java dans le package com.example.taskmanager.model :
package com.example.taskmanager.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private boolean completed;
// Getters and Setters
}
Etape 3: Créer le repository
Créez un fichier TaskRepository.java dans le package com.example.taskmanager.repository :
package com.example.taskmanager.repository;
import com.example.taskmanager.model.Task;
import org.springframework.data.jpa.repository.JpaRepository;
public interface TaskRepository extends JpaRepository<Task, Long> {
}
Etape 4: Créer le service
Créez un fichier TaskService.java dans le package com.example.taskmanager.service :
package com.example.taskmanager.service;
import com.example.taskmanager.model.Task;
import com.example.taskmanager.repository.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class TaskService {
@Autowired
private TaskRepository taskRepository;
public List<Task> getAllTasks() {
return taskRepository.findAll();
}
public Task getTaskById(Long id) {
return taskRepository.findById(id).orElse(null);
}
public Task createTask(Task task) {
return taskRepository.save(task);
}
public Task updateTask(Long id, Task taskDetails) {
Task task = taskRepository.findById(id).orElseThrow(() -> new RuntimeException("Task not found"));
task.setTitle(taskDetails.getTitle());
task.setCompleted(taskDetails.isCompleted());
return taskRepository.save(task);
}
public void deleteTask(Long id) {
taskRepository.deleteById(id);
}
}
Etape 5: Créer le contrôleur REST
Créez un fichier TaskController.java dans le package com.example.taskmanager.controller :
package com.example.taskmanager.controller;
import com.example.taskmanager.model.Task;
import com.example.taskmanager.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
@Autowired
private TaskService taskService;
@GetMapping
public List<Task> getAllTasks() {
return taskService.getAllTasks();
}
@GetMapping("/{id}")
public ResponseEntity<Task> getTaskById(@PathVariable Long id) {
Task task = taskService.getTaskById(id);
if (task != null) {
return ResponseEntity.ok(task);
} else {
return ResponseEntity.notFound().build();
}
}
@PostMapping
public Task createTask(@RequestBody Task task) {
return taskService.createTask(task);
}
@PutMapping("/{id}")
public ResponseEntity<Task> updateTask(@PathVariable Long id, @RequestBody Task taskDetails) {
Task updatedTask = taskService.updateTask(id, taskDetails);
if (updatedTask != null) {
return ResponseEntity.ok(updatedTask);
} else {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteTask(@PathVariable Long id) {
taskService.deleteTask(id);
return ResponseEntity.noContent().build();
}
}
Etape 6: Créer le fichier application.properties
Créez un fichier application.properties dans le répertoire src/main/resources :
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
Etape 7: Créer le Dockerfile
Créez un fichier Dockerfile à la racine de votre projet :
## Utilise une image Java de base comme l'image parente
FROM openjdk:17-jdk-slim
## Défini le répertoire de travail dans le conteneur
WORKDIR /app
## Copie les fichiers du projet vers le répertoire de travail
COPY target/taskmanager-0.0.1-SNAPSHOT.jar /app/taskmanager.jar
## Expose le port d'écoute de l'application (par exemple 8080)
EXPOSE 8080
## Démarre l'application lors du démarrage du conteneur
CMD ["java", "-jar", "taskmanager.jar"]
Etape 8: Construire et exécuter l'image Docker
Construire l'image Docker avec la commande suivante :
docker build -t taskmanager .
Exécuter le conteneur Docker avec la commande suivante :
docker run -p 8080:8080 taskmanager
Accédez à http://localhost:8080/api/tasks dans votre navigateur pour vérifier que l'API fonctionne correctement.
Erreurs frequentes et debugging
1. L'image Docker ne se construit pas
Message d'erreur :
Step 4/6 : COPY target/taskmanager-0.0.1-SNAPSHOT.jar /app/taskmanager.jar
COPY failed: stat /var/lib/docker/tmp/docker-builder892756664/target/taskmanager-0.0.1-SNAPSHOT.jar: no such file or directory
Code incorrect :
COPY target/taskmanager-0.0.1-SNAPSHOT.jar /app/taskmanager.jar
Code correct :
COPY target/*.jar /app/taskmanager.jar
2. L'application ne démarre pas dans le conteneur Docker
Message d'erreur :
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
Code incorrect :
spring.datasource.url=jdbc:h2:mem:testdb
Code correct :
spring.datasource.url=jdbc:h2:file:/app/db/testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
3. L'API n'est pas accessible depuis l'hôte
Message d'erreur :
curl -X GET http://localhost:8080/api/tasks
curl: (7) Failed to connect to localhost port 8080: Connection refused
Code incorrect :
EXPOSE 8080
Code correct :
EXPOSE 8080
## Expose le port d'écoute de l'application (par exemple 8080)
CMD ["java", "-jar", "taskmanager.jar"]
Pour aller plus loin
Utilisation de Docker Compose pour gérer les dépendances : Apprenez à utiliser
docker-compose.ymlpour définir et exécuter plusieurs services.Publications d'images Docker sur Docker Hub : Enregistrez votre image Docker sur Docker Hub afin de la partager et la réutiliser dans différents environnements.
Déploiement sur des plateformes cloud : Découvrez comment déployer votre application Spring Boot Dockerisée sur des plateformes tels que AWS Elastic Beanstalk, Google Cloud Run ou Azure App Service.
Défi pratique
Créez une application Spring Boot qui utilise un service de base de données relationnelle et expose une API REST pour gérer des utilisateurs. Utilisez Docker pour empaqueter l'application et déployez-la sur votre propre environnement local ou sur une plateforme cloud.
N'oubliez pas d'inclure les fichiers Dockerfile et docker-compose.yml dans votre projet, ainsi que la configuration de base de données appropriée. Assurez-vous que l'application fonctionne correctement avant de passer à la publication sur Docker Hub ou le déploiement sur une plateforme cloud.