Kubernetes : Déployer votre première application

Guide pratique pour déployer une application sur Kubernetes. De l'installation de minikube aux Deployments, Services et ConfigMaps, avec des exemples concrets.

Guide Kubernetes pour déployer sa première application

Kubernetes (K8s) est devenu le standard de facto pour l'orchestration de conteneurs. Conçu par Google et maintenant géré par la CNCF, Kubernetes automatise le déploiement, la mise à l'échelle et la gestion des applications conteneurisées. Ce guide accompagne la mise en place d'un cluster local et le déploiement d'une première application.

Prérequis

Une connaissance de base de Docker est recommandée avant d'aborder Kubernetes. Les conteneurs sont les briques fondamentales que Kubernetes orchestre. La lecture préalable du guide Docker facilite la compréhension des concepts présentés ici.

Comprendre l'architecture Kubernetes

Kubernetes repose sur une architecture maître-worker. Le Control Plane (plan de contrôle) prend les décisions globales sur le cluster, tandis que les Nodes (nœuds) exécutent les charges de travail.

text
# Architecture Kubernetes simplifiée

┌─────────────────────────────────────────────────────────────┐
│                      CONTROL PLANE                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │ API Server  │  │ Scheduler   │  │ Controller Manager  │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
│  ┌─────────────────────────────────────────────────────────┐│
│  │                        etcd                             ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
         ┌────────────────────┼────────────────────┐
         ▼                    ▼                    ▼
┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│     NODE 1      │  │     NODE 2      │  │     NODE 3      │
│  ┌───────────┐  │  │  ┌───────────┐  │  │  ┌───────────┐  │
│  │  kubelet  │  │  │  │  kubelet  │  │  │  │  kubelet  │  │
│  ├───────────┤  │  │  ├───────────┤  │  │  ├───────────┤  │
│  │ kube-proxy│  │  │  │ kube-proxy│  │  │  │ kube-proxy│  │
│  ├───────────┤  │  │  ├───────────┤  │  │  ├───────────┤  │
│  │   Pods    │  │  │  │   Pods    │  │  │  │   Pods    │  │
│  └───────────┘  │  │  └───────────┘  │  │  └───────────┘  │
└─────────────────┘  └─────────────────┘  └─────────────────┘

L'API Server est le point d'entrée pour toutes les commandes. etcd stocke l'état du cluster. Le Scheduler assigne les Pods aux Nodes. Les Controllers maintiennent l'état désiré du système.

Installation de l'environnement local

Pour expérimenter Kubernetes localement, plusieurs options existent : minikube, kind, k3d ou Docker Desktop. Minikube reste la solution la plus répandue pour l'apprentissage.

bash
# terminal
# Installation de kubectl (client Kubernetes)
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# Vérification de l'installation
kubectl version --client
# Client Version: v1.31.0

# Installation de minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# Démarrage du cluster local
minikube start --driver=docker --cpus=2 --memory=4096

# Vérification du statut
minikube status
# minikube: Running
# cluster: Running
# kubectl: Configured

Minikube crée un cluster Kubernetes single-node dans une machine virtuelle ou un conteneur Docker. Les ressources allouées (CPU, mémoire) peuvent être ajustées selon les besoins.

bash
# terminal
# Accès au dashboard Kubernetes (interface web)
minikube dashboard

# Vérification des nodes du cluster
kubectl get nodes
# NAME       STATUS   ROLES           AGE   VERSION
# minikube   Ready    control-plane   5m    v1.31.0

# Informations détaillées sur le cluster
kubectl cluster-info
Alternatives à minikube

Kind (Kubernetes in Docker) démarre plus rapidement et convient mieux aux tests CI/CD. K3d utilise k3s, une distribution légère de Kubernetes. Docker Desktop intègre Kubernetes directement mais consomme plus de ressources.

Les Pods : unité de base

Un Pod est la plus petite unité déployable dans Kubernetes. Un Pod encapsule un ou plusieurs conteneurs qui partagent le même réseau et le même stockage.

yaml
# pod-simple.yaml
apiVersion: v1
kind: Pod
metadata:
  # Nom unique du Pod dans le namespace
  name: nginx-pod
  # Labels pour l'organisation et la sélection
  labels:
    app: nginx
    environment: development
spec:
  containers:
    # Définition du conteneur principal
    - name: nginx
      # Image Docker à utiliser
      image: nginx:1.25-alpine
      # Ports exposés par le conteneur
      ports:
        - containerPort: 80
      # Ressources allouées au conteneur
      resources:
        requests:
          memory: "64Mi"
          cpu: "100m"
        limits:
          memory: "128Mi"
          cpu: "200m"

Ce manifest YAML déclare un Pod contenant un seul conteneur nginx. Les labels permettent d'identifier et de sélectionner les Pods. Les resources définissent les garanties minimales (requests) et les limites maximales (limits).

bash
# terminal
# Création du Pod
kubectl apply -f pod-simple.yaml
# pod/nginx-pod created

# Liste des Pods
kubectl get pods
# NAME        READY   STATUS    RESTARTS   AGE
# nginx-pod   1/1     Running   0          30s

# Détails complets du Pod
kubectl describe pod nginx-pod

# Logs du conteneur
kubectl logs nginx-pod

# Exécution d'une commande dans le Pod
kubectl exec -it nginx-pod -- /bin/sh

# Suppression du Pod
kubectl delete pod nginx-pod

Les Pods sont éphémères par nature. En cas de crash ou de suppression, Kubernetes ne les recrée pas automatiquement. Les Deployments résolvent cette limitation.

Deployments : gestion déclarative

Un Deployment définit l'état désiré pour un ensemble de Pods identiques. Kubernetes maintient automatiquement cet état en créant, mettant à jour ou supprimant des Pods selon les besoins.

yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  # Nom du Deployment
  name: webapp-deployment
  labels:
    app: webapp
spec:
  # Nombre de réplicas souhaité
  replicas: 3
  # Sélecteur pour identifier les Pods gérés
  selector:
    matchLabels:
      app: webapp
  # Template pour la création des Pods
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "200m"
          # Probe de vivacité : redémarre le conteneur si échec
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          # Probe de disponibilité : retire le Pod du Service si échec
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5

Le Deployment crée un ReplicaSet qui maintient 3 Pods identiques. Les probes vérifient la santé des conteneurs et permettent à Kubernetes de réagir automatiquement aux problèmes.

bash
# terminal
# Création du Deployment
kubectl apply -f deployment.yaml
# deployment.apps/webapp-deployment created

# Vérification du Deployment
kubectl get deployments
# NAME                READY   UP-TO-DATE   AVAILABLE   AGE
# webapp-deployment   3/3     3            3           1m

# Liste des Pods créés par le Deployment
kubectl get pods -l app=webapp
# NAME                                READY   STATUS    RESTARTS   AGE
# webapp-deployment-7d9f8b6c4-abc12   1/1     Running   0          1m
# webapp-deployment-7d9f8b6c4-def34   1/1     Running   0          1m
# webapp-deployment-7d9f8b6c4-ghi56   1/1     Running   0          1m

# Mise à l'échelle manuelle
kubectl scale deployment webapp-deployment --replicas=5

# Historique des déploiements
kubectl rollout history deployment webapp-deployment

La suppression d'un Pod déclenche automatiquement la création d'un nouveau Pod pour maintenir le nombre de réplicas souhaité.

Prêt à réussir tes entretiens DevOps ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Services : exposition réseau

Les Pods ont des adresses IP éphémères. Les Services fournissent une adresse stable pour accéder à un ensemble de Pods, avec load balancing intégré.

yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  # Type de Service : ClusterIP (interne), NodePort, LoadBalancer
  type: ClusterIP
  # Sélecteur pour identifier les Pods cibles
  selector:
    app: webapp
  ports:
    # Port exposé par le Service
    - port: 80
      # Port du conteneur cible
      targetPort: 80
      # Protocole (TCP par défaut)
      protocol: TCP

Ce Service de type ClusterIP est accessible uniquement depuis l'intérieur du cluster. Les requêtes vers webapp-service:80 sont distribuées entre les Pods avec le label app: webapp.

bash
# terminal
# Création du Service
kubectl apply -f service.yaml
# service/webapp-service created

# Liste des Services
kubectl get services
# NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
# webapp-service   ClusterIP   10.96.123.456   <none>        80/TCP    30s

# Test depuis un Pod temporaire
kubectl run curl-test --rm -it --image=curlimages/curl -- curl webapp-service

# Description détaillée du Service
kubectl describe service webapp-service

Pour exposer l'application à l'extérieur du cluster, le type NodePort ou LoadBalancer est nécessaire.

yaml
# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-nodeport
spec:
  type: NodePort
  selector:
    app: webapp
  ports:
    - port: 80
      targetPort: 80
      # Port sur chaque Node (30000-32767)
      nodePort: 30080

Avec minikube, la commande minikube service webapp-nodeport ouvre automatiquement le navigateur vers l'URL correcte.

ConfigMaps : configuration externalisée

Les ConfigMaps séparent la configuration du code. Les valeurs peuvent être injectées comme variables d'environnement ou fichiers montés.

yaml
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: webapp-config
data:
  # Valeurs simples clé-valeur
  APP_ENV: "production"
  LOG_LEVEL: "info"
  MAX_CONNECTIONS: "100"
  # Configuration multilignes (fichier complet)
  nginx.conf: |
    server {
        listen 80;
        server_name localhost;

        location / {
            root /usr/share/nginx/html;
            index index.html;
        }

        location /health {
            return 200 'OK';
            add_header Content-Type text/plain;
        }
    }

Les ConfigMaps stockent des données non sensibles. Pour les secrets (mots de passe, tokens), les Secrets Kubernetes sont plus appropriés.

yaml
# deployment-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-configured
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp-configured
  template:
    metadata:
      labels:
        app: webapp-configured
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          # Injection des variables d'environnement
          envFrom:
            - configMapRef:
                name: webapp-config
          # Ou variables individuelles
          env:
            - name: SPECIFIC_VAR
              valueFrom:
                configMapKeyRef:
                  name: webapp-config
                  key: LOG_LEVEL
          # Montage du fichier de configuration
          volumeMounts:
            - name: nginx-config
              mountPath: /etc/nginx/conf.d/default.conf
              subPath: nginx.conf
      volumes:
        - name: nginx-config
          configMap:
            name: webapp-config

Cette configuration injecte les variables d'environnement et monte le fichier nginx.conf dans le conteneur.

bash
# terminal
# Application des ressources
kubectl apply -f configmap.yaml
kubectl apply -f deployment-with-config.yaml

# Vérification des variables d'environnement
kubectl exec deployment/webapp-configured -- printenv | grep APP_ENV
# APP_ENV=production

# Vérification du fichier monté
kubectl exec deployment/webapp-configured -- cat /etc/nginx/conf.d/default.conf
Mise à jour des ConfigMaps

La modification d'un ConfigMap ne redémarre pas automatiquement les Pods. Pour appliquer les changements, un redémarrage manuel est nécessaire : kubectl rollout restart deployment webapp-configured. Certains outils comme Reloader automatisent ce processus.

Secrets : données sensibles

Les Secrets stockent des informations sensibles comme les mots de passe, tokens ou clés SSH. Bien que encodés en base64, ils ne sont pas chiffrés par défaut au repos.

yaml
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: webapp-secrets
type: Opaque
# Les valeurs doivent être encodées en base64
data:
  # echo -n 'admin' | base64
  username: YWRtaW4=
  # echo -n 'supersecretpassword' | base64
  password: c3VwZXJzZWNyZXRwYXNzd29yZA==
---
# Alternative : stringData accepte les valeurs en clair
apiVersion: v1
kind: Secret
metadata:
  name: webapp-secrets-plain
type: Opaque
stringData:
  username: admin
  password: supersecretpassword

Les Secrets peuvent être injectés de la même manière que les ConfigMaps.

yaml
# deployment-with-secrets.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-secure
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp-secure
  template:
    metadata:
      labels:
        app: webapp-secure
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          env:
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: webapp-secrets
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: webapp-secrets
                  key: password
bash
# terminal
# Création du Secret
kubectl apply -f secret.yaml

# Liste des Secrets (les valeurs ne sont pas affichées)
kubectl get secrets
# NAME              TYPE     DATA   AGE
# webapp-secrets    Opaque   2      10s

# Décodage d'une valeur
kubectl get secret webapp-secrets -o jsonpath='{.data.password}' | base64 -d
# supersecretpassword

Namespaces : isolation logique

Les Namespaces partitionnent un cluster en environnements virtuels isolés. Cette séparation permet de gérer plusieurs équipes ou environnements sur un même cluster.

yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: development
  labels:
    environment: development
---
apiVersion: v1
kind: Namespace
metadata:
  name: staging
  labels:
    environment: staging

Chaque ressource peut être créée dans un namespace spécifique.

bash
# terminal
# Création des namespaces
kubectl apply -f namespace.yaml

# Liste des namespaces
kubectl get namespaces
# NAME          STATUS   AGE
# default       Active   1d
# development   Active   10s
# staging       Active   10s

# Création d'une ressource dans un namespace spécifique
kubectl apply -f deployment.yaml -n development

# Liste des Pods dans un namespace
kubectl get pods -n development

# Changement du namespace par défaut
kubectl config set-context --current --namespace=development

Les ressources dans des namespaces différents sont isolées par défaut. La communication cross-namespace est possible via le DNS interne : service-name.namespace.svc.cluster.local.

Application complète : assemblage des ressources

Voici une application complète combinant tous les concepts présentés.

yaml
# complete-app.yaml
---
# Namespace dédié
apiVersion: v1
kind: Namespace
metadata:
  name: myapp
---
# ConfigMap pour la configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
  namespace: myapp
data:
  APP_NAME: "MyApp"
  LOG_LEVEL: "info"
---
# Secret pour les données sensibles
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
  namespace: myapp
type: Opaque
stringData:
  api-key: "sk-1234567890abcdef"
---
# Deployment avec 3 réplicas
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          envFrom:
            - configMapRef:
                name: myapp-config
          env:
            - name: API_KEY
              valueFrom:
                secretKeyRef:
                  name: myapp-secrets
                  key: api-key
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "200m"
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5
---
# Service pour l'exposition interne
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: myapp
spec:
  type: ClusterIP
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
---
# Service NodePort pour l'accès externe (développement)
apiVersion: v1
kind: Service
metadata:
  name: myapp-nodeport
  namespace: myapp
spec:
  type: NodePort
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30100

Ce fichier unique déploie une application complète avec configuration externalisée, secrets, haute disponibilité et exposition réseau.

bash
# terminal
# Déploiement de l'application complète
kubectl apply -f complete-app.yaml

# Vérification de toutes les ressources
kubectl get all -n myapp
# NAME                         READY   STATUS    RESTARTS   AGE
# pod/myapp-7d9f8b6c4-abc12    1/1     Running   0          30s
# pod/myapp-7d9f8b6c4-def34    1/1     Running   0          30s
# pod/myapp-7d9f8b6c4-ghi56    1/1     Running   0          30s
#
# NAME                    TYPE        CLUSTER-IP      PORT(S)        AGE
# service/myapp-service   ClusterIP   10.96.123.456   80/TCP         30s
# service/myapp-nodeport  NodePort    10.96.123.789   80:30100/TCP   30s
#
# NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/myapp   3/3     3            3           30s

# Accès à l'application avec minikube
minikube service myapp-nodeport -n myapp

Mise à jour et rollback

Kubernetes facilite les mises à jour progressives (rolling updates) et les retours en arrière (rollbacks).

bash
# terminal
# Mise à jour de l'image du Deployment
kubectl set image deployment/myapp myapp=nginx:1.26-alpine -n myapp

# Suivi du déploiement en temps réel
kubectl rollout status deployment/myapp -n myapp
# Waiting for deployment "myapp" rollout to finish: 1 out of 3 new replicas updated
# Waiting for deployment "myapp" rollout to finish: 2 out of 3 new replicas updated
# deployment "myapp" successfully rolled out

# Historique des révisions
kubectl rollout history deployment/myapp -n myapp
# REVISION  CHANGE-CAUSE
# 1         <none>
# 2         <none>

# Rollback vers la révision précédente
kubectl rollout undo deployment/myapp -n myapp

# Rollback vers une révision spécifique
kubectl rollout undo deployment/myapp --to-revision=1 -n myapp

La stratégie de mise à jour par défaut (RollingUpdate) remplace progressivement les anciens Pods par les nouveaux, garantissant une disponibilité continue.

Commandes kubectl essentielles

bash
# terminal
# ========================================
# Informations générales
# ========================================
kubectl cluster-info                    # Infos sur le cluster
kubectl get nodes -o wide               # Nodes avec détails
kubectl api-resources                   # Liste des types de ressources

# ========================================
# Gestion des ressources
# ========================================
kubectl get all                         # Toutes les ressources du namespace
kubectl get pods -A                     # Pods de tous les namespaces
kubectl get pods -o wide                # Pods avec IP et Node
kubectl get pods -w                     # Mode watch (temps réel)

# ========================================
# Inspection et debug
# ========================================
kubectl describe pod <name>             # Détails complets
kubectl logs <pod> -f                   # Logs en streaming
kubectl logs <pod> -c <container>       # Logs d'un conteneur spécifique
kubectl exec -it <pod> -- /bin/sh       # Shell interactif
kubectl port-forward <pod> 8080:80      # Tunnel local vers le Pod

# ========================================
# Édition et suppression
# ========================================
kubectl edit deployment <name>          # Édition en direct (vi)
kubectl delete -f manifest.yaml         # Suppression via fichier
kubectl delete pod <name> --force       # Suppression forcée

Conclusion

Kubernetes transforme la gestion des applications conteneurisées en fournissant un cadre déclaratif, résilient et extensible. Les concepts fondamentaux présentés ici constituent la base pour des déploiements production-ready.

Checklist pour un premier déploiement Kubernetes

  • ✅ Cluster local fonctionnel (minikube, kind ou k3d)
  • ✅ kubectl installé et configuré
  • ✅ Deployment avec replicas et probes de santé
  • ✅ Service pour l'exposition réseau
  • ✅ ConfigMap pour la configuration externalisée
  • ✅ Secret pour les données sensibles
  • ✅ Namespace pour l'isolation
  • ✅ Limites de ressources définies (requests/limits)
  • ✅ Stratégie de mise à jour et rollback maîtrisée

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

La maîtrise de Kubernetes ouvre la porte à des architectures cloud-native évolutives. Les prochaines étapes incluent l'exploration des Ingress Controllers pour le routage HTTP, des PersistentVolumes pour le stockage, et de Helm pour la gestion des packages. Kubernetes devient un atout majeur lors des entretiens DevOps et SRE.

Tags

#kubernetes
#k8s
#container orchestration
#devops
#deployment

Partager

Articles similaires