Comment déployer une application Spring Boot dans Kubernetes ?

JAVA Spring boot on Kubernetes

Dans cet article, nous nous concentrerons sur le déploiement d’une simple application Spring Boot dans Kubernetes. Le code source de l’application se trouve sur Github: spring-boot-k8s ; c’est un service simple qui expose un point de terminaison GET /hello/{name} qui retourne une simple chaîne « hello {name} ». Avant de passer à la partie intéressante ; veuillez-vous assurer que Java et docker sont installés et examinons d’abord quelques définitions.

Qu’est-ce qu’un conteneur?

Un conteneur est une unité logicielle standard qui regroupe le code et toutes ses dépendances; de sorte que l’application s’exécute rapidement et de manière fiable d’un environnement informatique à un autre.

Nous allons utiliser une architecture microservices, votre demande sera composée d’un ensemble de services où chaque service sera livré dans un conteneur. Ensuite dans les étapes de développement, vous pouvez avoir qu’une seule instance de chaque conteneur afin d’exécuter vos microservices. Mais cela n’est pas autorisé en production où vous devez assurer la haute disponibilité, la tolérance aux pannes et la résilience de vos services, sans temps d’arrêt. Cela signifie que vous devrez mettre à l’échelle vos services sur plusieurs nœuds et clusters.

Afin de gérer plusieurs conteneurs et plusieurs nœuds, vous avez besoin d’un orchestrateur de conteneurs. Il existe de nombreux orchestrateurs de conteneurs tels que:

  • Édition Docker Entreprise (Docker EE)
  • Mésosphère (DC / OS)
  • Kubernetes (K8S)

Qu’est-ce que Kubernetes?

Kubernetes (k8s) est une orchestration conteneur open source pour automatiser le déploiement, la mise à l’échelle et la gestion des applications. Il a été conçu à l’origine par Google, maintenant il est maintenu par la Cloud Native Computing Foundation (CNCF). Il vise à fournir une «plate-forme pour automatiser le déploiement, la mise à l’échelle et les opérations des conteneurs d’applications sur des clusters d’hôtes». Vous pouvez trouver plus de détails ici .

Kubernetes gère un cluster de nœuds. Un nœud est une machine de travail dans Kubernetes, anciennement appelée minion. Un nœud peut être une machine virtuelle ou une machine physique, selon le cluster. Chaque nœud contient les services nécessaires à l’exécution des pods et est géré par les composants principaux. Les services sur un nœud incluent le runtime du conteneur , kubelet et kube-proxy.

Le nœud maître est appelé le plan de contrôle : le cerveau du cluster (architecture Kubernetes ci-dessous).

JAVA Spring boot on Kubernetes

Installer Kubernetes localement (Kubectl + Minikube)

Kubectl:

L’outil de ligne de commande Kubernetes , kubectl , vous permet d’exécuter des commandes sur des clusters Kubernetes. Vous pouvez utiliser kubectl pour déployer des applications (notre application Spring Boot) sur Kubernetes, inspecter et gérer les ressources du cluster et afficher les journaux. 

Vous pouvez trouver des instructions sur la façon d’installer kubectl dans ce lien .

Minikube:

C’est un outil qui facilite l’exécution de Kubernetes localement. Il exécute un cluster Kubernetes à nœud unique dans une machine virtuelle (VM), sur votre ordinateur portable pour les utilisateurs qui souhaitent essayer Kubernetes ou développer avec lui au quotidien.

Vous pouvez suivre les instructions d’installation , une fois installé, assurez-vous que le docker est en cours d’exécution, puis démarrez minikube :

minikube start -p minikube-vbox --vm-driver = virtualbox

Créer et publier une image docker

Créer l’image Docker:

Kubernetes déploie et gère des conteneurs à l’aide d’images publiées sur un référentiel Docker. C’est pourquoi nous devons créer une image docker pour notre application Spring Boot, puis la pousser vers un référentiel docker (docker hub) pour le déployer sur Kubernetes.

Docker crée automatiquement des images en lisant les instructions d’un Dockerfile : fichier texte qui contient toutes les commandes, dans l’ordre, nécessaires pour créer une image donnée. Pour cela, nous allons créer un fichier appelé Dockerfile (sans extension) qui contient les éléments suivants:

FROM openjdk:11.0-jre-stretch 
MAINTAINER Oussama ABAI <oussamaabai@gmail.com> 
WORKDIR /usr/share/digicactus-k8s 
ARG appDir=/usr/share/digicactus-k8s 
ARG DEPENDENCY=target/dependency 
COPY ${DEPENDENCY}/BOOT-INF/lib ${appDir}/lib 
COPY ${DEPENDENCY}/META-INF ${appDir}/META-INF 
COPY ${DEPENDENCY}/BOOT-INF/classes ${appDir} 
EXPOSE 8081 5005 
ENTRYPOINT["java","cp","com/example/demo/*:lib/*:.","com.example.demo.DemoApplication"]

Notez que lors de la création d’image, chaque instruction représente une couche d’image en lecture seule (delta). Et lors de l’exécution des instructions, le docker recherche une image existante dans son cache, qui peut être réutilisée plutôt que de créer une nouvelle image (dupliquée).

Les meilleures pratiques

Pour éviter l’inefficacité, les charges lourdes et le gaspillage de stockage, nous utilisons une image docker légère JRE 11 comme image de base, et nous ne copions pas le FAT JAR (fourni par Spring-boot-maven-plugin) dans l’image de base. 

Au lieu de cela, nous utilisons le plugin maven-dependency-plugin pour décompresser le FAT JAR sous target/dependency puis nous copions /BOOT-INF/lib , /BOOT-INF/classes et /META-INF dans l’image de base puis dans le ENTRYPOINT que nous exécutons la classe principale, en spécifiant le chemin de classe.

Pour créer l’image, exécutez :

docker build -t springboot:0.1.0 .
JAVA Spring boot on Kubernetes

Cette commande est utilisée pour construire une image en lui donnant un nom d’image (springboot) et une version de balise (0.1.0). Vous pouvez voir qu’il y a plusieurs étapes dans le processus de construction des images. Ce sont des couches, et comme nous l’avons mentionné précédemment, chaque couche sera mise en cache par docker (c’est pourquoi nous n’avons pas utilisé le fat jar, pour plus d’informations, vous pouvez voir Leverage build cache). 

La prochaine fois que vous construirez l’image, la construction prendra moins de temps en raison de la mise en cache du docker et donc seules les étapes mises à jour ou nouvelles nécessiteront la création d’images.

Une fois l’image créée, vous pouvez la vérifier à l’aide de la commande :

JAVA Spring boot on Kubernetes

Vous pouvez également exécuter le conteneur de démonstration à l’aide de la commande docker run, puis effectuer un appel curl vers / hello endpoint :

JAVA Spring boot on Kubernetes
JAVA Spring boot on Kubernetes

Publier l’image Docker

Enfin, nous allons pousser notre image vers Docker Hub (un référentiel Docker public), pour cela, vous devrez avoir un compte sur Docker Hub et un référentiel, puis vous connecter.

JAVA Spring boot on Kubernetes

Ensuite, poussez l’image, notez que pour pousser un référentiel vers Docker Hub, vous devez nommer votre image locale à l’aide de votre nom d’utilisateur Docker Hub et du nom du référentiel que vous avez créé via Docker Hub sur le Web. Par exemple, pour moi, j’ai nommé mon image : oabai/springboot, et lui a donné une version de tag: 0.1.0, vous pouvez trouver l’image ici :

JAVA Spring boot on Kubernetes

C’est tout pour construire et publier l’image.

Créer et exécuter Kubernetes manifest resources

Créer un fichier de déploiement

Kubernetes utilise les pods comme unité d’exécution de base d’une application k8s. Un pod représente une unité de déploiement : une seule instance d’une application Spring Boot dans Kubernetes, qui peut être constituée d’un seul conteneur ou d’un petit nombre de conteneurs étroitement couplés et partageant des ressources.

Un objet de déploiement (ressource) dans Kubernetes fournit une mise à jour déclarative des pods, décrite à l’aide d’un fichier manifeste écrit en yaml ou en exécutant une commande kubectl. Vous décrivez un état souhaité dans un déploiement et le contrôleur de déploiement modifie l’état réel en l’état souhaité à une vitesse contrôlée.

Alors allons-y et créons un fichier manifeste de déploiement appelé deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
     name: digicactus-deployment
     labels:
       app: digicactus-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: digicactus-app
  template:
    metadata:
      labels:
        app: digicactus-app
    spec:
      containers:
      - name: digicactus-app
        image: oabai/springboot:0.1.0
        ports:
        - containerPort: 8081

Ici, nous disons à Kubernetes de créer 3 répliques pour notre application Spring Boot en utilisant la version 0.1.0 de notre image oabai/springboot, chaque réplique fonctionnera sur un Pod séparé sous le port 8081.

Pour déployer ce manifeste, vous pouvez exécuter la commande kubeclt create comme suit :

JAVA Spring boot on Kubernetes

Ensuite lister les pods en exécutant la commande kubectl get pods :

JAVA Spring boot on Kubernetes

K8S exécute 3 pods, chaque pod obtient sa propre adresse IP (172.17.0.5, 172.17.0.6 172.17.0.7). Ces pods ne sont pas accessibles depuis l’extérieur du cluster, car ils se trouvent sur un réseau différent (cluster kubernetes).

Les pods Kubernetes sont mortels, ils naissent et lorsqu’ils meurent, ils ne sont pas ressuscités. Cela conduit à un problème : L’ensemble de pods dits «backends» fournissent des fonctionnalités à d’autres pods appelés «frontends» à l’intérieur de votre cluster, du coup comment les frontends trouvent-ils et gardent-ils une trace de l’adresse IP à laquelle se connecter pour qu’ils puissent utiliser la partie backend de la charge de travail ?

Créer un service pour exposer les Pods

Les services permettent la communication entre divers composants à l’intérieur / à l’extérieur de l’application et établissent une connectivité externe aux sources de données et aux systèmes, en écoutant sur un port spécifique sur le nœud exécutant le Pod et en transférant les demandes vers ce Pod spécifique.

JAVA Spring boot on Kubernetes

Nous mettrons à jour le fichier deployment.yml en ajoutant la définition de l’objet Service kubernetes, mais avant de faire cela, nous arrêterons les pods en cours d’exécution en exécutant cette commande:

JAVA Spring boot on Kubernetes

Ensuite, mettez à jour le deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
    name: digicactus-deployment 
    labels: 
      app: digicactus-app 
spec: 
  replicas: 3 
  selector: 
    matchLabels: 
       app: digicactus-app 
  template: 
    metadata: 
      labels: 
        app: digicactus-app 
spec: 
   containers: 
   - name: digicactus-app 
     image: oabai/springboot:0.1.0 
     ports: 
     - containerPort: 8081
---
apiVersion: v1
kind: Service
metadata:
  name: digicactus-service
spec:
  selector:
    app: digicactus-app
  ports:
    - port: 8081
      targetPort: 8081
      nodePort: 30008
  type: LoadBalancer

Assurez-vous que la valeur de spec: selector de la définition de service est égale à la valeur de metadata: labels de la définition de déploiement.

Ensuite, exécutez à nouveau la commande kubectl create:

JAVA Spring boot on Kubernetes

Vous pouvez vérifier le service en exécutant:

JAVA Spring boot on Kubernetes

Vous notez que l’IP EXTERNE sera toujours <pending> sauf si vous exécutez cette commande minikube tunnel :

JAVA Spring boot on Kubernetes

Les services de type LoadBalancer peuvent être exposés via la commande de tunnel minikube. Il fonctionnera jusqu’à ce que Ctrl-C soit frappé.

Et enfin, appelez le point de terminaison du service de démonstration /hello/{name}

JAVA Spring boot on Kubernetes

Garder le meilleur pour la fin

Pour les personnes qui aiment surveiller les clusters via l’interface utilisateur Web, Minikube fournit un magnifique tableau de bord pour surveiller votre cluster (pods, déploiements, services et bien plus encore), pour y accéder, vous devez exécuter cette commande du tableau de bord du minikube :

JAVA Spring boot on Kubernetes

Et puis vous obtenez :

JAVA Spring boot on Kubernetes

C’est tout pour ce post, j’espère que vous l’avez apprécié je vous invite à jeter un oeil sur notre sélection d’article autour de Kubernetes ici et à plus tard!

Ciao!

Oussama ABAI

Image pour publication

About Oussama ABAI

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Résoudre : *
25 ⁄ 5 =