
Déployer une application sur Kubernetes consiste à déclarer comment elle doit tourner, puis à lui donner un point d'accès stable. Dans ce guide, vous allez créer un namespace, déployer nginx avec un Deployment, l'exposer via un Service, vérifier qu'il répond, puis observer son comportement quand vous augmentez le nombre de réplicas.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer un namespace pour organiser votre application
- Déployer une application avec
kubectl create deployment - Exposer l'application avec un Service
- Comprendre le lien entre labels, sélecteurs et endpoints
- Scaler et observer l'application
- Voir ce que Kubernetes fait en arrière-plan
Ce que vous allez créer
Section intitulée « Ce que vous allez créer »Lisez le schéma ci-dessous comme une chaîne de responsabilité. Chaque niveau crée et surveille le niveau inférieur : vous ne déclarez que le Deployment, le reste apparaît tout seul. Le Service est volontairement à part, au même niveau que le Deployment : il ne descend pas de lui, il vise les Pods de côté, par leur label.
À la fin de ce guide, vous aurez :
- Un namespace
demo-apppour organiser les ressources - Un Deployment qui gère des Pods nginx via un ReplicaSet
- Un Service qui cible les Pods portant le label
app=nginx
Étape 1 : Créer un namespace dédié
Section intitulée « Étape 1 : Créer un namespace dédié »Un namespace organise et isole logiquement vos ressources dans le cluster. C'est une bonne habitude à prendre dès le début.
kubectl create namespace demo-appnamespace/demo-app createdVérifiez qu'il existe :
kubectl get namespace demo-appNAME STATUS AGEdemo-app Active 5sÉtape 2 : Créer un Deployment
Section intitulée « Étape 2 : Créer un Deployment »Un Deployment dit à Kubernetes : "je veux X pods qui exécutent cette image".
Méthode impérative (pour apprendre)
Section intitulée « Méthode impérative (pour apprendre) »La commande kubectl create deployment crée un Deployment en une ligne :
kubectl create deployment nginx --image=nginx:1.28 -n demo-appdeployment.apps/nginx created| Option | Signification |
|---|---|
nginx | Nom du Deployment |
--image=nginx:1.28 | Image Docker à utiliser (version figée) |
-n demo-app | Namespace cible |
Vérifiez que le Deployment est prêt
Section intitulée « Vérifiez que le Deployment est prêt »La création du Deployment est instantanée, le démarrage du Pod ne l'est pas :
le nœud doit d'abord télécharger l'image, ce qui prend de quelques secondes
à une minute selon votre connexion. Si la commande suivante affiche 0/1,
relancez-la quelques secondes plus tard avant de conclure à un problème.
kubectl get deployment nginx -n demo-appNAME READY UP-TO-DATE AVAILABLE AGEnginx 1/1 1 1 10s| Colonne | Signification |
|---|---|
READY | Pods prêts / Pods souhaités |
UP-TO-DATE | Pods à jour avec la dernière configuration |
AVAILABLE | Pods qui peuvent servir du trafic |
1/1 signifie : 1 pod est prêt sur 1 demandé. Quand ces chiffres correspondent, le déploiement est opérationnel.
Voir le ReplicaSet créé
Section intitulée « Voir le ReplicaSet créé »Le Deployment ne crée pas directement les Pods. Il passe par un ReplicaSet :
kubectl get replicasets -n demo-appNAME DESIRED CURRENT READY AGEnginx-6d8867d6c 1 1 1 15sLe Deployment a créé un ReplicaSet (nginx-6d8867d6c), qui lui-même crée et surveille les Pods. Vous n'avez pas besoin de manipuler le ReplicaSet directement, c'est le Deployment qui le gère.
Voir le pod créé
Section intitulée « Voir le pod créé »C'est le Pod qui exécute réellement nginx : le Deployment et le ReplicaSet ne
sont que des objets de gestion. Regardez la colonne READY : le 1/1 compte
ici les conteneurs prêts dans le Pod, alors que le 1/1 du Deployment
comptait les Pods prêts. Deux colonnes de même apparence, deux unités
différentes.
kubectl get pods -n demo-appNAME READY STATUS RESTARTS AGEnginx-6d8867d6c-z2j62 1/1 Running 0 18sLe nom du pod (nginx-6d8867d6c-z2j62) est généré automatiquement :
nginx: nom du Deployment6d8867d6c: identifiant du ReplicaSetz2j62: identifiant unique du pod
Étape 3 : Exposer avec un Service
Section intitulée « Étape 3 : Exposer avec un Service »Le pod tourne, mais il n'est pas accessible de manière stable. Pour l'atteindre, créez un Service.
kubectl expose deployment nginx --port=80 --type=ClusterIP -n demo-appservice/nginx exposed| Option | Signification |
|---|---|
--port=80 | Port sur lequel le Service écoute |
--type=ClusterIP | Accessible uniquement depuis l'intérieur du cluster |
Vérifiez le Service créé :
kubectl get service nginx -n demo-appNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEnginx ClusterIP 10.43.51.181 <none> 80/TCP 8s| Colonne | Signification |
|---|---|
CLUSTER-IP | Adresse IP interne au cluster |
EXTERNAL-IP | <none> car ClusterIP n'est pas exposé à l'extérieur |
PORT(S) | Port d'écoute |
Étape 4 : Comprendre comment le Service trouve les Pods
Section intitulée « Étape 4 : Comprendre comment le Service trouve les Pods »C'est ici que vous comprenez vraiment comment Kubernetes relie les choses.
Voir les labels des Pods
Section intitulée « Voir les labels des Pods »Le Deployment a créé des Pods avec le label app=nginx. Vous ne l'avez jamais
écrit : kubectl create deployment l'a posé pour vous à partir du nom du
Deployment. Le second label, pod-template-hash, est ajouté par Kubernetes et
identifie le ReplicaSet d'origine ; c'est lui qui permet de distinguer les
anciens Pods des nouveaux pendant une mise à jour.
kubectl get pods -n demo-app --show-labelsNAME READY STATUS RESTARTS AGE LABELSnginx-6d8867d6c-z2j62 1/1 Running 0 45s app=nginx,pod-template-hash=6d8867d6cVoir le sélecteur du Service
Section intitulée « Voir le sélecteur du Service »Deux lignes seulement comptent dans cette sortie très bavarde : Selector et
Endpoints. La première est ce que vous avez déclaré, la seconde est ce que
Kubernetes en a déduit. Comparer les deux est le réflexe de diagnostic le
plus rentable sur un Service : un sélecteur correct avec des endpoints vides
signifie qu'aucun Pod ne porte le label attendu.
kubectl describe service nginx -n demo-appName: nginxNamespace: demo-appSelector: app=nginxType: ClusterIPIP: 10.43.51.181Port: <unset> 80/TCPEndpoints: 10.42.0.15:80| Champ | Signification |
|---|---|
Selector | Label que le Service cherche (app=nginx) |
Endpoints | Adresses IP des Pods qui correspondent au sélecteur |
Le lien est maintenant clair :
- Le Deployment crée des Pods avec le label
app=nginx - Le Service sélectionne les Pods ayant
app=nginx - Les
Endpointsmontrent les Pods effectivement ciblés
Étape 5 : Vérifier que l'application répond
Section intitulée « Étape 5 : Vérifier que l'application répond »Option 1 : Tester depuis un pod temporaire
Section intitulée « Option 1 : Tester depuis un pod temporaire »Cette commande crée un Pod temporaire, exécute wget, affiche le résultat puis supprime le Pod :
kubectl run test-curl --image=busybox:1.36 --rm -i --restart=Never -n demo-app -- wget -qO- http://nginx:80<!DOCTYPE html><html><head><title>Welcome to nginx!</title>...L'application répond ! Le Service nginx est accessible depuis n'importe quel Pod du namespace via son nom DNS (nginx ou nginx.demo-app.svc.cluster.local).
| Option | Signification |
|---|---|
--rm | Supprime le pod après exécution |
-i | Mode interactif (récupère la sortie) |
--restart=Never | Ne pas redémarrer si la commande échoue |
wget -qO- | Télécharge et affiche le contenu |
Option 2 : Port-forward (accès depuis votre poste)
Section intitulée « Option 2 : Port-forward (accès depuis votre poste) »Pour accéder à nginx depuis votre navigateur :
kubectl port-forward svc/nginx 8080:80 -n demo-appForwarding from 127.0.0.1:8080 -> 80Forwarding from [::1]:8080 -> 80Ouvrez http://localhost:8080 dans votre navigateur. Vous verrez la page d'accueil nginx.
Appuyez sur Ctrl+C pour arrêter le port-forward.
Étape 6 : Scaler l'application
Section intitulée « Étape 6 : Scaler l'application »Actuellement, vous avez 1 pod. Pour en avoir 3 :
kubectl scale deployment nginx --replicas=3 -n demo-appdeployment.apps/nginx scaledVérifiez que les nouveaux pods démarrent :
kubectl get pods -n demo-appNAME READY STATUS RESTARTS AGEnginx-6d8867d6c-57bpf 1/1 Running 0 10snginx-6d8867d6c-lptvk 1/1 Running 0 10snginx-6d8867d6c-z2j62 1/1 Running 0 2m3 pods tournent maintenant. Vérifiez que le Service les voit tous :
kubectl describe service nginx -n demo-app | grep EndpointsEndpoints: 10.42.0.15:80,10.42.0.16:80,10.42.0.17:80Le Service a détecté les nouveaux Pods et les a ajoutés à sa liste d'endpoints. Il répartit automatiquement les requêtes entre eux.
Étape 7 : Observer l'application
Section intitulée « Étape 7 : Observer l'application »Voir les détails du Deployment
Section intitulée « Voir les détails du Deployment »describe est plus verbeux que get parce qu'il ajoute deux choses absentes
d'un tableau : le modèle de Pod complet, c'est-à-dire ce que le Deployment
va reproduire à chaque réplica, et la liste des événements récents en bas
de sortie. Quand quelque chose ne va pas, ce sont ces événements de fin de
sortie qu'il faut lire en premier.
kubectl describe deployment nginx -n demo-appName: nginxNamespace: demo-appLabels: app=nginxSelector: app=nginxReplicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailableStrategyType: RollingUpdatePod Template: Labels: app=nginx Containers: nginx: Image: nginx:1.28@sha256:146adea4768b83c607d0bdfa4188464e3da6e0a3ad4475db1d1d8f64f27c29ccCette commande montre la configuration complète et les événements récents.
Voir les logs d'un Pod
Section intitulée « Voir les logs d'un Pod »Les logs viennent toujours d'un Pod (pas du Deployment). Identifiez d'abord un Pod :
kubectl get pods -n demo-appPuis affichez ses logs :
kubectl logs nginx-6d8867d6c-z2j62 -n demo-app --tail=102026/03/21 09:52:26 [notice] 1#1: start worker process 41...Raccourci : logs via le Deployment
Section intitulée « Raccourci : logs via le Deployment »kubectl permet de lire les logs via le nom du Deployment :
kubectl logs deployment/nginx -n demo-app --tail=10Found 3 pods, using pod/nginx-6d8867d6c-z2j622026/03/21 09:52:26 [notice] 1#1: start worker process 41...Cette forme est pratique, mais les logs viennent toujours d'un seul Pod, kubectl en choisit un pour vous.
Pour suivre les logs en temps réel :
kubectl logs deployment/nginx -n demo-app -fAppuyez sur Ctrl+C pour arrêter.
Voir les événements du namespace
Section intitulée « Voir les événements du namespace »Les événements forment le journal de bord du namespace : c'est là que
Kubernetes explique pourquoi il a agi. Le tri par .lastTimestamp est
indispensable, car sans lui la sortie n'est pas chronologique et devient
illisible dès la dizaine de lignes.
kubectl get events -n demo-app --sort-by='.lastTimestamp'Vous y retrouvez la création des Pods, le scaling, et les erreurs éventuelles. Un détail à connaître : les événements ne sont pas conservés indéfiniment, ils expirent au bout d'une heure par défaut. Un incident survenu la veille n'y figurera plus.
Méthode déclarative (fichier YAML)
Section intitulée « Méthode déclarative (fichier YAML) »Les commandes impératives sont parfaites pour apprendre et explorer. En production, on préfère décrire les ressources dans des fichiers YAML versionnés dans Git.
Voici l'équivalent de ce que vous avez créé :
apiVersion: v1kind: Namespacemetadata: name: demo-app---apiVersion: apps/v1kind: Deploymentmetadata: name: nginx namespace: demo-appspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.28@sha256:146adea4768b83c607d0bdfa4188464e3da6e0a3ad4475db1d1d8f64f27c29cc ports: - containerPort: 80---apiVersion: v1kind: Servicemetadata: name: nginx namespace: demo-appspec: selector: app: nginx ports: - port: 80 targetPort: 80 type: ClusterIPPour appliquer ce fichier :
kubectl apply -f demo-app.yamlCe que Kubernetes a fait en arrière-plan
Section intitulée « Ce que Kubernetes a fait en arrière-plan »Récapitulons ce qui s'est passé quand vous avez exécuté ces commandes :
- Vous avez créé un Deployment → Kubernetes a créé un ReplicaSet
- Le ReplicaSet a créé les Pods → Kubernetes a assigné chaque Pod à un nœud
- Chaque nœud a téléchargé l'image et démarré le conteneur nginx
- Vous avez créé un Service → Kubernetes a enregistré les Pods correspondant au sélecteur
app=nginx - Le Service a reçu une IP stable → Les endpoints pointent vers les Pods
- Vous avez scalé → Le ReplicaSet a créé 2 Pods supplémentaires
- Le Service a mis à jour ses endpoints automatiquement
C'est ça le modèle Kubernetes : vous déclarez ce que vous voulez, Kubernetes s'occupe de le réaliser et de le maintenir.
Nettoyer
Section intitulée « Nettoyer »Pour supprimer tout ce que vous avez créé, supprimez le namespace :
kubectl delete namespace demo-appnamespace "demo-app" deletedCette commande supprime toutes les ressources du namespace (Deployment, ReplicaSet, Service, Pods).
Dépannage
Section intitulée « Dépannage »Le Deployment reste à 0/1
Section intitulée « Le Deployment reste à 0/1 »Un Deployment bloqué à 0/1 ne dit jamais pourquoi de lui-même : l'objet
Deployment se contente de constater que son Pod n'est pas prêt. La raison se
trouve un cran plus bas, dans les événements du Pod. Commencez donc toujours
par les deux commandes suivantes avant de modifier quoi que ce soit.
kubectl describe deployment nginx -n demo-appkubectl get events -n demo-app| Cause fréquente | Solution |
|---|---|
| Image introuvable | Vérifiez le nom de l'image (nginx:1.28 pas ngix:1.28) |
| Pas de ressources | Réduisez le nombre de réplicas ou libérez de la mémoire |
| ImagePullBackOff | Problème de connexion à la registry ou image privée |
Le pod est en CrashLoopBackOff
Section intitulée « Le pod est en CrashLoopBackOff »CrashLoopBackOff signifie que le conteneur démarre puis s'arrête, en boucle.
Le piège : au moment où vous tapez kubectl logs, le conteneur vient de
redémarrer et n'a encore rien écrit. Les logs qui vous intéressent sont ceux de
l'exécution précédente, celle qui a planté.
kubectl logs <nom-du-pod> -n demo-app --previousC'est le rôle du flag --previous. Notez aussi que Kubernetes espace les redémarrages successifs, jusqu'à cinq minutes d'attente : un Pod en CrashLoopBackOff depuis longtemps peut sembler figé alors qu'il attend simplement sa prochaine tentative.
Le Service ne répond pas
Section intitulée « Le Service ne répond pas »Un Service qui ne répond pas n'est presque jamais cassé au sens technique : il fonctionne, mais il ne pointe vers rien. Le diagnostic tient donc en une seule vérification, et elle vient avant toute autre.
kubectl describe service nginx -n demo-appVérifiez que Endpoints n'est pas vide. S'il l'est, le sélecteur du Service ne correspond à aucun Pod, vérifiez les labels avec kubectl get pods --show-labels.
Le namespace reste en Terminating
Section intitulée « Le namespace reste en Terminating »C'est normal, donnez-lui quelques secondes. Kubernetes nettoie les ressources dans l'ordre. Si ça dure trop longtemps, des finalizers peuvent bloquer la suppression.
Récapitulatif des commandes
Section intitulée « Récapitulatif des commandes »Pour apprendre (impératif)
Section intitulée « Pour apprendre (impératif) »Ces cinq commandes créent des objets sans passer par un fichier. Elles sont faites pour explorer vite : rien n'est versionné, rien n'est relisible plus tard, et vous ne pouvez pas rejouer la séquence à l'identique sur un autre cluster. C'est acceptable en apprentissage, pas au-delà.
| Action | Commande |
|---|---|
| Créer namespace | kubectl create namespace nom |
| Créer Deployment | kubectl create deployment nom --image=image -n namespace |
| Exposer avec Service | kubectl expose deployment nom --port=80 -n namespace |
| Scaler | kubectl scale deployment nom --replicas=N -n namespace |
| Supprimer tout | kubectl delete namespace nom |
Pour observer
Section intitulée « Pour observer »Celles-ci ne modifient rien : vous pouvez les lancer sans risque, y compris sur un cluster de production. Ce sont les seules du guide dont vous aurez besoin tous les jours. Retenez surtout la troisième, qui relie une panne d'accès à sa cause la plus fréquente, un sélecteur qui ne trouve aucun Pod.
| Action | Commande |
|---|---|
| Voir les pods | kubectl get pods -n namespace |
| Voir les labels | kubectl get pods -n namespace --show-labels |
| Voir les endpoints | kubectl describe service nom -n namespace |
| Voir les logs | kubectl logs <pod> -n namespace |
| Port-forward | kubectl port-forward svc/nom 8080:80 -n namespace |
| Tester depuis un pod | kubectl run test --rm -i --restart=Never --image=busybox -- wget -qO- http://service |
En production (déclaratif)
Section intitulée « En production (déclaratif) »Deux commandes suffisent, et la seconde est celle qu'on oublie. kubectl diff
compare votre fichier à l'état réel du cluster et affiche ce qui changerait,
sans rien appliquer. Prenez l'habitude de la lancer avant chaque apply :
c'est ce qui vous évitera d'écraser une modification faite à la main entre-temps.
| Action | Commande |
|---|---|
| Appliquer une config | kubectl apply -f fichier.yaml |
| Voir les différences | kubectl diff -f fichier.yaml |
À retenir
Section intitulée « À retenir »- Un Deployment gère vos Pods via un ReplicaSet, il les crée, les surveille et les recrée si nécessaire
- Un Service expose vos Pods, il fournit une adresse stable même quand les Pods changent
- Le Service cible les Pods par labels, pas le Deployment, vérifiez toujours les
Endpoints - Utilisez un namespace pour organiser et nettoyer proprement
- Figez les versions d'images (
nginx:1.28pasnginx:latest) - Les commandes impératives sont pour apprendre, en production, passez au déclaratif (YAML)
kubectl describeest votre meilleur ami pour comprendre ce qui se passe- Si vous cassez quelque chose, supprimez le namespace et recommencez
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Architecture Kubernetes : Ce qui s'est réellement passé dans le cluster pendant ce déploiement.
- Les Deployments : Les stratégies de mise à jour et de rollback derrière la commande utilisée.
- Les Services : ClusterIP, NodePort et LoadBalancer, pour choisir la bonne exposition.
- Les ConfigMaps : La sortie des paramètres hors de l'image, étape suivante de toute application.