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).
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 .
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 :
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 :
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.
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 :
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 :
Ensuite lister les pods en exécutant la commande kubectl get pods :
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.
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:
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:
Vous pouvez vérifier le service en exécutant:
Vous notez que l’IP EXTERNE sera toujours <pending> sauf si vous exécutez cette commande minikube tunnel :
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}
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 :
Et puis vous obtenez :
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