Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Déployer votre première application sur Kubernetes

20 min de lecture

logo kubernetes

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.

  • 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

À la fin de ce guide, vous aurez :

Namespace demo-app
├── Deployment nginx
│ └── ReplicaSet
│ └── 3 Pods nginx (label: app=nginx)
└── Service nginx
└── sélectionne les Pods avec app=nginx
  • Un namespace demo-app pour 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

Un namespace organise et isole logiquement vos ressources dans le cluster. C’est une bonne habitude à prendre dès le début.

Créer le namespace
kubectl create namespace demo-app
Résultat
namespace/demo-app created

Vérifiez qu’il existe :

Vérifier
kubectl get namespace demo-app
Résultat
NAME STATUS AGE
demo-app Active 5s

Un Deployment dit à Kubernetes : “je veux X pods qui exécutent cette image”.

La commande kubectl create deployment crée un Deployment en une ligne :

Créer le déploiement
kubectl create deployment nginx --image=nginx:1.28 -n demo-app
Résultat
deployment.apps/nginx created
OptionSignification
nginxNom du Deployment
--image=nginx:1.28Image Docker à utiliser (version figée)
-n demo-appNamespace cible
Voir l'état du Deployment
kubectl get deployment nginx -n demo-app
Résultat
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 10s
ColonneSignification
READYPods prêts / Pods souhaités
UP-TO-DATEPods à jour avec la dernière configuration
AVAILABLEPods 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.

Le Deployment ne crée pas directement les Pods. Il passe par un ReplicaSet :

Voir le ReplicaSet
kubectl get replicasets -n demo-app
Résultat
NAME DESIRED CURRENT READY AGE
nginx-6d8867d6c 1 1 1 15s

Le 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.

Lister les pods
kubectl get pods -n demo-app
Résultat
NAME READY STATUS RESTARTS AGE
nginx-6d8867d6c-z2j62 1/1 Running 0 18s

Le nom du pod (nginx-6d8867d6c-z2j62) est généré automatiquement :

  • nginx : nom du Deployment
  • 6d8867d6c : identifiant du ReplicaSet
  • z2j62 : identifiant unique du pod

Le pod tourne, mais il n’est pas accessible de manière stable. Pour l’atteindre, créez un Service.

Exposer le Deployment
kubectl expose deployment nginx --port=80 --type=ClusterIP -n demo-app
Résultat
service/nginx exposed
OptionSignification
--port=80Port sur lequel le Service écoute
--type=ClusterIPAccessible uniquement depuis l’intérieur du cluster

Vérifiez le Service créé :

Voir le Service
kubectl get service nginx -n demo-app
Résultat
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.43.51.181 <none> 80/TCP 8s
ColonneSignification
CLUSTER-IPAdresse 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.

Le Deployment a créé des Pods avec le label app=nginx :

Afficher les labels
kubectl get pods -n demo-app --show-labels
Résultat
NAME READY STATUS RESTARTS AGE LABELS
nginx-6d8867d6c-z2j62 1/1 Running 0 45s app=nginx,pod-template-hash=6d8867d6c
Détails du Service
kubectl describe service nginx -n demo-app
Extrait du résultat
Name: nginx
Namespace: demo-app
Selector: app=nginx
Type: ClusterIP
IP: 10.43.51.181
Port: <unset> 80/TCP
Endpoints: 10.42.0.15:80
ChampSignification
SelectorLabel que le Service cherche (app=nginx)
EndpointsAdresses IP des Pods qui correspondent au sélecteur

Le lien est maintenant clair :

  1. Le Deployment crée des Pods avec le label app=nginx
  2. Le Service sélectionne les Pods ayant app=nginx
  3. Les Endpoints montrent les Pods effectivement ciblés

Cette commande crée un Pod temporaire, exécute wget, affiche le résultat puis supprime le Pod :

Tester l'accès via DNS interne
kubectl run test-curl --image=busybox:1.36 --rm -i --restart=Never -n demo-app -- wget -qO- http://nginx:80
Résultat (extrait)
<!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).

OptionSignification
--rmSupprime le pod après exécution
-iMode interactif (récupère la sortie)
--restart=NeverNe 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 :

Rediriger le port localement
kubectl port-forward svc/nginx 8080:80 -n demo-app
Résultat
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

Ouvrez http://localhost:8080 dans votre navigateur. Vous verrez la page d’accueil nginx.

Appuyez sur Ctrl+C pour arrêter le port-forward.

Actuellement, vous avez 1 pod. Pour en avoir 3 :

Passer à 3 réplicas
kubectl scale deployment nginx --replicas=3 -n demo-app
Résultat
deployment.apps/nginx scaled

Vérifiez que les nouveaux pods démarrent :

Voir les pods
kubectl get pods -n demo-app
Résultat
NAME READY STATUS RESTARTS AGE
nginx-6d8867d6c-57bpf 1/1 Running 0 10s
nginx-6d8867d6c-lptvk 1/1 Running 0 10s
nginx-6d8867d6c-z2j62 1/1 Running 0 2m

3 pods tournent maintenant. Vérifiez que le Service les voit tous :

Voir les endpoints mis à jour
kubectl describe service nginx -n demo-app | grep Endpoints
Résultat
Endpoints: 10.42.0.15:80,10.42.0.16:80,10.42.0.17:80

Le 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.

Détails complets
kubectl describe deployment nginx -n demo-app
Extrait du résultat
Name: nginx
Namespace: demo-app
Labels: app=nginx
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available
StrategyType: RollingUpdate
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.28

Cette commande montre la configuration complète et les événements récents.

Les logs viennent toujours d’un Pod (pas du Deployment). Identifiez d’abord un Pod :

Lister les pods
kubectl get pods -n demo-app

Puis affichez ses logs :

Logs d'un Pod spécifique
kubectl logs nginx-6d8867d6c-z2j62 -n demo-app --tail=10
Résultat
2026/03/21 09:52:26 [notice] 1#1: start worker process 41
...

kubectl permet de lire les logs via le nom du Deployment :

Logs via Deployment (raccourci)
kubectl logs deployment/nginx -n demo-app --tail=10
Résultat
Found 3 pods, using pod/nginx-6d8867d6c-z2j62
2026/03/21 09:52:26 [notice] 1#1: start worker process 41
...

Cette forme est pratique, mais les logs viennent toujours d’un seul Podkubectl en choisit un pour vous.

Pour suivre les logs en temps réel :

Logs en streaming
kubectl logs deployment/nginx -n demo-app -f

Appuyez sur Ctrl+C pour arrêter.

Événements récents
kubectl get events -n demo-app --sort-by='.lastTimestamp'

Cette commande montre ce qui s’est passé : création de pods, scaling, erreurs éventuelles.

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éé :

demo-app.yaml
apiVersion: v1
kind: Namespace
metadata:
name: demo-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: demo-app
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.28
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: demo-app
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP

Pour appliquer ce fichier :

Appliquer la configuration
kubectl apply -f demo-app.yaml

Récapitulons ce qui s’est passé quand vous avez exécuté ces commandes :

  1. Vous avez créé un Deployment → Kubernetes a créé un ReplicaSet
  2. Le ReplicaSet a créé les Pods → Kubernetes a assigné chaque Pod à un nœud
  3. Chaque nœud a téléchargé l’image et démarré le conteneur nginx
  4. Vous avez créé un Service → Kubernetes a enregistré les Pods correspondant au sélecteur app=nginx
  5. Le Service a reçu une IP stable → Les endpoints pointent vers les Pods
  6. Vous avez scalé → Le ReplicaSet a créé 2 Pods supplémentaires
  7. 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.

Pour supprimer tout ce que vous avez créé, supprimez le namespace :

Supprimer le namespace et son contenu
kubectl delete namespace demo-app
Résultat
namespace "demo-app" deleted

Cette commande supprime toutes les ressources du namespace (Deployment, ReplicaSet, Service, Pods).

Voir pourquoi le pod ne démarre pas
kubectl describe deployment nginx -n demo-app
kubectl get events -n demo-app
Cause fréquenteSolution
Image introuvableVérifiez le nom de l’image (nginx:1.28 pas ngix:1.28)
Pas de ressourcesRéduisez le nombre de réplicas ou libérez de la mémoire
ImagePullBackOffProblème de connexion à la registry ou image privée
Voir les logs du pod
kubectl logs <nom-du-pod> -n demo-app --previous

Le flag --previous montre les logs de l’exécution précédente (avant le crash).

Vérifier les endpoints
kubectl describe service nginx -n demo-app

Vé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.

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.

ActionCommande
Créer namespacekubectl create namespace nom
Créer Deploymentkubectl create deployment nom --image=image -n namespace
Exposer avec Servicekubectl expose deployment nom --port=80 -n namespace
Scalerkubectl scale deployment nom --replicas=N -n namespace
Supprimer toutkubectl delete namespace nom
ActionCommande
Voir les podskubectl get pods -n namespace
Voir les labelskubectl get pods -n namespace --show-labels
Voir les endpointskubectl describe service nom -n namespace
Voir les logskubectl logs <pod> -n namespace
Port-forwardkubectl port-forward svc/nom 8080:80 -n namespace
Tester depuis un podkubectl run test --rm -i --restart=Never --image=busybox -- wget -qO- http://service
ActionCommande
Appliquer une configkubectl apply -f fichier.yaml
Voir les différenceskubectl diff -f fichier.yaml
  1. Un Deployment gère vos Pods via un ReplicaSet — il les crée, les surveille et les recrée si nécessaire
  2. Un Service expose vos Pods — il fournit une adresse stable même quand les Pods changent
  3. Le Service cible les Pods par labels, pas le Deployment — vérifiez toujours les Endpoints
  4. Utilisez un namespace pour organiser et nettoyer proprement
  5. Figez les versions d’images (nginx:1.28 pas nginx:latest)
  6. Les commandes impératives sont pour apprendre — en production, passez au déclaratif (YAML)
  7. kubectl describe est votre meilleur ami pour comprendre ce qui se passe
  8. Si vous cassez quelque chose, supprimez le namespace et recommencez

Vous savez maintenant déployer et exposer une application. Continuez avec :

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn