# Dockeriser Spring Boot sans Dockerfile
## Introduction
Vous êtes un développeur backend orienté `Spring Boot` et vous débutez un nouveau projet. Il y a de fortes chances que l'on vous demande de configurer à un moment ou un autre de déployer votre projet via `Docker`. Là, on a tous le même réflexe : créer un `Dockerfile`. Après une petite recherche sur les internets, vous devriez obtenir quelque chose comme ceci :
```Dockerfile
FROM openjdk:11-jre-slim
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
```
> Oui, ça vient d'un [exemple officiel](https://spring.io/guides/gs/spring-boot-docker/).
L'étape suivante serait d'effectuer :
```bash
docker build . -t demo:0.0.1-SNAPSHOT
```
et
```bash
docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT
```
Mais si je vous disais que l'on peut se passer de cette phase de configuration à partir de `Spring Boot 2.3` ? Car honnêtement, quelle est la plus-value de refaire toujours cette configuration qui restera dans 90% des cas la même ? Je vais vous montrer par la suite une manière de s'en passer !
## Un peu de magie
### Prérequis
Commençons par se créer un projet Spring Boot. Nous pouvons soit passer par notre IDE favori, soit par [start.spring.io](https://start.spring.io/). Par simplicité, on va utiliser le second, avec curl :
```bash
curl https://start.spring.io/starter.zip -d bootVersion=2.3.4 -d dependencies=web -o demo.zip
unzip demo.zip
```
> On demande à générer un projet spring boot en version 2.3.4, nommé "demo", avec le starter web.
### On passe à l'action
Depuis Spring Boot 2.3, il est très simple de créer une image docker à partir de votre projet, sans toucher à un `Dockerfile` :
```bash
mvn spring-boot:build-image
```
Et là, quelques minutes plus tard, la magie opère et vous pouvez lancer votre conteneur avec la commande :
```bash
docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT
```
## Mais c'est quoi le truc ?
### Buildpacks
Sous le capot, Spring Boot utilise [buildpacks](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-java), une techno lancée par Heroku, qui va grosso modo analyser votre application et aller chercher toutes les dépendances manquantes pour la faire tourner. Sur du Spring Boot, buildpacks va aller automatiquement chercher la JRE nécessaire pour faire tourner le .jar produit. L'avantage de buildpacks est ici de ne plus avoir à se soucier des dépendances nécessaires à l'exécution du code pour se concentrer sur l'écriture de ce dernier.
Une évolution de buildpacks, sobrement intitulée [buildpacks cloud natives](https://buildpacks.io/) permet de générer des conteneurs. Ces images sont au format [Open Container Initiative](https://opencontainers.org/). OCI est un standard open-source qui permet d'avoir des images le plus agnostique possible des insfrastructures, des cloud providers ou encore des outils devops. Si vous voulez en savoir un peu plus sur les liens entre OCI et Docker, je vous conseille la lecture de cet [article.](https://blog.alterway.fr/le-point-sur-les-container-runtimes.html)
### Et si je veux personnaliser la chose ?
Par défaut, le nom de l'image vaut `docker.io/library/${project.artifactId}:${project.version}` mais il peut être personnalisé en changeant la propriété suivante dans la configuration de `spring-boot-maven-plugin` du **pom.xml** :
```xml
org.springframework.boot
spring-boot-maven-plugin
2.3.4.RELEASE
nom-image:un-tag
```
> Si un tag n'est pas précisé, il aura pour valeur *latest*.
Si vous voulez également personnaliser le processus de build de l'image, certaines variables peuvent être précisées de la façon suivante :
```xml
...
http://proxy.example.com
https://proxy.example.com
...
```
Voici la liste des variables disponibles :
- HTTP_PROXY : Préciser un proxy HTTP au builder (pour le téléchargement des `runtimes`)
- HTTPS_PROXY : Préciser un proxy HTTPS au builder (pour le téléchargement des `runtimes`)
- BP_JVM_VERSION : Préciser la version de Java à utiliser (si on ne souhaite pas utiliser celle du **pom.xml**)
- JAVA_TOOL_OPTIONS : Les options de lancement de la JVM
Concernant la partie conteneur, on peut aussi directement injecter les variables d'environnement au `docker run`, comme ici le profil spring qui nous intéresse :
```bash
docker run -e "SPRING_PROFILES_ACTIVE=prod" -it -p8080:8080 demo:0.0.1-SNAPSHOT
```
## :new: Mise à jour avec Spring Boot 2.4
Spring Boot 2.4 apporte une nouveauté intéressante : il est possible de configurer une registry directement dans le **pom.xml** pour y envoyer l'image une fois construite. Pour cela, il suffit de renseigner les paramètres suivants dans la configuration du plugin maven :
```xml
org.springframework.boot
spring-boot-maven-plugin
docker.example.com/library/${project.artifactId}
true
user
secret
https://docker.example.com/v1/
user@example.com
```
On peut également passer ces paramètres dans la commande de build de l'application :
```bash
mvn spring-boot:build-image -Dspring-boot.build-image.imageName=docker.example.com/library/my-app:v1 -Dspring-boot.build-image.publish=true
```
## Intégration avec Spring Dev Tools
### Configuration préliminaire
Si vous utilisez `Spring Dev Tools` dans votre projet, vous avez l'habitude de disposer de *Hot Reload* après avoir rebuildé votre application (`Build > Build Projet` dans le menu d'IntelliJ) )
Avec Spring Boot 2.3, il est possible de pousser la manipulation un peu plus loin et de disposer de *Hot Reload*, directement sur votre image docker.
La première étape consiste à... embarquer Spring Dev Tools dans votre image docker ! On va pour cela modifier notre **pom.xml** pour ne plus l'exclure (ce qui était le comportement par défaut) :
```xml
org.springframework.boot
spring-boot-maven-plugin
false
```
En second lieu, il nous faut déclarer un secret dans notre configuration applicative : un petit tour par l'**application.properties** et c'est fait :
```properties
spring.devtools.remote.secret=Ceci est un secret, pas si secret ;)
```
> Cette propriété est là pour sécuriser une connexion à distance. On doit la préciser en local, mais sa valeur n'a pas d'importance dans cet exemple.
Pour que ces changements soient pris en compte, il nous faut récréer notre image docker, puis en instancier un conteneur :
```bash
mvn spring-boot:build-image
```
et
```bash
docker run -it -p8080:8080 demo:0.0.1-SNAPSHOT
```
### Lancement
Il s'agit maintenant de faire communiquer notre IDE avec le conteneur docker qui tourne, afin de le mettre à jour à chaque fois que l'on build notre code :
![image info](SpringBootDockerConfigurationIde.png)
Il s'agit donc de définir l'exécution d'une "Application" avec comme *Main class* :
```java
org.springframework.boot.devtools.RemoteSpringApplication
```
et comme *Program argument* : http://localhost:8080
> 8080 étant le port publié du conteneur ;)
On lance cette application, on fait nos requêtes sur **http://localhost:8080** et bim, à chaque fois que l'on rebuild l'application, le conteneur est mis à jour avec nos changements !
## Conclusion
Dans cet article on aura vu comment facilement "dockeriser" notre application Spring Boot et comment paramétrer l'image docker générée. Puis on aura vu comment intégrer ce mécanisme avec Spring Boot Developper Tools.
Vous pourrez retrouver les sources liées à cet article sur [notre gitlab.](https://gitlab.com/maxds-public/spring-boot-docker)