De Docker Compose à Kubernetes : architecture complète, distributions (K8s, K3s, K0s, MicroK8s), objets fondamentaux, networking, Ingress, scaling automatique et déploiement en production.
Kubernetes fonctionne par déclaration d'objets dans des manifestes YAML. Vous décrivez l'état désiré, K8s le réalise et le maintient. Ce chapitre couvre les objets que vous utilisez dans 95% des déploiements.
Les namespaces partitionnent le cluster en environnements isolés. Les ressources d'un namespace ne sont pas visibles des autres par défaut (côté réseau, avec NetworkPolicy).
apiVersion: v1
kind: Namespace
metadata:
name: productionkubectl apply -f namespace.yaml
kubectl get namespaces
# NAME STATUS AGE
# default Active 10m
# kube-system Active 10m
# kube-public Active 10m
# kube-node-lease Active 10m
# production Active 5sNamespaces réservés :
default : où tout atterrit sans namespace explicitekube-system : composants K8s (CoreDNS, kube-proxy, metrics-server)kube-public : accessible sans authentification (données publiques du cluster)Un Pod est un ou plusieurs conteneurs qui partagent le réseau et le stockage. Dans 95% des cas : un Pod = un conteneur.
apiVersion: v1
kind: Pod
metadata:
name: mon-app
namespace: production
labels:
app: mon-app
version: "1.0"
spec:
containers:
- name: app
image: nginx:1.25-alpine
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"Requests vs Limits :
requests : ce que le scheduler réserve sur le nœud pour décider du placementlimits : le maximum que le conteneur peut utiliser (OOMKilled si dépassement mémoire)CPU en m = millicores. 100m = 0.1 vCPU. 1000m = 1 vCPU.
Ne déployez jamais un Pod directement en production. Les Pods sont éphémères et non auto-remplacés. Utilisez un Deployment.
Un Deployment déclare le nombre de réplicas, l'image à utiliser, et la stratégie de mise à jour. Il crée et gère un ReplicaSet, qui lui-même gère les Pods.
apiVersion: apps/v1
kind: Deployment
metadata:
name: mon-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: mon-app
template:
metadata:
labels:
app: mon-app
spec:
containers:
- name: app
image: mon-registry/mon-app:1.2.0
ports:
- containerPort: 3000
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
env:
- name: NODE_ENV
value: production
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # max pods en plus pendant l'update
maxUnavailable: 0 # zéro downtime — tous les pods restent dispolivenessProbe : K8s tue et redémarre le conteneur si elle échoue. À utiliser pour détecter les deadlocks.
readinessProbe : K8s retire le pod du load balancer si elle échoue. Le conteneur tourne mais ne reçoit plus de trafic. À utiliser pour le warm-up au démarrage.
startupProbe : remplace liveness pendant le démarrage pour les apps lentes. Une fois réussie, liveness prend le relais.
startupProbe:
httpGet:
path: /health
port: 3000
failureThreshold: 30 # 30 * 10s = 5 min max pour démarrer
periodSeconds: 10# Déployer
kubectl apply -f deployment.yaml
# Status du rollout
kubectl rollout status deployment/mon-app -n production
# Historique des versions
kubectl rollout history deployment/mon-app -n production
# Mettre à jour l'image
kubectl set image deployment/mon-app app=mon-registry/mon-app:1.3.0 -n production
# Rollback à la version précédente
kubectl rollout undo deployment/mon-app -n production
# Rollback à une version spécifique
kubectl rollout undo deployment/mon-app --to-revision=2 -n production
# Scaler manuellement
kubectl scale deployment mon-app --replicas=5 -n productionLes Pods ont des IPs qui changent à chaque recréation. Un Service fournit une IP et un DNS stables, et distribue le trafic vers les Pods correspondants via un sélecteur de labels.
Accessible uniquement depuis l'intérieur du cluster. Pour la communication inter-services.
apiVersion: v1
kind: Service
metadata:
name: mon-app
namespace: production
spec:
type: ClusterIP
selector:
app: mon-app # cible tous les pods avec ce label
ports:
- port: 80 # port du Service
targetPort: 3000 # port du conteneur
protocol: TCPDNS interne : mon-app.production.svc.cluster.local (ou juste mon-app depuis le même namespace).
Expose le Service sur un port de chaque nœud (30000–32767). Accessible depuis l'extérieur via <node-ip>:<nodePort>.
spec:
type: NodePort
selector:
app: mon-app
ports:
- port: 80
targetPort: 3000
nodePort: 30080 # optionnel, sinon assigné automatiquementUsage : tests et développement. En production, préférer LoadBalancer ou Ingress.
Provisionne un load balancer externe (AWS ALB, GCP LB, etc.) qui route vers le Service.
spec:
type: LoadBalancer
selector:
app: mon-app
ports:
- port: 80
targetPort: 3000Sur bare metal/K3s, ce type nécessite MetalLB ou Kube-VIP pour fonctionner.
Pas de ClusterIP — le DNS retourne directement les IPs des pods. Utilisé par StatefulSets.
spec:
clusterIP: None
selector:
app: mon-dbVous n'interagissez généralement pas directement avec les ReplicaSets — c'est le Deployment qui les gère. Mais comprendre leur rôle aide à diagnostiquer.
kubectl get replicasets -n production
# NAME DESIRED CURRENT READY
# mon-app-7d4b8f9c6 3 3 3 ← version actuelle
# mon-app-6c8b7f4d2 0 0 0 ← ancienne version (gardée pour rollback)Chaque rolling update crée un nouveau ReplicaSet. L'ancien est conservé avec 0 réplica pour permettre le rollback.
Pour les bases de données et les services qui ont besoin d'une identité stable (PostgreSQL, Redis cluster, Elasticsearch).
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: production
spec:
serviceName: postgres # headless service
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secrets
key: password
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 20GiDifférences StatefulSet vs Deployment :
postgres-0, postgres-1, postgres-2postgres-0.postgres.production.svc.cluster.localLes objets fondamentaux sont maîtrisés. Le chapitre suivant couvre ConfigMaps, Secrets, PersistentVolumes et PersistentVolumeClaims — la gestion de la configuration et du stockage.