Dans ce module, nous explorerons les objets fondamentaux de Kubernetes. Ces concepts constituent les briques de base pour comprendre et déployer des applications dans un cluster Kubernetes.
Kubernetes organise tout en objets (ou ressources) qui décrivent l'état souhaité de votre cluster. Ces objets suivent une structure commune :
apiVersion: apps/v1 # Version de l'API
kind: Deployment # Type d'objet
metadata: # Métadonnées
name: mon-app
labels:
app: web
spec: # Spécification (état souhaité)
replicas: 3
status: # État actuel (géré par Kubernetes)
readyReplicas: 3
Un Pod est la plus petite unité de déploiement dans Kubernetes. Il représente :

apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: web
tier: frontend
annotations:
kubernetes.io/created-by: "formation-demo"
spec:
containers:
- name: nginx
image: nginx:1.29.5
ports:
- containerPort: 80
name: http
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
env:
- name: ENV_NAME
value: "production"
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: sidecar-logger
image: busybox:1.36
command: ["sh", "-c", "while true; do echo $(date) >> /var/log/nginx/access.log; sleep 30; done"]
volumeMounts:
- name: shared-data
mountPath: /var/log/nginx
volumes:
- name: shared-data
emptyDir: {}
restartPolicy: Always
terminationGracePeriodSeconds: 30
# 1. Créer un Pod simple
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test-pod
labels:
app: test
spec:
containers:
- name: nginx
image: nginx:1.29.5
ports:
- containerPort: 80
EOF
# 2. Vérifier la création
kubectl get pods
kubectl get pods -o wide # Avec plus de détails
# 3. Examiner le Pod en détail
kubectl describe pod test-pod
# 4. Voir les logs
kubectl logs test-pod
# 5. Exécuter des commandes dans le Pod
kubectl exec test-pod -- nginx -v
kubectl exec -it test-pod -- /bin/bash
# 6. Tester la connectivité
kubectl exec test-pod -- curl localhost
# 7. Nettoyer
kubectl delete pod test-pod
États des Pods :
spec:
containers:
- name: app
image: nginx:1.29.5 # Version spécifique
resources: # Toujours définir les ressources
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
livenessProbe: # Health checks
httpGet:
path: /health
port: 80
readinessProbe: # Readiness checks
httpGet:
path: /ready
port: 80
:latestLes Labels sont des métadonnées clé/valeur pour organiser et sélectionner des objets.
metadata:
labels:
app: frontend # Application
version: v1.2.0 # Version
tier: web # Couche applicative
environment: production # Environnement
team: platform # Équipe responsable
cost-center: "marketing" # Centre de coût
# Sélection par égalité
kubectl get pods -l app=frontend
kubectl get pods -l version=v1.2.0
# Sélection par ensemble
kubectl get pods -l 'environment in (production,staging)'
kubectl get pods -l 'tier notin (database)'
# Sélection multiple (ET logique)
kubectl get pods -l app=frontend,environment=production
# Existence d'un label
kubectl get pods -l version
kubectl get pods -l '!beta' # N'a pas le label beta
# 1. Créer des Pods avec différents labels
kubectl run web-v1 --image=nginx:1.29.5 --labels="app=web,version=v1,env=prod"
kubectl run web-v2 --image=nginx:1.29.5 --labels="app=web,version=v2,env=staging"
kubectl run api-v1 --image=nginx:1.29.5 --labels="app=api,version=v1,env=prod"
# 2. Voir tous les labels
kubectl get pods --show-labels
# 3. Filtrer par labels
kubectl get pods -l app=web
kubectl get pods -l env=prod
kubectl get pods -l 'version in (v1,v2)'
# 4. Ajouter/modifier des labels
kubectl label pod web-v1 team=frontend
kubectl label pod api-v1 team=backend tier=service
# 5. Supprimer un label
kubectl label pod web-v1 team-
# 6. Nettoyer
kubectl delete pods -l app
Un Deployment fournit des mises à jour déclaratives pour les Pods et ReplicaSets. Il gère :
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3 # Nombre de Pods souhaités
strategy: # Stratégie de déploiement
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Max de Pods en plus pendant l'update
maxUnavailable: 1 # Max de Pods indisponibles pendant l'update
selector: # Sélecteur pour identifier les Pods
matchLabels:
app: nginx
template: # Template des Pods
metadata:
labels:
app: nginx
version: "v1.0"
spec:
containers:
- name: nginx
image: nginx:1.29.5
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
# 1. Créer un Deployment
kubectl create deployment nginx-app --image=nginx:1.29.5 --replicas=3
# 2. Voir le Deployment et ses ressources associées
kubectl get deployments
kubectl get replicasets
kubectl get pods -l app=nginx-app
# 3. Mettre à l'échelle (scaling)
kubectl scale deployment nginx-app --replicas=5
kubectl get pods -w # Observer les nouveaux Pods
# 4. Mettre à jour l'image (rolling update)
kubectl set image deployment/nginx-app nginx=nginx:1.29.5
kubectl rollout status deployment/nginx-app
# 5. Voir l'historique
kubectl rollout history deployment/nginx-app
# 6. Rollback à la version précédente
kubectl rollout undo deployment/nginx-app
# 7. Rollback à une version spécifique
kubectl rollout history deployment/nginx-app --revision=2
kubectl rollout undo deployment/nginx-app --to-revision=2
# 8. Pause/Resume des déploiements
kubectl rollout pause deployment/nginx-app
kubectl set image deployment/nginx-app nginx=nginx:1.29.5
kubectl rollout resume deployment/nginx-app
# 9. Examiner la configuration
kubectl describe deployment nginx-app
kubectl get deployment nginx-app -o yaml
# 10. Nettoyer
kubectl delete deployment nginx-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # 25% de Pods en plus maximum
maxUnavailable: 25% # 25% de Pods indisponibles maximum
strategy:
type: Recreate # Arrête tous les Pods puis redémarre avec la nouvelle version
Un ReplicaSet s'assure qu'un nombre spécifique de Pods identiques s'exécute à tout moment. En pratique, vous ne créez pas directement des ReplicaSets - ils sont gérés par les Deployments.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-replicaset
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.29.5
ports:
- containerPort: 80
# 1. Créer un Deployment pour voir les ReplicaSets en action
kubectl create deployment web-app --image=nginx:1.29.5 --replicas=3
# 2. Observer la hiérarchie
kubectl get deployments,replicasets,pods -l app=web-app
# 3. Identifier la relation
kubectl describe replicaset $(kubectl get rs -l app=web-app -o name)
# 4. Supprimer un Pod et observer la récréation
POD_NAME=$(kubectl get pods -l app=web-app -o jsonpath='{.items[0].metadata.name}')
kubectl delete pod $POD_NAME
kubectl get pods -l app=web-app -w
# 5. Comprendre l'ownership
kubectl get pods -l app=web-app -o yaml | grep -A5 ownerReferences
# 6. Nettoyer
kubectl delete deployment web-app
apiVersion: batch/v1
kind: Job
metadata:
name: simple-job
spec:
template:
spec:
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c", "echo 'Tâche terminée' && sleep 10"]
restartPolicy: Never
backoffLimit: 4 # Nombre maximum de tentatives
apiVersion: batch/v1
kind: Job
metadata:
name: parallel-job
spec:
parallelism: 3 # 3 Pods en parallèle
completions: 6 # 6 tâches à terminer au total
template:
spec:
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c", "echo \"Worker $HOSTNAME started\" && sleep 30"]
restartPolicy: Never
# 1. Créer un Job simple
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: simple-job
spec:
template:
spec:
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c", "echo 'Tâche terminée' && sleep 10"]
restartPolicy: Never
backoffLimit: 4 # Nombre maximum de tentatives
EOF
# 2. Suivre l'exécution
kubectl get jobs -w
kubectl get pods -l job-name=simple-job
# 3. Voir les résultats
kubectl logs job/simple-job
# 4. Créer un Job qui échoue pour tester backoffLimit
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: failing-job
spec:
template:
spec:
containers:
- name: fail
image: busybox:1.36
command: ["sh", "-c", "exit 1"]
restartPolicy: Never
backoffLimit: 2
EOF
# 5. Observer les tentatives
kubectl get jobs
kubectl get pods -l job-name=failing-job
# 6. Job parallèle de démonstration
cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: parallel-work
spec:
parallelism: 2
completions: 4
template:
spec:
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c", "echo 'Worker starting'; sleep 20; echo 'Worker done'"]
restartPolicy: Never
EOF
# 7. Observer l'exécution parallèle
kubectl get jobs -w
kubectl get pods -l job-name=parallel-work -w
# 8. Nettoyer
kubectl delete jobs --all
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-job
spec:
schedule: "0 2 * * *" # Tous les jours à 2h du matin
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: busybox:1.36
command: ["sh", "-c", "echo 'Backup started at $(date)'"]
restartPolicy: OnFailure
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
Un DaemonSet garantit qu'une copie d'un Pod s'exécute sur chaque Node (ou un sous-ensemble) du cluster.
Cas d'usage typiques :
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true # Utilise le réseau de l'hôte
hostPID: true # Accès aux processus de l'hôte
containers:
- name: node-exporter
image: prom/node-exporter:latest
ports:
- containerPort: 9100
hostPort: 9100 # Expose sur l'IP du Node
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
tolerations: # Permet l'exécution sur les Nodes master
- effect: NoSchedule
operator: Exists
# 1. Créer un DaemonSet simple
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
labels:
app: log-collector
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: logger
image: busybox:1.36
command: ["sh", "-c", "while true; do echo 'Collecting logs from node $(hostname)'; sleep 60; done"]
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
EOF
# 2. Vérifier qu'un Pod s'exécute sur chaque Node
kubectl get daemonsets
kubectl get pods -l app=log-collector -o wide
# 3. Voir les détails du DaemonSet
kubectl describe daemonset log-collector
# 4. Mettre à jour le DaemonSet
kubectl edit daemonset log-collector
# 5. Observer la mise à jour
kubectl rollout status daemonset/log-collector
# 6. Nettoyer
kubectl delete daemonset log-collector
Les Namespaces fournissent une isolation logique des ressources dans un cluster. Ils permettent de :
# Voir les namespaces existants
kubectl get namespaces
# Namespaces système par défaut :
# - default : namespace par défaut pour les objets utilisateur
# - kube-system : objets créés par Kubernetes
# - kube-public : lisible par tous les utilisateurs
# - kube-node-lease : objets lease des nodes
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: dev
team: platform
annotations:
description: "Namespace pour l'environnement de développement"
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: development
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "10"
services: "5"
# 1. Créer des namespaces pour différents environnements
kubectl create namespace development
kubectl create namespace staging
kubectl create namespace production
# 2. Labelliser les namespaces
kubectl label namespace development environment=dev team=platform
kubectl label namespace staging environment=staging team=platform
kubectl label namespace production environment=prod team=platform
# 3. Voir les namespaces avec labels
kubectl get namespaces --show-labels
# 4. Créer des ressources dans des namespaces spécifiques
kubectl create deployment web-dev --image=nginx:1.29.5 -n development
kubectl create deployment web-staging --image=nginx:1.29.5 -n staging
kubectl create deployment web-prod --image=nginx:1.29.5 -n production
# 5. Lister les ressources par namespace
kubectl get deployments -n development
kubectl get deployments -n staging
kubectl get deployments --all-namespaces
# 6. Changer le namespace par défaut pour kubectl
kubectl config set-context --current --namespace=development
kubectl get deployments # Maintenant dans le namespace 'development'
# 7. Revenir au namespace default
kubectl config set-context --current --namespace=default
# 8. Utiliser des alias pour simplifier
alias kdev='kubectl --namespace=development'
alias kstaging='kubectl --namespace=staging'
alias kprod='kubectl --namespace=production'
# Test des alias
kdev get deployments
kstaging get deployments
# 9. Appliquer des quotas de ressources
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: development
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
limits.cpu: "4"
limits.memory: 8Gi
pods: "10"
EOF
# 10. Vérifier les quotas
kubectl describe quota -n development
# 11. Créer un déploiement avec des ressources spécifiées (obligatoire avec ResourceQuota)
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-with-resources
namespace: development
spec:
replicas: 2
selector:
matchLabels:
app: web-with-resources
template:
metadata:
labels:
app: web-with-resources
spec:
containers:
- name: nginx
image: nginx:1.29.5
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
EOF
# 12. Vérifier que le déploiement fonctionne
kubectl get deployments -n development
# 13. Vérifier les quotas
kubectl describe quota -n development
# ou
kubectl get resourcequotas -n development
# 14. Tenter de créer un déploiement sans ressources (va échouer)
kubectl create deployment web-no-resources --image=nginx:1.29.5 -n development
# Pas d'erreur, mais le déploiement ne sera pas créé car il n'y a pas de ressources spécifiées
# 15. Tenter de créer un pod sans ressources (va échouer)
kubectl run nginx --image=nginx:1.29.5
# Error from server (Forbidden): pods "nginx" is forbidden: failed quota: dev-quota: must specify limits.cpu for: nginx; limits.memory for: nginx; requests.cpu for: nginx; requests.memory for: nginx
# 16. Nettoyer
kubectl delete namespaces development staging production
Les LimitRanges définissent des contraintes par défaut, minimales et maximales pour les ressources individuelles (Pods, Containers, PVC) dans un namespace.
| ResourceQuota | LimitRange |
|---|---|
| Limite agrégée du namespace | Limite par objet individuel |
| Ex: Max 4 CPU total | Ex: Chaque container max 2 CPU |
| Vérifié à la création de l'objet | Appliqué/modifié à la création |
limits (si non spécifiées)requests (si non spécifiées)limit et request (évite l'overcommit excessif)apiVersion: v1
kind: LimitRange
metadata:
name: resource-constraints
namespace: development
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 250m
memory: 256Mi
max:
cpu: 2
memory: 2Gi
min:
cpu: 100m
memory: 128Mi
maxLimitRequestRatio:
cpu: 4
memory: 2
kubectl apply -f resource-constraints-limitrange.yaml
Pod sans requests/limits → Kubernetes injecte automatiquement les valeurs default et defaultRequest du LimitRange.
# Pod déployé sans resources
spec:
containers:
- name: nginx
image: nginx
# Résultat après application du LimitRange
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
Recommandation : Utiliser les deux ensemble. LimitRange assure que chaque container a des requests/limits appropriées, ResourceQuota limite la consommation totale du namespace.
# Convention de nommage recommandée
metadata:
name: frontend-web-v1-2-0 # app-component-version
labels:
app.kubernetes.io/name: frontend
app.kubernetes.io/component: web
app.kubernetes.io/version: "1.2.0"
app.kubernetes.io/instance: prod-instance
app.kubernetes.io/part-of: ecommerce-platform
app.kubernetes.io/managed-by: helm
# Toujours définir les ressources
resources:
requests: # Ce dont l'application a besoin
memory: "64Mi"
cpu: "100m"
limits: # Maximum autorisé
memory: "128Mi"
cpu: "200m"
# Liveness Probe : redémarre le conteneur si échec
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness Probe : retire du Service si échec
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Création rapide
kubectl run nginx --image=nginx:1.29.5
kubectl create deployment web --image=nginx:1.29.5
kubectl expose deployment web --port=80
# Avantages : Rapide pour les tests
# Inconvénients : Non reproductible, pas de versioning
# Fichiers manifests versionnés
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
# ... configuration complète
kubectl apply -f deployment.yaml
kubectl apply -f . # Tous les fichiers du répertoire
# Avantages : Reproductible, versionnable, GitOps
# Inconvénients : Plus verbeux
# Création et application
kubectl create -f manifest.yaml # Crée (échoue si existe)
kubectl apply -f manifest.yaml # Crée ou met à jour
kubectl replace -f manifest.yaml # Remplace complètement
# Inspection
kubectl get <resource> # Liste
kubectl describe <resource> <name> # Détails
kubectl logs <pod-name> # Logs
kubectl exec -it <pod> -- <command> # Commandes
# Modification
kubectl edit <resource> <name> # Édite avec $EDITOR
kubectl patch <resource> <name> -p '<json-patch>'
kubectl scale deployment <name> --replicas=5
# Suppression
kubectl delete <resource> <name>
kubectl delete -f manifest.yaml
kubectl delete all --all # Tout supprimer (attention !)
Dans le module suivant, nous explorerons les Services et le réseau Kubernetes, pour apprendre comment exposer et faire communiquer vos applications.
TP associé : TP 3 : Concepts de Base
Ce que vous avez appris :
Ce qui vous attend :