Maîtriser Docker et Kubernetes : Déploiement et Scalabilité d'Applications Modernes
Maîtriser Docker et Kubernetes : Déploiement et Scalabilité d'Applications Modernes

Introduction à Kubernetes : Concepts Fondamentaux

Bienvenue dans cette première leçon consacrée à Kubernetes dans le cadre de notre cours "Maîtriser Docker et Kubernetes : Déploiement et Scalabilité d'Applications Modernes". Après avoir exploré les fondations de la conteneurisation avec Docker, il est temps de passer à l'étape supérieure : l'orchestration de conteneurs.

Introduction : Du Conteneur à l'Orchestration

Nous avons vu que Docker nous permet d'empaqueter nos applications et leurs dépendances dans des conteneurs isolés, légers et portables. C'est un pas de géant vers la standardisation des environnements de développement et de production. Cependant, la conteneurisation seule ne résout pas tous les défis liés au déploiement et à la gestion d'applications à grande échelle.

Imaginez devoir gérer des centaines, voire des milliers de conteneurs répartis sur plusieurs machines. Comment s'assurer qu'ils sont toujours disponibles ? Comment les mettre à jour sans interruption de service ? Comment répartir la charge entre eux ? Comment gérer la persistance des données ou la configuration spécifique à chaque environnement ? C'est là qu'intervient l'orchestration de conteneurs, et Kubernetes en est le leader incontesté.

Dans cette leçon, nous allons démystifier Kubernetes. Nous explorerons :

  • Pourquoi Kubernetes est devenu indispensable.
  • Ce qu'est Kubernetes et ce qu'il n'est pas.
  • Son architecture et ses composants clés.
  • Les objets fondamentaux qui le composent et comment ils interagissent.

Préparez-vous à entrer dans le monde fascinant de la gestion de clusters à l'échelle du cloud !

1. Pourquoi Kubernetes ? Le Contexte de l'Orchestration

Lorsque vous utilisez Docker pour conteneuriser une application, vous résolvez le problème "ça marche sur ma machine". Mais qu'en est-il lorsque votre application a besoin de :

  • Scalabilité : Gérer un trafic variable, augmenter ou diminuer le nombre d'instances de votre application dynamiquement.
  • Haute Disponibilité : Assurer que votre application reste fonctionnelle même si une machine ou un conteneur tombe en panne.
  • Déploiement Continu : Mettre à jour votre application avec de nouvelles versions sans perturber les utilisateurs (déploiements "rolling update").
  • Gestion des Ressources : Allouer efficacement les ressources (CPU, mémoire) aux différents conteneurs.
  • Découverte de Services : Permettre aux différents composants de votre application (microservices) de se trouver et de communiquer entre eux.
  • Persistance des Données : Gérer le stockage des données qui doivent survivre à la destruction des conteneurs.
  • Configuration et Secrets : Gérer les variables d'environnement, les fichiers de configuration et les informations sensibles de manière sécurisée et dynamique.

Sans un orchestrateur, gérer ces aspects manuellement deviendrait rapidement un cauchemar complexe et sujet aux erreurs. C'est ici que Kubernetes entre en jeu.

2. Qu'est-ce que Kubernetes ?

Kubernetes (souvent abrégé K8s) est une plateforme open source portable et extensible pour la gestion des charges de travail et des services conteneurisés, qui facilite la configuration déclarative et l'automatisation.

En d'autres termes, Kubernetes est un système d'orchestration de conteneurs qui permet de :

  • Déployer des applications conteneurisées.
  • Gérer leur cycle de vie (mises à jour, rollbacks).
  • Scaler (augmenter ou diminuer le nombre d'instances) automatiquement.
  • Superviser leur état et redémarrer les conteneurs défaillants.
  • Exposer les applications aux utilisateurs.

2.1. Un peu d'Histoire et de Philosophie

Kubernetes est né chez Google (projet Borg puis Omega), qui utilisait depuis des années des systèmes d'orchestration internes pour gérer des milliards de conteneurs par semaine. Google a décidé d'ouvrir le code de ce projet et de le donner à la Cloud Native Computing Foundation (CNCF), ce qui a largement contribué à son adoption massive.

La philosophie de Kubernetes repose sur le modèle déclaratif (vs impératif) :

  • Déclaratif : Vous décrivez l'état désiré de votre système (par exemple, "je veux 3 instances de mon application Nginx"). Kubernetes s'occupe de rendre l'état actuel conforme à cet état désiré. Si un conteneur tombe en panne, Kubernetes le recrée pour maintenir les 3 instances.
  • Impératif : Vous donnez des instructions étape par étape ("démarre Nginx sur la machine A, puis Nginx sur la machine B, si la machine A tombe, redémarre Nginx sur la machine C").

Cette approche déclarative est une pierre angulaire de la robustesse et de l'automatisation de Kubernetes.

3. L'Architecture de Kubernetes : Le Cluster

Kubernetes fonctionne sur un ensemble de machines, appelé cluster. Un cluster Kubernetes est composé de deux types de nœuds principaux :

  1. Le Plan de Contrôle (Control Plane / Master Node) : Le "cerveau" du cluster. Il gère l'état global du cluster, prend les décisions d'orchestration et répond aux requêtes API.
  2. Les Nœuds de Travail (Worker Nodes) : Les machines sur lesquelles vos conteneurs (vos applications) s'exécutent réellement.

Explorons les composants clés de chacun :

3.1. Composants du Plan de Contrôle (Master Node)

Le Plan de Contrôle est responsable de maintenir l'état du cluster, de planifier les tâches et de répondre aux requêtes API.

  • kube-apiserver :
    • C'est le point d'entrée principal pour interagir avec le cluster Kubernetes.
    • Il expose l'API Kubernetes. Toutes les communications (internes et externes) passent par lui.
    • Il valide les requêtes, met à jour l'état du cluster dans etcd.
  • etcd :
    • Une base de données distribuée clé-valeur très rapide et fiable.
    • Il stocke toutes les données de configuration du cluster, son état actuel et l'état désiré. C'est la source de vérité du cluster.
  • kube-scheduler :
    • Surveille les nouveaux Pods (nous verrons ce qu'est un Pod plus tard) qui n'ont pas encore été affectés à un nœud.
    • Sélectionne le meilleur nœud pour chaque Pod en fonction de contraintes (ressources requises, affinités, politiques, etc.).
  • kube-controller-manager :
    • Exécute plusieurs "contrôleurs" logiques. Chaque contrôleur est une boucle de contrôle qui surveille l'état actuel du cluster via l'API, le compare à l'état désiré (stocké dans etcd), et tente de rapprocher les deux.
    • Exemples de contrôleurs : Node Controller, Replication Controller, Endpoints Controller, Service Account Controller.
  • cloud-controller-manager (optionnel) :
    • Intègre Kubernetes avec des APIs spécifiques aux fournisseurs de cloud (AWS, GCP, Azure, etc.) pour gérer des ressources comme les load balancers, les volumes de stockage, etc.

3.2. Composants des Nœuds de Travail (Worker Nodes)

Les Nœuds de Travail sont les machines qui exécutent vos applications conteneurisées.

  • kubelet :
    • L'agent principal qui s'exécute sur chaque nœud de travail.
    • Il communique avec le kube-apiserver, reçoit les instructions sur les Pods à exécuter sur ce nœud.
    • Il gère l'état des Pods sur son nœud, rapporte leur état au Plan de Contrôle.
    • Il interagit avec le Container Runtime pour démarrer et arrêter les conteneurs.
  • kube-proxy :
    • Un proxy réseau qui s'exécute sur chaque nœud.
    • Il gère les règles réseau sur le nœud pour permettre la communication avec les Pods, à la fois à l'intérieur et à l'extérieur du cluster.
    • Il implémente les Services Kubernetes (nous y reviendrons).
  • Container Runtime :
    • Le moteur qui exécute les conteneurs.
    • Historiquement Docker, mais Kubernetes supporte d'autres runtimes conformes au Container Runtime Interface (CRI) comme containerd ou CRI-O.

4. Les Concepts Fondamentaux : Les Objets Kubernetes

Kubernetes gère ses ressources sous forme d'objets. Chaque objet représente un enregistrement de l'état désiré de votre cluster. Lorsque vous créez un objet, le Plan de Contrôle s'assure que cet objet existe et maintient son état.

Nous allons explorer les objets les plus courants et fondamentaux :

4.1. Pod : L'Unité Atomique

Le Pod est la plus petite unité déployable de Kubernetes. Un Pod représente une seule instance de votre application.

  • Un Pod encapsule un ou plusieurs conteneurs qui partagent :
    • Le même espace réseau (même adresse IP, même ports).
    • Les mêmes volumes de stockage.
    • Des namespaces Linux et des cgroups partagés.
  • Pourquoi plusieurs conteneurs dans un même Pod ?
    • C'est rare pour les applications principales. Généralement, chaque Pod héberge un conteneur principal.
    • Utile pour les "sidecar containers" qui étendent ou supportent le conteneur principal (ex: un conteneur qui collecte des logs du conteneur principal).
  • Nature éphémère : Les Pods sont conçus pour être éphémères. Ils peuvent être créés, détruits et recréés par Kubernetes. Il ne faut jamais compter sur la survie d'un Pod.
  • Pas de redémarrage automatique en cas de crash du Pod : Si un conteneur à l'intérieur d'un Pod crash, Kubernetes peut redémarrer ce conteneur. Mais si le Pod lui-même disparaît (à cause d'une panne de nœud, par exemple), il ne sera pas recréé directement par Kubernetes. C'est le rôle des contrôleurs de niveau supérieur (Deployment, ReplicaSet).

4.2. ReplicaSet : Assurer la Haute Disponibilité

Un ReplicaSet s'assure qu'un nombre spécifié de copies d'un Pod est toujours en cours d'exécution.

  • Si un Pod tombe en panne (le nœud qui l'héberge crash, le conteneur se termine inopinément), le ReplicaSet détecte la divergence et crée un nouveau Pod pour maintenir le nombre désiré.
  • Il est rarement utilisé directement. Il est généralement géré par un Deployment.

4.3. Deployment : Le Cœur du Déploiement

Le Deployment est l'objet le plus courant pour déployer et gérer des applications sans état (stateless applications) dans Kubernetes.

  • Il gère les ReplicaSets sous-jacents.
  • Il permet les déploiements progressifs (rolling updates) : met à jour l'application de manière contrôlée, en remplaçant progressivement les anciens Pods par les nouveaux, sans interruption de service.
  • Il permet les rollbacks : revenir facilement à une version précédente de l'application en cas de problème.

Exemple de code 1 : Déploiement d'une application Nginx

Ce fichier YAML déclare un Deployment nommé nginx-deployment qui garantira qu'il y a toujours 3 répliques (Pods) de notre application Nginx en cours d'exécution.

# filename: nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3 # Nous voulons 3 instances de notre application
  selector:
    matchLabels:
      app: nginx # Ce sélecteur permet au Deployment de trouver les Pods qu'il gère
  template: # Le 'template' décrit les Pods que ce Deployment doit créer
    metadata:
      labels:
        app: nginx # Le label que le sélecteur utilise pour identifier les Pods
    spec:
      containers:
      - name: nginx # Nom du conteneur
        image: nginx:1.14.2 # Image Docker à utiliser
        ports:
        - containerPort: 80 # Le port sur lequel le conteneur écoute

Explication du code :

  • apiVersion: Indique la version de l'API Kubernetes que nous utilisons pour cet objet.
  • kind: Le type d'objet Kubernetes que nous créons, ici un Deployment.
  • metadata.name: Un nom unique pour notre Deployment.
  • metadata.labels: Des étiquettes key-value attachées à l'objet pour l'organiser et le sélectionner.
  • spec.replicas: Le nombre souhaité de Pods. Ici, 3.
  • spec.selector.matchLabels: Détermine quels Pods sont gérés par ce Deployment. Il recherche les Pods avec le label app: nginx.
  • spec.template: C'est le gabarit pour la création des Pods. Toute modification ici entraînera une mise à jour progressive des Pods.
  • spec.template.metadata.labels: Les labels qui seront appliqués aux Pods créés par ce Deployment. Ils doivent correspondre au selector.
  • spec.template.spec.containers: La liste des conteneurs qui composent le Pod.
    • name: Nom du conteneur (unique dans le Pod).
    • image: L'image Docker à utiliser.
    • ports: Les ports exposés par le conteneur.

Pour appliquer ce déploiement, vous utiliseriez la commande kubectl apply -f nginx-deployment.yaml.


4.4. Service : Exposer votre Application

Un Service est un moyen abstrait d'exposer un ensemble de Pods en tant que service réseau, avec une adresse IP stable et un DNS. Il fournit un moyen stable d'accéder aux Pods, même s'ils sont recréés ou déplacés.

  • Problème résolu : Les Pods sont éphémères et leurs adresses IP changent constamment. Comment les autres services ou les utilisateurs externes peuvent-ils les trouver ? Le Service résout ce problème.
  • Le Service sélectionne les Pods via un selector basé sur les labels (comme le Deployment).
  • Types de Services :
    • ClusterIP (par défaut) : Expose le service sur une IP interne au cluster. Accessible uniquement depuis l'intérieur du cluster.
    • NodePort : Expose le service sur un port statique sur chaque nœud du cluster. Accessible depuis l'extérieur du cluster via <NodeIP>:<NodePort>. Pour les tests ou petits déploiements.
    • LoadBalancer : Expose le service via le load balancer du fournisseur de cloud (si vous êtes sur AWS, GCP, Azure...). C'est la méthode recommandée pour exposer un service à l'Internet.
    • ExternalName : Mappe un service à un nom DNS externe, utile pour les services externes au cluster.

Exemple de code 2 : Exposition du service Nginx

Ce fichier YAML crée un Service qui expose notre nginx-deployment sur le port 80.

# filename: nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx # Ce sélecteur va cibler les Pods avec le label 'app: nginx'
  ports:
    - protocol: TCP
      port: 80 # Le port sur lequel le Service sera accessible
      targetPort: 80 # Le port sur lequel le conteneur (dans le Pod) écoute
  type: LoadBalancer # Ou ClusterIP, ou NodePort selon le besoin

Explication du code :

  • apiVersion: v1 pour les Services.
  • kind: Service.
  • metadata.name: Nom du service.
  • spec.selector.app: C'est crucial ! Il indique au Service de diriger le trafic vers les Pods qui ont le label app: nginx. C'est comme ça que le Service et le Deployment sont liés.
  • spec.ports: Définit comment le trafic est mappé.
    • port: Le port sur lequel le Service lui-même sera accessible.
    • targetPort: Le port sur lequel l'application (le conteneur) à l'intérieur du Pod écoute.
  • spec.type: Le type de Service. LoadBalancer ici signifie que si vous êtes sur un fournisseur de cloud, un équilibreur de charge externe sera provisionné.

Pour appliquer ce service, vous utiliseriez la commande kubectl apply -f nginx-service.yaml.


4.5. Namespace : Isolation Logique

Un Namespace permet d'isoler logiquement des groupes de ressources au sein d'un même cluster Kubernetes.

  • Utile pour des environnements multiples (développement, staging, production) ou pour différentes équipes au sein d'une même organisation.
  • Les noms des ressources doivent être uniques au sein d'un Namespace, mais peuvent être dupliqués entre Namespaces.
  • Chaque cluster démarre avec des Namespaces par défaut : default, kube-system, kube-public.

4.6. Volume : Persistance des Données

Comme les Pods sont éphémères, les données stockées à l'intérieur d'un conteneur disparaissent avec le Pod. Les Volumes permettent de stocker des données de manière persistante ou partagée.

  • Un Volume est un répertoire (qui peut être monté) accessible par les conteneurs d'un Pod.
  • Types de Volumes :
    • emptyDir: Un volume temporaire créé avec le Pod, détruit quand le Pod l'est. Utile pour le stockage temporaire ou le partage entre conteneurs du même Pod.
    • hostPath: Monte un fichier ou un répertoire de la machine hôte. Peut poser des problèmes de portabilité.
    • PersistentVolumeClaim (PVC) & PersistentVolume (PV): Le mécanisme standard pour le stockage persistant et découplé. Le PV représente une ressource de stockage physique (ex: un disque réseau), et le PVC est une requête de stockage faite par un Pod.

4.7. ConfigMap et Secret : Configuration et Données Sensibles

  • ConfigMap : Permet de stocker des données de configuration non sensibles sous forme de paires clé-valeur. Idéal pour les variables d'environnement, les fichiers de configuration.
  • Secret : Similaire à ConfigMap, mais conçu pour stocker des données sensibles (mots de passe, clés API, tokens) de manière plus sécurisée (encodées en base64 par défaut, et idéalement chiffrées au repos).

4.8. Ingress : Accès HTTP/HTTPS Externe

Alors que les Services de type LoadBalancer exposent des services au niveau de la couche 4 (TCP/UDP), un Ingress gère l'accès HTTP et HTTPS aux services à l'intérieur du cluster.

  • Il agit comme une passerelle d'entrée, permettant de configurer le routage du trafic basé sur le chemin URL ou le nom d'hôte.
  • Nécessite un "Ingress Controller" (comme Nginx Ingress Controller, Traefik, ou le GKE Ingress Controller) pour fonctionner.

5. Interaction avec Kubernetes : kubectl

L'outil en ligne de commande principal pour interagir avec un cluster Kubernetes est kubectl.

  • kubectl communique avec le kube-apiserver pour créer, modifier, supprimer des objets Kubernetes et obtenir des informations sur l'état du cluster.
  • Commandes courantes :
    • kubectl apply -f <fichier.yaml> : Applique un fichier de configuration.
    • kubectl get <type_objet> : Liste les objets d'un certain type (ex: kubectl get pods, kubectl get deployments).
    • kubectl describe <type_objet> <nom_objet> : Affiche les détails d'un objet.
    • kubectl logs <nom_pod> : Affiche les logs d'un conteneur dans un Pod.
    • kubectl exec -it <nom_pod> -- /bin/bash : Exécute une commande dans un conteneur d'un Pod.
    • kubectl delete -f <fichier.yaml> ou kubectl delete <type_objet> <nom_objet> : Supprime des objets.

Conclusion

Nous avons fait un premier pas majeur dans l'univers de Kubernetes. Vous devriez maintenant avoir une compréhension solide de :

  • Pourquoi l'orchestration de conteneurs est essentielle pour gérer des applications modernes à l'échelle.
  • Ce qu'est Kubernetes, sa philosophie déclarative et son origine.
  • L'architecture d'un cluster Kubernetes, avec ses composants du Plan de Contrôle (cerveau) et des Nœuds de Travail (ouvriers).
  • Les objets fondamentaux qui constituent le vocabulaire de Kubernetes :
    • Le Pod (l'unité atomique).
    • Le ReplicaSet (pour la haute disponibilité des Pods).
    • Le Deployment (pour la gestion des déploiements et des mises à jour).
    • Le Service (pour exposer vos applications).
    • Les Namespaces (pour l'organisation logique).
    • Les Volumes, ConfigMaps et Secrets (pour la persistance des données et la configuration).
    • L'Ingress (pour l'accès HTTP/HTTPS).
  • L'outil kubectl pour interagir avec votre cluster.

Kubernetes est un système puissant et complexe, mais en maîtrisant ces concepts fondamentaux, vous avez posé des bases solides. La prochaine étape sera de mettre les mains dans le cambouis, probablement en installant un mini-cluster local (comme Minikube ou Kind) et en manipulant ces objets vous-même.

Continuez votre exploration, car la maîtrise de Kubernetes est une compétence inestimable dans le monde du développement et de l'exploitation modernes !