L'histoire de la conteneurisation se comprend mieux comme une succession de réponses à un même problème : déployer des applications de façon fiable, dense et reproductible.
Au départ, une application = un serveur physique dédié. Le modèle est simple mais se heurte vite à un problème de scalabilité : chaque nouvelle application (ou montée en charge) suppose une nouvelle machine, avec son coût, son délai d'approvisionnement et son administration propre. Les ressources, dimensionnées pour les pics, restent largement sous-utilisées le reste du temps.
La virtualisation améliore nettement la situation : plusieurs VM cohabitent sur un même serveur physique, ce qui augmente la densité et la souplesse. Mais ce n'est pas encore l'idéal. Chaque VM embarque son propre système d'exploitation complet — un inconvénient supplémentaire par rapport au serveur dédié : il faut provisionner, mettre à jour et sécuriser autant d'OS qu'il y a de VM, ce qui reconsomme énormément de ressources (RAM, disque, CPU pour le boot et les services système).
L'avantage majeur que la VM conserve, en revanche, est de taille : une isolation forte, chaque VM disposant de son propre noyau.
Le conteneur reprend l'objectif d'isolation de la VM, mais sans dupliquer l'OS. L'idée : créer l'isolation directement au niveau du système hôte, en cloisonnant des processus plutôt qu'en virtualisant une machine complète.
SERVEUR DÉDIÉ MACHINE VIRTUELLE CONTENEUR
───────────── ───────────────── ─────────
┌─────┐ ┌─────┐ ┌────┐ ┌────┐ ┌────┐
│ App │ │ App │ │App │ │App │ │App │
├─────┤ ├─────┤ ├────┤ ├────┤ ├────┤
┌─────────┐ │ OS │ │ OS │ ← chaque VM │deps│ │deps│ │deps│
│ App │ ├─────┤ ├─────┤ a son OS └────┘ └────┘ └────┘
├─────────┤ │Hyperviseur │ ┌──────────────────┐
│ OS │ ├─────────────┤ │ Moteur conteneurs│
├─────────┤ │ OS │ ├──────────────────┤
│ Matériel│ │ Matériel │ │ OS hôte (1 seul) │
└─────────┘ └─────────────┘ ├──────────────────┤
│ Matériel │
1 app = 1 machine densité ↑ mais OS dupliqué └──────────────────┘
noyau partagé, léger
Le conteneur isole les processus (via les namespaces du noyau Linux) et borne leurs ressources (via les cgroups), tout en partageant le noyau de l'hôte. D'où sa légèreté — et, on le verra, son principal point de vigilance en sécurité.
Ces mécanismes (namespaces, cgroups, chroot) existaient bien avant les outils modernes de conteneurisation. Le mérite de Docker n'est pas de les avoir inventés, mais de les avoir rendus simples d'usage.
Le tournant introduit par Docker n'est pas technique au sens du noyau : c'est un tournant de standardisation et d'expérience développeur.
Docker normalise la façon d'empaqueter une application avec toutes ses dépendances. Le résultat de cet empaquetage — l'image — devient le livrable : l'unité que l'on construit une fois et que l'on déploie partout.
Cela apporte deux propriétés décisives :
Le format d'image est aujourd'hui standardisé par l'Open Container Initiative (OCI). Une image construite avec Docker est donc utilisable par l'ensemble de l'écosystème (autres moteurs, orchestrateurs, registries), sans dépendre d'un fournisseur unique.
Parce que l'image est un artefact stable et reproductible, on livre plus vite et plus souvent. Docker s'inscrit ainsi naturellement dans les chaînes d'intégration continue / déploiement continu (CI/CD) : construire l'image, la tester, la publier, la déployer — automatiquement.
Le partage du noyau est la contrepartie de la légèreté. Comme le noyau est mutualisé entre tous les conteneurs, une faille du noyau a une surface d'impact plus large : un attaquant qui exploite une vulnérabilité peut potentiellement franchir l'isolation et se propager — on parle de capillarité entre conteneurs, ou d'évasion vers l'hôte. C'est le point d'attention structurel de toute la conteneurisation, qui justifiera plus loin les bonnes pratiques (utilisateur non-root, images minimales, scan de vulnérabilités).
En une phrase : Docker a rendu simple l'utilisation d'outils d'isolation finalement assez anciens, et c'est précisément cette simplicité qui a déclenché son adoption massive.
Le Dockerfile est le script qui décrit et construit l'image, couche par couche (layer by layer). Chaque instruction produit une couche empilée sur la précédente. L'image finale contient donc l'application et l'ensemble de ses couches : système de base minimal, librairies, dépendances, code, configuration.
Cette construction en couches permet aussi une gestion des versions rigoureuse : on tague les images, on conserve l'historique, on peut revenir à une version antérieure.
Dockerfile ──build──► Image (versionnée) ──instanciation──► Conteneur
(description) (le livrable) (l'exécution)
Le conteneur fait tourner l'application. Deux propriétés essentielles :
| Instruction | Rôle |
|---|---|
FROM |
Image de base (primaire) dont on hérite. Première instruction du fichier. |
COPY |
Copie des fichiers depuis le contexte de build vers l'image. |
WORKDIR /opt |
Définit le répertoire de travail courant pour les instructions suivantes. |
EXPOSE 8080 |
Documente le port sur lequel l'application écoute. |
CMD |
Commande exécutée au démarrage du conteneur. |
RUN |
Exécute des commandes shell pendant le build (installation de paquets, etc.). |
ENV |
Définit une variable d'environnement. |
VOLUME |
Déclare un répertoire destiné à être persistant (monté hors du conteneur). |
💡
RUNvsCMD— la distinction clé :RUNs'exécute au moment du build (et fige son résultat dans une couche de l'image) ;CMDs'exécute au lancement du conteneur. On installe avecRUN, on lance l'application avecCMD.
Ces pratiques visent trois objectifs simultanés : images légères, build reproductible, sécurité renforcée.
nginx:1.27-alpine plutôt que nginx:latest) afin de garantir une référence stable et un build reproductible dans le temps.stdout/stderr) plutôt que dans des fichiers internes : c'est le moteur (ou l'orchestrateur) qui collecte et route les journaux.USER). Un conteneur compromis tournant en root facilite l'évasion vers l'hôte.🧭 Ces règles ne sont pas cosmétiques : « un process au premier plan », « l'app meurt → le conteneur tombe » et « logs sur stdout » sont précisément ce qui rend un conteneur pilotable par un orchestrateur comme Kubernetes. Les bonnes pratiques Docker préparent le terrain pour K8s.
Lancer manuellement plusieurs conteneurs liés (web, base de données, cache…) devient vite fastidieux. Docker Compose automatise la création et l'articulation d'un ensemble de conteneurs.
docker compose up).** Compose n'orchestre pas un cluster multi-nœuds. Dès qu'on vise la haute disponibilité, le scaling automatique et la résilience à l'échelle (réparation automatique, répartition sur plusieurs serveurs), on passe à Kubernetes.
Kubernetes (souvent abrégé K8s) est une plateforme d'orchestration de conteneurs. Là où Docker gère des conteneurs sur une machine, K8s gère une flotte de serveurs — appelés nodes — sur lesquels il déploie les conteneurs, met à disposition les ressources et en optimise l'usage.
┌──────────────────────────────┐
│ PLAN DE CONTRÔLE │
│ (control plane) │
│ décide, planifie, surveille │
└───────────────┬──────────────┘
│ pilote
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ NODE 1 │ │ NODE 2 │ │ NODE 3 │
│ ┌─────┐ │ │ ┌─────┐ │ │ ┌─────┐ │
│ │Pods │ │ │ │Pods │ │ │ │Pods │ │
│ └─────┘ │ │ └─────┘ │ │ └─────┘ │
└─────────┘ └─────────┘ └─────────┘
En contrepartie de cette puissance, l'installation, la configuration et l'administration de Kubernetes sont complexes. C'est le revers structurel de la plateforme (développé au §11).
L'écosystème des distributions. On déploie rarement Kubernetes « brut ». On s'appuie sur des distributions : managées chez les opérateurs cloud (EKS, AKS, GKE, ainsi que des acteurs européens comme OVHcloud ou Scaleway) ou légères pour le lab, l'edge et les petites productions (K3s, k0s). Des plateformes comme Rancher viennent par-dessus pour gérer plusieurs clusters de façon centralisée.
Docker et Kubernetes — une confusion fréquente à lever. Kubernetes n'utilise pas Docker comme moteur d'exécution à l'intérieur des nœuds : il s'appuie sur des runtimes conformes à l'interface CRI (containerd, CRI-O). Cela ne change rien pour le développeur : les images construites avec Docker (format OCI) restent parfaitement utilisables. Seul le composant qui exécute les conteneurs sur les nœuds diffère.
Kubernetes manipule des objets déclaratifs. Voici la chaîne qui mène d'un conteneur isolé à une application résiliente.
Le Pod est l'unité de base de Kubernetes, son plus petit élément déployable. Il contient un ou plusieurs conteneurs qui :
Point capital : le Pod est éphémère. Il peut être détruit et recréé à tout moment (panne d'un nœud, mise à l'échelle, mise à jour). On ne s'attache jamais à un Pod individuel.
💡 Le cas « plusieurs conteneurs dans un Pod » correspond typiquement au motif sidecar : un conteneur principal accompagné d'un conteneur auxiliaire (proxy, collecteur de logs, etc.) qui doivent partager réseau et stockage.
Le ReplicaSet définit combien de Pods (réplicas) doivent tourner, à partir d'un template qui décrit le Pod à instancier. Si un Pod disparaît, le ReplicaSet en recrée un pour maintenir le compte.
Le Deployment définit et historise les ReplicaSets. C'est lui qu'on manipule en pratique. Son intérêt majeur : il permet le retour en arrière (rollback) vers une version précédente, et les mises à jour progressives (rolling updates). Le Deployment concerne les applications stateless (sans état).
Pour les applications stateful (avec état) — typiquement un SGBD — il existe le StatefulSet. Il déploie des Pods à identité stable (nom et stockage persistants, ordre de démarrage maîtrisé), ce qu'exigent les bases de données et autres services qui conservent des données.
Deployment (stateless) StatefulSet (stateful)
─────────── ───────────
historise les versions identité stable des pods
rollback possible stockage persistant dédié
│ ordre de démarrage maîtrisé
▼ │
ReplicaSet ▼
(maintient N réplicas) ex. cluster de base de données
│
▼
Pods (éphémères, interchangeables)
Une bonne application ne code pas sa configuration en dur dans l'image. Kubernetes fournit deux objets pour l'externaliser :
Ces données sont rendues accessibles aux Pods, notamment via des volumes (ou injectées comme variables d'environnement).
Sécurité des Secrets : par défaut, un objet
Secretn'est qu'encodé en base64, pas chiffré — il ne faut pas le considérer comme protégé en soi. Les bonnes pratiques imposent d'activer le chiffrement au repos (encryption at rest) du datastore, un RBAC strict sur l'accès aux Secrets, voire des solutions externes (Sealed Secrets, External Secrets Operator, HashiCorp Vault).
Puisque les Pods sont éphémères, les données durables vivent en dehors d'eux. Le PersistentVolumeClaim (PVC) est la demande de stockage persistant qu'un Pod adresse au cluster : il met un volume persistant à disposition du Pod, indépendamment du cycle de vie de celui-ci. C'est le mécanisme qui permet, par exemple, à une base de données conteneurisée de conserver ses données malgré les recréations de Pods.
Problème : le Pod est éphémère, son adresse change. Comment un client s'y connecte-t-il de façon fiable ?
Réponse : le Service. Il fournit un point d'accès stable (nom DNS et IP virtuelle constants) et oriente les requêtes des clients vers les Pods appropriés, en répartissant la charge entre eux. Les Pods peuvent être détruits et recréés : le Service continue de router le trafic vers les Pods sains du moment.
L'Ingress joue le rôle de reverse-proxy : il gère l'accès au cluster par l'utilisateur final (depuis l'extérieur). Il route le trafic HTTP/HTTPS entrant vers les bons Services selon le nom de domaine ou le chemin d'URL, et gère typiquement la terminaison TLS.
Utilisateur final
│ HTTP/HTTPS
▼
┌─────────┐ ┌──────────┐ ┌──────┐ ┌──────┐
│ Ingress │ ──► │ Service │ ──► │ Pod │ ... │ Pod │
│ (proxy) │ │ (routage │ └──────┘ └──────┘
└─────────┘ │ stable) │ réplicas interchangeables
└──────────┘
Le Namespace partitionne logiquement un cluster. Il permet de gérer les droits sur les ressources (qui peut faire quoi, où), d'isoler des environnements (dev / test / prod) ou des équipes, et d'appliquer des quotas. C'est la brique de base de la multi-tenance et de la gestion des accès (couplée au RBAC).
kubectl — l'outil en ligne de commande de référence pour interagir avec un cluster Kubernetes (créer, inspecter, modifier les objets). C'est l'outil central de tout utilisateur de K8s.k9s — interface texte/TUI qui affiche en temps réel l'état d'un namespace (et plus largement du cluster) sous forme synthétique et navigable. Très apprécié pour le diagnostic rapide.| Outil | Rôle |
|---|---|
| Helm | Gestionnaire de paquets pour Kubernetes (« le apt de K8s ») : empaquette une application complète en charts paramétrables, réutilisables et versionnés. |
| Kustomize | Personnalise des manifests YAML par superposition (overlays), sans dupliquer les fichiers (une base commune déclinée en dev/prod). Intégré à kubectl (kubectl apply -k). |
| ArgoCD / Flux | Déploiement GitOps : le dépôt Git devient la source de vérité, le cluster se synchronise automatiquement sur son contenu. |
| Dive | Explore une image couche par couche, pour analyser son contenu et traquer le gaspillage d'espace. |
| Trivy | Scanne les vulnérabilités des images (CVE des paquets), des manifests et des configurations. Standard de fait dans les chaînes CI. |
| Traefik | Reverse-proxy moderne qui s'intègre nativement avec Docker et Kubernetes (découverte automatique des services, rôle d'Ingress Controller). |
| Popeye | Produit un rapport d'audit sur un cluster K8s (configurations risquées, ressources mal définies, bonnes pratiques non respectées). |
| Lens | IDE graphique pour visualiser et administrer un ou plusieurs clusters. |
Deux constats méritent d'être soulignés.
Kubernetes est, par conception, permissif par défaut : sans durcissement explicite, beaucoup de choses sont autorisées (communications inter-Pods, privilèges, accès aux API). Sécuriser un cluster est un travail à part entière : mise en place du RBAC, des NetworkPolicies (cloisonnement réseau), des Pod Security Standards, du chiffrement des Secrets, etc. Ce n'est pas automatique.
Installer et configurer un cluster K8s est difficile. Le plan de contrôle, le réseau (CNI), le stockage, la sécurité, la supervision : chaque brique demande de l'expertise.
💡 Recommandation : pour la plupart des organisations, mieux vaut s'appuyer sur une offre Kubernetes managée (chez un opérateur cloud) plutôt que d'opérer son propre cluster « à la main ». L'opérateur prend en charge le plan de contrôle, les mises à jour et une partie de la sécurité. Pour l'auto-hébergement léger (lab, edge, petites prod), des distributions comme K3s ou k0s simplifient radicalement l'installation.
Le fil conducteur, du serveur dédié à Kubernetes, est une quête de densité, de portabilité et de résilience :
Les abstractions clés à retenir pour K8s :
| Objet | Rôle en une phrase |
|---|---|
| Pod | Unité atomique, éphémère, 1+ conteneurs partageant réseau et stockage. |
| ReplicaSet | Maintient un nombre voulu de Pods identiques. |
| Deployment | Gère les versions stateless : rolling update et rollback. |
| StatefulSet | Équivalent pour les applications à état (bases de données). |
| Service | Point d'accès stable qui route vers des Pods éphémères. |
| Ingress | Reverse-proxy d'entrée du cluster pour l'utilisateur final. |
| ConfigMap / Secret | Externalisent configuration et données sensibles. |
| PersistentVolumeClaim | Fournit du stockage persistant à un Pod. |
| Namespace | Cloisonne les ressources et gère les droits. |
🎯 À garder en tête : la puissance de Kubernetes a un coût en complexité et en sécurité. On déclare l'état désiré, K8s le maintient — mais c'est à l'équipe d'en assurer le durcissement, car la plateforme est ouverte par défaut.