À la découverte de l’orchestration de conteneurs

Magazine
Marque
Linux Pratique
HS n°
Numéro
57
Mois de parution
avril 2023
Spécialité(s)


Résumé

Vous utilisez peut-être déjà les conteneurs depuis un moment, mais avez-vous déjà essayé de mettre en place des solutions distribuées ou simplement redondantes avec des conteneurs ? Faire tourner deux conteneurs de la même application sur la même machine peut vite devenir lourd, il n’y a pas moyen de simplement lancer la même commande, car le port réseau est déjà utilisé par exemple. Simple à gérer vous me direz, il suffit de lancer le deuxième conteneur en mappant un autre port, c’est vrai, mais essayez de faire cela quand vous devez gérer 150 conteneurs, le cauchemar n’est-ce pas ? Il y a une solution pour ça, et cette solution porte le nom si bien choisi d' « orchestrateur », car oui tel le maître d’orchestre, il va nous permettre de donner du rythme et de l’ordre dans le brouhaha que peut être la gestion de conteneurs.


Body

1. Un orchestrateur c'est quoi ?

Je vais essayer de ne pas rentrer dans trop de détails techniques dans cette partie, mais simplement donner une vue d’ensemble de l'implémentation d’un orchestrateur.

Pour faire simple, un orchestrateur est un outil d’automatisation et de gestion de conteneurs et de services, mais c’est aussi un outil opérationnel visant à gérer toutes les ressources devant permettre à vos conteneurs ou services d'être fonctionnels.

C’est ainsi que l’orchestrateur s’occupera de gérer l’attribution IP de vos conteneurs ainsi que leur port mapping au niveau du système d’exploitation où tourneront vos conteneurs.

C’est l’orchestrateur qui se charge du scaling de votre application si c’est nécessaire lorsque vous subissez un pic d’utilisation de votre application web, mais c’est aussi lui qui se charge de faire le rolling upgrade de votre application quand vous mettez à jour l’image de vos conteneurs.

Si votre application a besoin d’un volume de stockage, il est capable de demander ce volume à un provider (cloud ou non) et de l'attacher à votre conteneur.

C’est aussi à lui de trouver le ou les nœuds les plus adaptés pour faire tourner votre workload, en fonction par exemple de leur capacité ou de leur OS.

Un orchestrateur c’est un peu comme un OS distribué, il gère des conteneurs, du stockage, le réseau ainsi que les droits d'accès des utilisateurs voulant démarrer une application, comme le ferait Linux, la différence est qu’il peut le faire sur une multitude de nœuds en même temps.

2. L'histoire abrégée des orchestrateurs

Avec le succès de Docker dès 2013, plusieurs problématiques se sont posées aux équipes qui ont dû gérer des environnements conteneurisés. Comment allaient-elles devoir manager les déploiements, peut-on mutualiser les infrastructures pour y faire tourner plusieurs conteneurs sur la même machine virtuelle, ou encore comment faire en sorte que les systèmes soient suffisamment robustes pour faire en sorte de ne pas avoir d'arrêts de production suite au crash d’une machine virtuelle ? Mais comment se passer des conteneurs et du formidable gain qu’ils pouvaient apporter à la mise en production de nouvelles fonctionnalités ou de correction de bugs ?

En 2015, c’est l’annonce de la version 1.0 d’un projet basé sur un outil utilisé chez Google, un certain Kubernetes [1], en 2015 c’est aussi Docker qui lance de son côté Docker Swarm. Plusieurs autres projets voient leur version 1.0 en 2016 tels que Marathon d’Apache Mesos.

Et dernièrement, nous avons aussi eu l'arrivée en 2020 de Nomad de Hashicorp en version 1.0 sur le segment des orchestrateurs, bien que le projet ait débuté en 2015.

Cette vision du paysage de l’orchestration n’est pas exhaustive, AWS ou Microsoft ont par exemple créé le leur pour leur cloud avant d'intégrer Kubernetes, ou d'autres un peu moins connus comme Rancher avec Cattle.

Tout cet écosystème a permis de voir évoluer les différentes solutions, mais en fin 2017 la communauté a définitivement choisi son champion, et c’est Kubernetes. Depuis lors nous avons vu s'arrêter certains projets tels que Cattle de Rancher, qui s'est alors focalisé sur l’instanciation de clusters Kubernetes, de son côté le projet Marathon a totalement été arrêté en 2019. Avec le rachat de Docker par Mirantis, les plateformes Swarm migrent petit à petit vers Kubernetes, surtout depuis l’ajout de Mirantis Kubernetes Engine permettant de faire tourner dans un cluster hybride, Swarm aux côtés de Kubernetes.

3. Passons à la pratique

Quoi de mieux pour comprendre les avantages et la joie que peut être un orchestrateur à l’usage, qu’en mettant les mains dans le cambouis ?

Cet article étant une exploration des orchestrateurs, je vais me permettre de choisir deux des trois orchestrateurs encore sur le marché, en dehors de ceux spécifiques aux différents cloud provider.

Pour chaque orchestrateur, nous allons tester deux types d’installation, la première, vous permettant d’utiliser l’orchestrateur directement depuis votre ordinateur, la deuxième méthode vous permettra d'être proche d’un environnement rencontré en entreprise.

Mon choix s'est donc porté sur Docker Swarm et Kubernetes.

Swarm, car malgré sa perte de vitesse, il reste encore très présent dans de nombreuses entreprises, et si vous êtes déjà habitué à Docker Compose vous ne serez pas perdu.

Le deuxième choix est évidemment Kubernetes, choix de la communauté pour ses diverses forces telles que son évolutivité, son intégration avec les différents clouds ou encore son écosystème, mais c’est aussi le mien lorsqu’il s’agit de faire tourner un conteneur.

Je n’aborderai pas ici Nomad, malgré un certain intérêt pour les produits créés par Hashicorp, celui-ci n’a pour moi pas d’avantages par rapport à Kubernetes dans un usage standard de conteneurs.

3.1 Docker Swarm

Un des avantages de Swarm c’est qu’il est directement prêt à être mis en place lorsque vous installez Docker sur une machine, même si toutefois ce n’est pas utile sur votre Mac ou Linux de salon, cela peut être intéressant de le noter lorsque vous voulez monter une infra Swarm dans votre lab.

Si vous avez déjà l’habitude d’utiliser Docker Compose, l’utilisation de Swarm ne va pas vous perdre, ce qui est un avantage lorsque vous voulez découvrir les bienfaits de l’orchestration.

3.1.1 SinD

SinD [2] ou Swarm in Docker, est un binaire qui vous permet de créer un cluster Swarm directement sur un nœud faisant tourner Docker (disons votre laptop). C’est un formidable outil si vous souhaitez tester un déploiement Compose dans Swarm, mais que vous n’avez pas la possibilité de créer de machines virtuelles.

Pour commencer, il vous faut une machine avec Docker.

La première étape va consister à télécharger le binaire depuis la page GitHub du projet :

$ curl -OL https://github.com/jlevesy/sind/releases/download/v1.0.0/sind_1.0.0_Linux_amd64.tar.gz

Puis d’ajouter le binaire à votre PATH :

$ sudo tar -xzf sind_1.0.0_Linux_amd64.tar.gz -C /usr/local/bin sind

Vérifions la version de SinD pour valider que nous sommes capables d'exécuter le binaire :

$ sind version
Version: 1.0.0
Go version: 1.16.5

Maintenant, nous sommes prêts à lancer la création de notre cluster Swarm de taille standard composé d'un manager et d'un worker :

$ sind create --managers=1 --workers=1 -p 8080:8080
 
Connecting to the docker daemon...ok
Checking if a cluster named "default" already exists...ok
Creating a new cluster "default" with 1 managers and 1 workers...ok
✔ Cluster "default" successfully created

Félicitations, vous venez de créer votre premier cluster Swarm !

Cette configuration inclut un mapping sur le port 8080 de la machine qui va nous servir dans quelques instants à accéder à une application web que nous allons déployer.

Bien entendu, si vous désirez déployer vos propres applications, il vous faudra faire vous-même ce travail de mapping de ports. Mais encore une fois, si vous êtes déjà familiarisés avec Docker, la méthode est la même et elle ne devrait donc pas vous dérouter.

Connectons-nous au cluster Swarm :

$ eval $(sind env)

Nous pouvons ensuite lister les noeuds du cluster Swarm et interagir avec eux :

$ docker node ls
ID                          HOSTNAME               STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
8aoif87d29pvqk5rizrri9otb * sind-default-manager-0 Ready  Active       Leader         20.10.23
ta2ae4qzu5678x5ywit7okmj9   sind-default-worker-0  Ready  Active                      20.10.23

C’est parfait, nous voyons bien nos deux nœuds, un manager et un worker, et tout ça tourne dans mon Docker desktop.

Maintenant que notre environnement est fonctionnel, déployons une première application. Pour éviter la complexité, nous allons déployer un simple serveur web qui affiche un message de bienvenue.

Voici le fichier Compose que nous utilisons :

---
version: '3.7'
networks:
  appv1net:
    driver: overlay
    name: appv1net
 
services:
  appv1:
    image: newa/gohello:1.0
    deploy:
      mode: replicated
      replicas: 2
    ports:
      - 8080:80
    networks:
      - appv1net

C’est parti pour le déploiement :

$ docker stack deploy --compose-file=app.yaml app
Creating network appv1net
Creating service app_appv1

Vérifions que notre déploiement correspond bien à ce que nous attendons :

$ docker service ls
ID             NAME        MODE         REPLICAS   IMAGE              PORTS
nb4oqqh1d4qj   app_appv1   replicated   2/2        newa/gohello:1.0   *:8080->80/tcp

Puis vérifions que nous avons bien accès à notre application :

$curl http://localhost:8080
Bienvenue !

Une fois que notre test est validé, nous pouvons faire un peu de ménage pour ne pas consommer des ressources inutilement :

$ unset DOCKER_HOST && sind delete
 
Connecting to the docker daemon...ok
Checking if a cluster named "default" exists...ok
Deleting cluster "default"...ok
✔ Cluster "default" successfully deleted !

3.1.2 Swarm en vrai

La première étape est d’installer Docker Community Edition sur nos deux machines.

Maintenant que nous avons découvert comment tester Swarm sans aucun effort, passons à une configuration un peu plus conventionnelle. Comme pour SinD, nous allons créer un cluster avec un seul manager et un seul worker. Il ne nous faut donc pas plus de deux machines pour mettre en place le cluster, chacune d'elles avec 1 vCPU et 1Go de RAM. Pour le système d’exploitation, je vais rester classique et choisir Ubuntu, mais n'importe quelle distribution fait aussi bien l'affaire.

La première étape est d’installer Docker Community Edition sur nos deux machines :

$ sudo apt remove docker docker-engine docker.io containerd runc
$ sudo apt update
$ sudo apt install -y ca-certificates curl gnupg lsb-release
$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update
$ sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Nous ajoutons ensuite notre utilisateur au groupe Docker pour nous faciliter la vie :

$ sudo usermod -aG docker ubuntu

Passons ensuite à la création du manager. Pour ce faire, il va nous falloir récupérer l’IP de notre nœud pour l’ajouter à la commande. N'étant pas un adepte du copier-coller, voilà ma petite astuce pour l'obtenir directement en ligne de commandes :

$ sudo docker swarm init --advertise-addr $(hostname -I | awk '{print $1}')
Swarm initialized: current node (ywfevvyqhzj8elawos7v4jf1d) is now a manager.
 
To add a worker to this swarm, run the following command:
 
    docker swarm join --token SWMTKN-1-0p34victdklc1mvm61oy50bqnkvr2lxw581hqjn4sb3onvy9be-77dijlrwywvnqtgk8b8vihyui 172.27.2.204:2377
 
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Notre manager est maintenant prêt, nous pouvons passer au worker. Il nous suffit d'utiliser la commande fournie par le manager :

$ docker swarm join --token <SWARM_TOKEN> <SWARM_MANAGER_IP>:2377
This node joined a swarm as a worker.

Si tout s'est bien passé, nous pouvons vérifier depuis le manager que les deux noeuds font bien partie du cluster :

$ docker node ls
ID                          HOSTNAME            STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xaoym52o2k819t1yiimui25es   i-026e537fc9f24f010 Ready  Active                      20.10.23
ywfevvyqhzj8elawos7v4jf1d * i-099a9b5fb354bd081 Ready  Active       Leader         20.10.23

À ce stade, nous ne pouvons contrôler notre cluster que depuis le nœud manager, ce qui n'est pas la situation idéale. En effet, à terme il serait plus naturel de pouvoir le commander directement de notre poste de travail. Heureusement c'est quelque chose d'extrêmement simple à configurer avec cette variable d'environnement qui nous permet d'interagir avec le manager au travers de SSH :

$ export DOCKER_HOST=ssh://<user>@<SWARM_MANAGER_IP>

Maintenant nous pouvons lister les noeuds du cluster localement :

$ docker node ls
ID                          HOSTNAME            STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
xaoym52o2k819t1yiimui25es   i-026e537fc9f24f010 Ready  Active                      20.10.23
ywfevvyqhzj8elawos7v4jf1d * i-099a9b5fb354bd081 Ready  Active       Leader         20.10.23

Notre configuration en place, nous pouvons déployer notre application de test comme précédemment :

$ docker stack deploy --compose-file=app.yaml app
Creating network appv1net
Creating service app_appv1

Jetons un coup d'oeil à la stack applicative :

$ docker service ps app_appv1
ID           NAME         IMAGE             NODE                 DESIRED STATE  CURRENT STATE          ERROR PORTS
42h20a70z563 app_appv1.1  newa/gohello:1.0  i-026e537fc9f24f010  Running        Running 7 seconds ago
9ks43jckinoj app_appv1.2  newa/gohello:1.0  i-099a9b5fb354bd081  Running        Running 7 seconds ago

Et finalement, testons l'accès à l'application :

$ curl http://<SWARM_WORKER_IP>:8080
Bienvenue !

Voilà, notre premier cluster Swarm est en place ! Le gros plus de Swarm est sans nul doute son utilisation intuitive lorsque l'on est déjà familiarisé avec Compose.

3.2 Kubernetes

Kubernetes est sans doute intimidant au premier abord, mais dites-vous que seul le premier pas coûte, mais ensuite il n’y plus de retour possible : tout autre orchestrateur vous semblera sans saveur.

L'atout majeur de Kubernetes c’est son adaptabilité et sa capacité d'évolution. Vous voulez y ajouter de nouveaux objets à lui faire gérer ? Pas de soucis, il y a les Custom Resource (CRD) pour ça. Vous voulez empêcher vos utilisateurs de pouvoir déployer dans le namespace d’autres équipes ? Pas de soucis, Kubernetes vient directement avec RBAC.

Kubernetes est un pur outil cloud natif, il est totalement capable de gérer des ressources de votre cloud pour vous, comme le stockage ou les load balancer par exemple.

Pour éviter de vous perdre, je vais directement vous montrer le déploiement de notre application, le tout dans un simple fichier YAML comprenant deux parties : un déploiement et un service. Mais à quoi cela correspond-il simplement ?

Le déploiement permet de gérer les réplicas de conteneurs, comment ils peuvent être déployés au sein du cluster ou combien de réplicas.

Le service permet de donner une IP et un nom DNS uniques dans le réseau interne de Kubernetes pour accéder aux différents pods de l’application que vous déployez.

Voici le contenu de ce fichier :

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: gohello-deploy
spec:
  replicas: 4
  selector:
    matchLabels:
      app: gohello
  template:
    metadata:
      labels:
        app: gohello
    spec:
      containers:
      - name: app-v1
        image: newa/gohello:1.0
        imagePullPolicy: Always
 
---
apiVersion: v1
kind: Service
metadata:
  name: gohello-svc
  labels:
    app: gohello
spec:
  type: ClusterIP
  ports:
  - port: 80
    name: http
  selector:
    app: gohello

Interagir avec l’API de Kubernetes peut se faire de diverses façons, Curl ou Postman par exemple, mais la façon la plus simple est d'utiliser kubectl qui a été créé pour cela, téléchargeons donc le binaire :

$ curl -LO https://dl.k8s.io/release/v1.26.0/bin/linux/amd64/kubectl
$ sudo mv kubectl /usr/local/bin
$ sudo chown root: /usr/local/bin/kubectl && sudo chmod +x /usr/local/bin/kubectl

Passons maintenant à la pratique avec Minikube, un outil du projet Kubernetes qui permet de déployer un cluster local en une seule commande, puis nous passerons au déploiement d’un cluster plus proche d’un environnement d'entreprise.

3.2.1 Minikube

Minikube tout comme SinD est un simple binaire qui s'occupe de tout faire pour nous. Cependant, là où SinD utilise uniquement Docker, Minikube nous permet d’utiliser plusieurs drivers, nous permettant ainsi de faire démarrer notre orchestrateur dans une machine virtuelle KVM, VirtualBox ou Hyperkit, mais aussi dans un simple conteneur.

Il ne tient qu'à vous de choisir le driver qui vous convient le mieux. Ici, je vais utiliser Docker. Et nous allons le voir, la commande créant le cluster nous permet très simplement de choisir notre driver.

Nous avons tout d'abord besoin de télécharger le binaire minikube [3] :

$ curl -OL https://github.com/kubernetes/minikube/releases/download/v1.28.0/minikube-linux-amd64
$ sudo mv minikube-linux-amd64 /usr/local/bin/minikube
$ sudo chown root: /usr/local/bin/minikube && sudo chmod +x /usr/local/bin/minikube

C'est tout ce dont nous avons besoin pour démarrer notre cluster :

$ minikube start --driver=docker
😄 minikube v1.28.0 on Linux 13.1 (amd64)
✨ Using the docker driver based on existing profile
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
    > gcr.io/k8s-minikube/kicbase: 0 B [________________________] ?% ? p/s 24s
🤷 docker "minikube" container is missing, will recreate.
🔥 Creating docker container (CPUs=2, Memory=4000MB) ...
🐳 Preparing Kubernetes v1.25.3 on Docker 20.10.20 ...
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎 Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟 Enabled addons: storage-provisioner, default-storageclass
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

Voilà, en même pas 3 minutes (selon votre connexion internet), votre Kubernetes est prêt ! Pour s'en assurer, rien de plus simple : il nous suffit de lister les noeuds de notre cluster avec la commande kubectl :

$ kubectl get no
NAME       STATUS   ROLES           AGE   VERSION
minikube   Ready    control-plane   93s   v1.25.3

Un avantage avec minikube c’est qu’il vient avec une liste d’addons à activer en fonction des besoins. Par exemple, il y a une storage classe, permettant ainsi de faire tourner une application nécessitant de la persistance de données. On peut aussi avoir un ingress controller, un runtime sécurisé, ou une registry... La liste est longue ! Nous pouvons voir tous les addons avec une simple commande :

$ minikube addons list
|-----------------------------|----------|--------------|------------|
|         ADDON NAME          | PROFILE |    STATUS     | MAINTAINER |
|-----------------------------|----------|--------------|------------|
...
| dashboard                   | minikube | disabled     | Kubernetes |
| default-storageclass        | minikube | enabled ✅   | Kubernetes |
...

Nous allons garder notre configuration par défaut pour le moment et nous concentrer sur le déploiement de notre application. Pour cela, une simple commande suffit :

$ kubectl apply -f k8s-app.yaml
deployment.apps/gohello-deploy created
service/gohello-svc created

Voyons maintenant si notre nombre de réplicas est conforme à ce que nous avons demandé :

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
gohello-deploy-6488854b97-6rb7n   1/1     Running   0          2m18s
gohello-deploy-6488854b97-b5czx   1/1     Running   0          2m18s
gohello-deploy-6488854b97-b9xwc   1/1     Running   0          2m18s
gohello-deploy-6488854b97-cl2pm   1/1     Running   0          2m18s

Il y a bien 4 réplicas et notre application est bien démarrée. Maintenant, essayons d’y accéder. Dans notre fichier YAML, nous avons choisi de faire un service de type ClusterIP, c'est-à-dire que le service n’est accessible qu'à l'intérieur du cluster Kubernetes. Comment va-t-on y accéder ? C’est là que kubectl est magique, car il nous permet de faire un port-forward temporaire afin de pouvoir tester notre application :

$ kubectl port-forward svc/gohello-svc 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

Essayons d'accéder à notre application sur le port 8080 :

$ curl http://localhost:8080
Bienvenue !

Parfait, ça marche !

3.2.2 Kubernetes en vrai

Minikube est un outil vraiment pratique pour se familiariser avec Kubernetes, ou même pour tester ses développements en local, mais les chances de le rencontrer dans un environnement de production sont plus que minces.

Comme pour Swarm, nous allons créer un cluster de deux nœuds : un nœud pour le control-plane et un pour le data-plane. Le premier ne fera tourner aucune application, seulement les composants de Kubernetes quant au second, il nous permettra de faire tourner notre application.

À petite échelle, Kubernetes se montre un peu plus gourmand en ressources que Swarm, aussi nous allons cette fois-ci déployer des machines de 2 vCPU, avec 2Go de RAM.

Depuis la version 1.25 de Kubernetes, Docker n’est plus supporté comme conteneur runtime, nous allons donc le substituer par containerd, ce qui est totalement transparent à l'utilisation, mais toujours bon à savoir :

$ sudo apt-get install -y apt-transport-https ca-certificates curl
$ sudo mkdir /etc/apt/keyrings/
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update && sudo apt install containerd.io -y
$ sudo rm -rf /etc/containerd/config.toml
$ sudo systemctl restart containerd

L'outil que nous allons utiliser pour mettre en place notre cluster s'appelle Kubeadm, et tout comme Minikube, il fait lui aussi partie du projet Kubernetes. C’est un outil qui non seulement nous permet de déployer des clusters Kubernetes de production, mais qui nous permet aussi de gérer leurs mises à jour.

Avec kubeadm, tous les composants de Kubernetes sont conteneurisés, à l'exception bien sûr de kubelet, qui est le composant responsable de la gestion du cycle de vie des conteneurs. Nous allons donc l'installer en même temps que kubeadm sur les deux machines de notre cluster :

$ sudo curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
$ echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
$ sudo apt update && sudo apt install -y kubelet kubeadm
$ sudo systemctl enable --now kubelet

Swap

Il est vivement recommandé de supprimer le swap des machines sur lesquelles tourne Kubernetes, alors pensez bien à le désactiver dans le fstab et de lancer la commande : sudo swapoff -a.

Quelques modules kernel doivent aussi être activés pour que Kube fonctionne correctement :

cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sudo sysctl --system

Nous pouvons enfin démarrer et lancer l’initialisation de notre cluster Kubernetes en une seule commande que nous exécutons sur le noeud qui sera notre control-plane :

$ sudo kubeadm init

Vous pouvez copier le contenu du fichier /etc/kubernetes/admin.conf dans le fichier ~/.kube/config de votre machine locale, cela nous évitera de devoir piloter le cluster depuis la machine virtuelle.

Une fois l’initialisation terminée, kubeadm vous retourne une commande à exécuter sur le noeud worker, voici la commande en question :

$ sudo kubeadm join <CONTROL_PLANE_NODE_IP>:6443 --token <TOKEN> --discovery-token-ca-cert-hash sha256:<DISCOVERY-TOKEN-CA-CERT-HASH>

Il vous suffit de la copier, puis de la coller dans la console de la seconde machine. Elle permet de déployer le nœud worker, et de le faire rejoindre le cluster.

Vérifions que nous avons accès à notre cluster avec la commande kubectl :

$ kubectl get nodes
NAME                  STATUS     ROLES           AGE   VERSION
i-0082da1c2be9e9f3d   NotReady   <none>          14m   v1.26.1
i-05bc246b5c19701e5   NotReady   control-plane   17m   v1.26.1

Comme on peut le voir, nos deux nœuds sont dans l'état NotReady, ce qui signifie qu'il nous reste encore une étape dans la configuration de notre cluster. En effet, à l'heure actuelle, notre cluster n'a pas de composant pour gérer le réseau, contrairement à Minikube. C'est tout simplement parce que nous sommes dans un déploiement de type « production », et Kubernetes n'a pas d'opinion sur le composant que vous souhaitez utiliser (c'est d'ailleurs une autre de ses forces). Libre à vous donc de choisir votre addon réseau dans l'écosystème de Kubernetes [4] en fonction de vos besoins, même si je vous conseille de vous intéresser à Cilium [5] pour vos environnements de production, il vous permettra notamment de profiter de toutes les capacités d’eBPF [6] ainsi que d’avoir une visibilité maximum de votre couche réseau. Ici, nous allons déployer Calico qui sera largement suffisant pour notre exemple :

$ curl https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml -O
$ kubectl apply -f calico.yaml

Peu de temps après l'installation du réseau, vos noeuds devraient passer à l'état Ready :

$ kubectl get nodes
NAME                  STATUS   ROLES           AGE   VERSION
i-0082da1c2be9e9f3d   Ready    <none>          29m   v1.26.1
i-05bc246b5c19701e5   Ready    control-plane   32m   v1.26.1

Notre cluster est maintenant fonctionnel !

Nous allons une nouvelle fois déployer notre application pour s'assurer qu'elle se comporte exactement de la même manière que sur Minikube :

$ kubectl apply -f k8s-app.yaml
deployment.apps/gohello-deploy created
service/gohello-svc created

Si précédemment nous avions utilisé un port forwarding pour accéder à notre application, cette fois-ci nous allons plutôt opter pour une configuration plus adaptée à la production. Plusieurs méthodes s'offrent à nous pour publier notre application directement à l'extérieur du cluster :

  • paramétrer le service en mode nodePort permet de créer un mapping avec un port de notre machine ;
  • le type loadBalancer permet de faire la même chose, mais associe le port directement avec un load balancer tout en instanciant celui-ci auprès d’un cloud provider par exemple ;
  • un ingress controller enfin permet de mutualiser le port externe et d’utiliser des règles de reverse proxy pour accéder à son service.

Pour notre découverte, nous allons utiliser Traefik. L'une des solutions les plus pratiques pour le déployer est d'utiliser Helm. Helm [7] est un package manager pour Kubernetes. Tout comme n'importe quel autre package manager que vous avez l'habitude d'utiliser sur votre distribution Linux, Helm est en mesure de déployer une application dans Kubernetes en gérant ses dépendances. Helm utilise des modèles de fichiers YAML avec lesquels vous n’interagissez pas directement. À la place, vous n'avez qu'à adapter un fichier de valeur fourni avec le chart pour personnaliser le déploiement en fonction de vos besoins. Et il va sans dire que Helm vient avec un immense catalogue d'applications prêtes à l'emploi, comme Traefik que nous allons utiliser, mais aussi Redis, MongoDB ou encore Elastic par exemple.

Première étape, installer le binaire Helm :

$ curl -OL https://get.helm.sh/helm-v3.11.0-linux-amd64.tar.gz
$ tar -xzf helm-v3.11.0-linux-amd64.tar.gz linux-amd64
$ sudo mv linux-amd64/helm /usr/local/bin/helm
$ sudo chown root: /usr/local/bin/helm && sudo chmod +x /usr/local/bin/helm

Vérifions que Helm fonctionne correctement :

$ helm version
version.BuildInfo{Version:"v3.11.0", GitCommit:"472c5736ab01133de504a826bd9ee12cbe4e7904", GitTreeState:"clean", GoVersion:"go1.18.10"}

Déployons Traefik : première étape, ajouter le dépôt Traefik à votre liste de dépôts (une opération qu'il est aussi fréquent de faire avec Linux) :

$ helm repo add traefik https://traefik.github.io/charts
"traefik" has been added to your repositories

Passons au déploiement :

$ helm install traefik traefik/traefik --namespace=traefik --create-namespace --set service.type=NodePort
NAME: traefik
LAST DEPLOYED: Thu Jan 26 15:34:28 2023
NAMESPACE: traefik
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Traefik Proxy v2.9.5 has been deployed successfully on traefik namespace !

Vérifions si tout est bien en place dans le namespace traefik :

$ kubectl get pods -n traefik
NAME                           READY   STATUS    RESTARTS   AGE
pod/traefik-7df9b5986c-gk6d9   1/1     Running   0          36s

Parfait, Traefik est déployé avec un service de type node port, mais nous n'avons pas encore d'ingress pour tester l'accès à notre application depuis l'extérieur du cluster. On peut même voir le port mapping qui est appliqué au service Traefik, ici pour accéder au service sur un port 80, il faudra utiliser le port 31743 :

$ kubectl get services -n traefik
NAME              TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
service/traefik   NodePort   10.110.247.20   <none>        80:31743/TCP,443:30314/TCP   37s

Ajoutons maintenant la définition de l'Ingress au fichier de déploiement de notre application :

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gohello-ing
spec:
  rules:
  - host: demo.app.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: gohello-svc
            port:
              number: 80

Puis nous appliquons à nouveau le fichier YAML :

$ kubectl apply -f k8s-app.yaml
deployment.apps/gohello-deploy unchanged
service/gohello-svc unchanged
ingress.networking.k8s.io/gohello-ing created

Testons enfin l'accès à notre application :

$ curl -H "Host: demo.app.local" 172.27.1.70:31743
Bienvenue !

Tout fonctionne. Et si vous êtes arrivés au même résultat, bravo ! Sinon je vous encourage à revoir les différentes étapes, peut-être avez-vous manqué quelque chose, mais je ne doute pas qu'à terme, votre configuration sera elle aussi totalement fonctionnelle !

Conclusion

Dans cet article, nous avons pu découvrir deux orchestrateurs de conteneurs, mais aussi deux méthodes pour les déployer et ainsi commencer à mieux les maîtriser. Expérimenter sur son laptop est super simple avec des outils tels que SinD ou Minikube ; d'autres existent aussi, tel que Kind par exemple qui est aussi un équivalent de SinD pour déployer Kubernetes. Nous avons vu la création d’un cluster dans un environnement de type production avec l'aide de Kubeadm, mais ici encore d'autres outils existent comme Kops ou Kubespray (pour ne citer qu'eux). Vous pouvez déployer un cluster Kubernetes en quelques commandes, mais aussi le mettre à jour. Par contre, il vous faudra étudier plus en détail certaines options pour sécuriser vos clusters.

Tandis que Swarm est en perte de vitesse, Kubernetes a un avenir radieux devant lui. Il bénéficie d'un énorme écosystème que je vous invite à découvrir au travers du landscape de la CNCF [8], la fondation qui gère le projet Kubernetes.

Références

[1] L'histoire de Kubernetes, partie 1 : https://www.youtube.com/watch?v=318elIq37PE
et partie 2 : 
https://www.youtube.com/watch?v=318elIq37PE

[2] https://github.com/jlevesy/sind

[3] https://github.com/kubernetes/minikube

[4] https://kubernetes.io/fr/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network

[5] https://cilium.io/

[6] https://ebpf.io/

[7] https://helm.sh/

[8] https://landscape.cncf.io/



Article rédigé par

Par le(s) même(s) auteur(s)

L'avenir incertain de Docker Compose

Magazine
Marque
Linux Pratique
HS n°
Numéro
52
Mois de parution
octobre 2021
Spécialité(s)
Résumé

La vélocité, voici un concept phare qui a guidé l'innovation de ces dix dernières années. Mais qu'est-ce que la vélocité ? Certainement pas d'écrire son code plus vite, mais bien d'avoir la boucle de feedback la plus courte possible. Et pour obtenir ce résultat, il faut réduire le cycle de release à son strict minimum.

Buildpacks ou Dockerfile, lequel choisir ?

Magazine
Marque
Linux Pratique
HS n°
Numéro
52
Mois de parution
octobre 2021
Spécialité(s)
Résumé

Le processus de créer une image Docker est toujours sujet à débat : il y a les pros Dockerfile et les antis, ceux qui pensent que c'est simple, et ceux qui ne comprennent pas pourquoi cette responsabilité devrait « shifter » vers eux. Et c'est vrai, créer une image Docker n'est pas si simple : on ne s'improvise pas expert en packaging du jour au lendemain. Par chance, il existe une alternative out-of-the-box au classique Dockerfile : les Buildpacks.

Les derniers articles Premiums

Les derniers articles Premium

Présentation de Kafka Connect

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Un cluster Apache Kafka est déjà, à lui seul, une puissante infrastructure pour faire de l’event streaming… Et si nous pouvions, d’un coup de baguette magique, lui permettre de consommer des informations issues de systèmes de données plus traditionnels, tels que les bases de données ? C’est là qu’intervient Kafka Connect, un autre composant de l’écosystème du projet.

Le combo gagnant de la virtualisation : QEMU et KVM

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

C’est un fait : la virtualisation est partout ! Que ce soit pour la flexibilité des systèmes ou bien leur sécurité, l’adoption de la virtualisation augmente dans toutes les organisations depuis des années. Dans cet article, nous allons nous focaliser sur deux technologies : QEMU et KVM. En combinant les deux, il est possible de créer des environnements de virtualisation très robustes.

Brève introduction pratique à ZFS

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Il est grand temps de passer à un système de fichiers plus robuste et performant : ZFS. Avec ses fonctionnalités avancées, il assure une intégrité des données inégalée et simplifie la gestion des volumes de stockage. Il permet aussi de faire des snapshots, des clones, et de la déduplication, il est donc la solution idéale pour les environnements de stockage critiques. Découvrons ensemble pourquoi ZFS est LE choix incontournable pour l'avenir du stockage de données.

Générez votre serveur JEE sur-mesure avec Wildfly Glow

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Et, si, en une ligne de commandes, on pouvait reconstruire son serveur JEE pour qu’il soit configuré, sur mesure, pour les besoins des applications qu’il embarque ? Et si on pouvait aller encore plus loin, en distribuant l’ensemble, assemblé sous la forme d’un jar exécutable ? Et si on pouvait même déployer le tout, automatiquement, sur OpenShift ? Grâce à Wildfly Glow [1], c’est possible ! Tout du moins, pour le serveur JEE open source Wildfly [2]. Démonstration dans cet article.

Les listes de lecture

8 article(s) - ajoutée le 01/07/2020
Découvrez notre sélection d'articles pour faire vos premiers pas avec les conteneurs, apprendre à les configurer et les utiliser au quotidien.
11 article(s) - ajoutée le 02/07/2020
Si vous recherchez quels sont les outils du DevOps et comment les utiliser, cette liste est faite pour vous.
8 article(s) - ajoutée le 02/07/2020
Il est essentiel d'effectuer des sauvegardes régulières de son travail pour éviter de perdre toutes ses données bêtement. De nombreux outils sont disponibles pour nous assister dans cette tâche.
Voir les 60 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous