loader-logo

Construire et déployer une application Spring boot à ressort pour Kubernetes

Dans cet article, nous allons nous concentrer sur le déploiement d’une simple action de 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 terminal GET/hello/{name} qui renvoie une chaîne simple « hello/{name} ».

Avant de passer à la partie intéressante de cette conférence, veuillez vous assurer que votre Java et Docker sont installés et nous allons d’abord passer par quelques définitions.

Qu’est-ce qu’un conteneur ?

Un conteneur est une unité standard de logiciel qui emballe le code et toutes ses dépendances, de sorte que l’application fonctionne rapidement et de manière fiable d’un environnement informatique à un autre.

Si vous utilisez une architecture de micro-services, votre application se composera d’un ensemble de services où chaque service sera expédié dans un conteneur. Dans les étapes de développement, vous pouvez vous permettre d’avoir une seule instance de chaque conteneur afin d’exécuter vos micro-services, mais ce n’est pas autorisé dans la production où vous devez assurer une haute disponibilité, la tolérance à la faute et la résilience de vos services, sans temps d’arrêt ; cela signifie que vous devez étendre vos services sur plusieurs nœuds et grappes.

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

  • Docker Edition Entreprises (Docker EE)
  • Mesosphere (DC/OS)
  • Kubernetes (K8S)

Qu’est-ce que Kubernetes ?

Kubernetes (K8S) est un système d’orchestration de conteneurs open-source pour automatiser le déploiement, la mise en échelle et la gestion des applications. Il a été conçu à l’origine par Google, et est maintenant maintenu par le Cloud Native Computing Foundation (CNCF). Il vise à fournir une « plateforme pour automatiser le déploiement, la mise à l’échelle et l’exploitation de conteneurs d’applications à travers des grappes d’hôtes ». Vous pouvez trouver plus de détails ici.

Les Kubernets gèrent un amas de nœuds. Un nœud est une machine ouvrière à Kubernets, auparavant connu sous le nom de minion. Un nœud peut être une machine virtuelle ou 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 comprennent l’execution de conteneurs Kubelet et kube-proxy.

Le nœud maître est appelé le Plan de Contrôle ; le cerveau de l’amas (l’architecture de kubernetes ci-dessous).

Aucun texte alternatif pour cette image

 

Installation de Kubernetes localement (Kubectl + Minikube)

Kubectl :

L’outil en ligne de commande Kubernetes, Kubectl, vous permet d’exécuter des commandes contre des clusters Kubernetes. Vous pouvez utiliser Kubectl pour déployer des applications, inspecter et gérer des ressources de cluster, et visualiser des journaux. Pour une liste complète des opérations Kubectl.

Vous pouvez trouver des instructions sur la façon d’installer Kubectl en cliquant sur Ce lien.

Minikube :

Minikube est un outil qui rend facile l’exécution locale de Kubernetes. Minikube gère un cluster Kubernetes à un seul nœud à l’intérieur d’une machine virtuelle (VM) sur votre ordinateur portable pour les utilisateurs qui cherchent à essayer Kubernetes ou développer avec elle au quotidien.

Vous pouvez suivre les instructions d’installation. Une fois installé, assurez-vous que Docker est en cours d’exécution, puis démarrez Minikube :

minikube start -p minikube-vbox --vm-driver=virtualbox
1- démarrer minikube avec envs proxy :
minikube start --docker-env="http_proxy=1.2.3.4:8080" --docker-env="https_proxy=1.2.3.4:8080"
2- Récupérez l’IP de la VM utilisée par minikube (supposons qu’elle soit 2.2.3.4) :
minikube start --docker-env="http_proxy=1.2.3.4:8080" --docker-env="https_proxy=1.2.3.4:8080"
3- Assurez-vous que kubectl ne passera pas par le proxy si vous appelez le cluster local :
export no_proxy="127.0.0.1,localhost,2.2.3.4"

Créer et publier une image de Docker

Les Kubernetes déploient et gèrent des conteneurs en utilisant des images publiées sur le dépôt de Docker. C’est pourquoi nous avons besoin de créer une image de Docker pour notre application simple, puis de l’envoyer vers un dépôt de Docker (Docker hub). Docker construit automatiquement des images en lisant les instructions d’un Dockerfile – un fichier texte qui contient toutes les commandes, dans l’ordre, nécessaire pour construire une image donnée. Pour cela, nous allons créer un fichier appelé Dockerfile (sans extension) qui contient ce qui suit :

FROM openjdk:11.0-jre-stretch
MAINTAINER Abdelghani ROUSSI <roussi.abdelghani@gmail.com>

WORKDIR /usr/share/demo-k8s

ARG appDir=/usr/share/demo-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 de l’image, chaque instruction représente une couche d’image en lecture seule (Delta). Et que sur l’exécution d’instruction Docker cherche une image existante dans son cache qui peut être réutilisée plutôt que de créer une nouvelle image (dupliquée).

Pratiques exemplaires

Pour éviter l’inefficacité, les charges lourdes et les déchets de stockage, nous utilisons une image légère de Jre 11 docker comme image de base, et nous ne copions pas le grand pot (fourni par Spring-boot-maven-plugin) à l’image de base. Au lieu de cela, nous utilisons le plugin maven-dependency pour décompresser le grand pot sous target/dependency puis nous copions /BOOT-INF/lib, BOOT-INF/classes et /META-INF sur l’image de base puis dans le ENTRYPOINT nous lançons la classe principale en spécifiant le chemin de classe.

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

docker build -t demo:0.1.0 .

Cette commande est utilisée pour construire une image avec un nom d’image (démo) et une version tag (0.1.0). Vous pouvez voir qu’il y a plusieurs étapes dans le processus de construction des images ; ce sont des calques, et comme nous l’avons mentionné précédemment, chaque calque sera mis en cache par Docker (c’est pourquoi nous n’avons pas utilisé le grand pot, pour plus d’informations vous pouvez voir le Leverage Build Cache). La prochaine fois que vous construisez l’image, la construction prendra moins de temps en raison de cache docker et donc seulement mis à jour ou de nouvelles étapes auront besoin de création d’images.

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

Vous pouvez également lancer le conteneur de démonstration en utilisant la commande docker run, puis faire un appel de boucle à /hello Endpoint :

Enfin, nous allons envoyer notre image à Docker Hub (un dépôt public de fichiers), pour cela vous aurez besoin d’avoir un compte sur Docker Hub et un dépôt, puis connectez-vous :

Ensuite, faites passer l’image, notez que pour envoyer un dépôt vers le Docker Hub, vous devez nommer votre image locale en utilisant votre nom d’utilisateur Docker Hub, et le nom du dépôt que vous avez créé par l’intermédiaire de Docker Hub sur le web (Pour moi, j’ai nommé mon image : aroussisvg/demo-k8s, et je lui ai donné une version tag : 0.1.0), vous pouvez trouver l’image ici :

C’est tout pour construire et publier une image.

Créer et exécuter des ressources manifestes Kubernetes :

Les Kubernetes utilisent 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 à Kubernetes, qui pourrait consister en un seul conteneur ou un petit nombre de conteneurs qui sont étroitement couplés et qui partagent les ressources.

Un objet de déploiement (ressource) dans Kubernetes fournit une mise à jour déclarative des gousses, décrite à l’aide d’un fichier manifeste écrit en Yaml ou en exécutant une commande Kubectl. Vous décrivez un état désiré dans un déploiement, et le contrôleur de déploiement change l’état réel à l’état désiré à un taux contrôlé.

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

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

Ici nous disons à Kubernetes de créer 3 répliques pour notre application en utilisant la version 0.1.0 de notre image aroussisvg/demo-k8s, chaque réplique s’exécutera sur un Pod séparé sous le port 8081.

Pour déployer ce manifeste, vous pouvez exécuter la commande créer Kubeclt comme suit :

Vous pouvez ensuite lister les Pods en exécutant la commande Kubeclt get Pods :

Vous pouvez aussi utiliser un outil appelé K9s, qui est un outil Kubeclt comme ligne de commande pour interagir avec vos clusters Kubernetes en utilisant un terminal ui.

Vous pouvez voir que k8S exécute 3 Pods, chaque Pod obtient sa propre adresse IP (172.17.0.6, 127.17.0.5 127.17.0.5). Ces Pods ne sont pas accessibles de l’extérieur du cluster, parce qu’ils sont un réseau différent (cluster Kubernete).

Les Kubernetes Pods sont mortels, ils sont nés et quand ils meurent ils ne sont pas ressuscités. Cela entraîne un problème : si un ensemble de POD (appelés « Backends ») fournit des fonctionnalités à d’autres PODS (appelés « Frontends ») à l’intérieur de votre cluster, comment les frontends peuvent-ils trouver et suivre l’adresse IP à laquelle se connecter, pour que le serveur frontal puisse utiliser la partie backend de la charge de travail ? Entrez les services.

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 du nœud exécutant le Pod et en transmettant les demandes à ce Pod spécifique.

Nous allons mettre à jour le déploiement.yml en ajoutant la définition de l’objet Service Kubernetes, mais avant cela nous allons arrêter les Pods en exécutant cette commande :

Puis mettre à jour le déploiement.yml :

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

 

S’assurer que la valeur de spec :selector de la définition de service est égale à la valeur des métadonnées : labels de la définition de déploiement.

Puis exécutez à nouveau la commande Kubeclt create :

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

Vous remarquerez que l’IP EXTERNE restera <en attente> à moins d’exécuter cette commande Minikube tunnel :

Les services de type LoadBalancer peuvent être exposés via la commande Minikube tunnel. Il s’exécutera jusqu’à ce que Ctrl-C est tapé.

Enfin, appelez le service de démonstration /hello/{nom}

Gardez le meilleur pour la fin

Pour les personnes qui aiment surveiller les clusters via web-uis, Minikube fournit un tableau de bord agréable pour surveiller votre cluster (Pods, Déploiements, Services et bien plus encore), pour y accéder, vous devez exécuter cette commande Minikube tableau de bord :

Et ensuite vous obtenez :

Ce sera tout pour ce poste, j’espère que vous avez apprécié, au plaisir de vous revoir plus tard !

Ciao !

Abdelghani

Partager sur facebook
Partager sur twitter
Partager sur linkedin
Partager sur pinterest
Partager sur whatsapp

Laisser un commentaire

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

Sélectionnez votre pays et votre langue​

Maroc

Tunis

Allemagne

Switzerland

France

Global