Modèles Kubernetes
Modèles Kubernetes de qualité production pour déployer, gérer et déboguer des charges de travail de manière fiable.
Quand activer
- Écriture de manifests Kubernetes (Deployments, Services, Ingress, Jobs)
- Configuration des ressources requests/limits, sondes liveness/readiness
- Mise en place du RBAC, des namespaces ou des ServiceAccounts
- Gestion de la configuration et des secrets dans K8s
- Débogage de CrashLoopBackOff, OOMKilled, pods en attente ou erreurs de pull d'image
- Configuration de HPA (Horizontal Pod Autoscaler) ou de PodDisruptionBudgets
- Révision de YAML Kubernetes pour la sécurité ou la correction
Quand utiliser
Identique à Quand activer ci-dessus. Cet alias satisfait aux conventions de format de compétence du dépôt. Utilisez cette compétence chaque fois que vous écrivez, révisez ou déboguez du YAML Kubernetes et des charges de travail.
Comment cela fonctionne
Cette compétence fournit des modèles YAML prêts à copier-coller, de qualité production et des commandes de débogage kubectl organisés par tâche :
- Modèle de déploiement — Un
Deploymentde production entièrement configuré avec contexte de sécurité, stratégie de mise à jour progressive, les trois types de sondes, limites de ressources et injection d'environnement à partir de ConfigMap/Secret. - Sondes — Tableau de décision pour startup vs liveness vs readiness, avec le calcul correct de
failureThreshold × periodSeconds. - Services & Ingress — Modèles ClusterIP, LoadBalancer et Ingress TLS avec annotations cert-manager.
- ConfigMaps & Secrets — Conseils sur
envFrom, montage de fichiers et secrets externes. - Gestion des ressources — Règles empiriques pour les requests vs limits par type de charge de travail (API web, JVM, worker, sidecar).
- RBAC — Chaîne ServiceAccount → Role → RoleBinding avec moindre privilège.
- HPA & PDB — Configurations d'autoscaling et de sécurité contre la vidange de nœuds.
- Jobs & CronJobs — Modèles de charges de travail ponctuelles et planifiées avec
restartPolicycorrecte. - Aide-mémoire kubectl — Commandes pour logs, exec, rollback, port-forward, dry-run et diagnostic d'erreurs courantes.
- Anti-patrons & liste de vérification — Ce qu'il NE FAUT PAS faire, et une liste de vérification sécurité/fiabilité/observabilité.
Exemples
Voir les sections ci-dessous pour des exemples complets et exécutables. Références rapides :
| Tâche | Aller à |
|---|---|
| YAML de déploiement production complet | Modèles de charge de travail principaux |
| Configuration des sondes | Sondes |
| Configuration RBAC avec moindre privilège | RBAC |
| Déboguer un CrashLoopBackOff | Aide-mémoire de débogage kubectl |
| Autoscaling | HPA |
Modèles de charge de travail principaux
Déploiement — Modèle de production
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: my-namespace
labels:
app: my-app
version: "1.0.0"
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Autoriser 1 pod supplémentaire pendant la mise à jour
maxUnavailable: 0 # Ne jamais descendre en dessous du nombre souhaité
template:
metadata:
labels:
app: my-app
version: "1.0.0"
spec:
# Contexte de sécurité au niveau du pod
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
# Arrêt progressif
terminationGracePeriodSeconds: 30
containers:
- name: my-app
image: ghcr.io/org/my-app:1.0.0 # Ne jamais utiliser :latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
protocol: TCP
# Les requests ET les limits de ressources sont toutes deux requises
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
# Contexte de sécurité du conteneur
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
# Sondes (voir la section Sondes ci-dessous)
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 0
periodSeconds: 30
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 2
# Environnement à partir de ConfigMap et Secret
envFrom:
- configMapRef:
name: my-app-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-secrets
key: db-password
# Répertoire tmp accessible en écriture quand readOnlyRootFilesystem: true
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Sondes — Liveness, Readiness, Startup
Comprendre quand utiliser chaque sonde est essentiel :
| Sonde | Action en cas d'échec | Utiliser pour |
|---|---|---|
startupProbe | Tue le conteneur si lent à démarrer | Applications à démarrage lent (JVM, Python) |
livenessProbe | Redémarre le conteneur | Détection de blocage/processus bloqué |
readinessProbe | Retire des points de terminaison du Service | Indisponibilité temporaire (reconnexion DB) |
# Modèle correct : startupProbe couvre le démarrage lent,
# puis liveness/readiness prennent le relais
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30 # 30 * 5s = 150s temps max de démarrage
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 30
failureThreshold: 3 # 3 * 30s = 90s avant redémarrage
readinessProbe:
httpGet:
path: /ready # Point de terminaison séparé : vérifie DB, cache, etc.
port: 8080
periodSeconds: 10
failureThreshold: 2
# INVALIDE : initialDelaySeconds sans startupProbe
# Si l'application met 60s à démarrer, définissez plutôt une startupProbe
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60 # MAUVAIS : Attente arbitraire, condition de concurrence
Services et Ingress
Types de Services
# ClusterIP (par défaut) — interne uniquement
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: my-namespace
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
# LoadBalancer — trafic externe (fournisseurs cloud)
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8080
Ingress avec TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- myapp.example.com
secretName: my-app-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
ConfigMaps et Secrets
ConfigMap — Configuration non sensible
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-config
namespace: my-namespace
data:
LOG_LEVEL: "info"
APP_ENV: "production"
MAX_CONNECTIONS: "100"
# Monter comme fichier pour une configuration complexe
app.yaml: |
server:
port: 8080
timeout: 30s
# Monter ConfigMap comme un fichier
volumes:
- name: config
configMap:
name: my-app-config
items:
- key: app.yaml
path: app.yaml
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
Secrets — Données sensibles
# Créer un secret à partir de littéral (CLI, puis stocker dans Vault/SOPS)
kubectl create secret generic my-app-secrets \
--from-literal=db-password='s3cr3t' \
--namespace=my-namespace \
--dry-run=client -o yaml | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: my-app-secrets
namespace: my-namespace
type: Opaque
# Les valeurs sont encodées en base64 (PAS chiffrées — utilisez Sealed Secrets ou ESO pour un vrai chiffrement)
data:
db-password: czNjcjN0 # base64 de 's3cr3t'
Important : Les Secrets Kubernetes bruts sont seulement encodés en base64, pas chiffrés au repos à moins que votre cluster ne soit configuré avec le chiffrement. Utilisez Sealed Secrets ou External Secrets Operator pour la production.
Ressources Requests et Limits
resources:
requests: # L'ordonnanceur utilise cela pour placer le pod
cpu: "100m" # 100 millicores = 0,1 CPU
memory: "128Mi"
limits: # Le conteneur est tué/limité au-dessus de cela
cpu: "500m"
memory: "256Mi"
Règles empiriques :
| Type de charge de travail | CPU Request | Memory Request | Notes |
|---|---|---|---|
| API Web | 100–250m | 128–256Mi | Définir les limits 2 à 4 fois les requests |
| Worker/consommateur | 250–500m | 256–512Mi | Memory limit = request pour la prévisibilité |
| Application JVM | 500m–1 | 512Mi–2Gi | Laisser de la marge au-dessus de -Xmx pour la surcharge JVM |
| Sidecar | 10–50m | 32–64Mi | Garder minimal |
# INVALIDE : Pas de requests ni de limits — ordonnancement imprévisible, évictions OOM
containers:
- name: app
image: myapp:latest
# Ressources manquantes : {} — c'est dangereux en production
# INVALIDE : Limits sans requests — les requests sont par défaut égales aux limits, réservation excessive de capacité
resources:
limits:
cpu: "2"
memory: "1Gi"
# requests manquantes — prendra par défaut les valeurs des limits
RBAC — Rôles et ServiceAccounts
Principe du moindre privilège
Deux modèles selon que l'application appelle ou non l'API Kubernetes :
Modèle A — L'application N'A PAS BESOIN de l'API Kubernetes (la plupart des applications)
Désactiver le montage automatique du jeton sur le ServiceAccount. Le Role/RoleBinding ne sont pas nécessaires.
# ServiceAccount avec jeton désactivé — valeur par défaut la plus sûre
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: false # Aucun jeton API K8s injecté dans les pods
# Référence dans le Deployment — pas de jeton, pas d'accès à l'API
spec:
template:
spec:
serviceAccountName: my-app-sa
automountServiceAccountToken: false # Double sécurité : également défini au niveau du pod
Modèle B — L'application A BESOIN de l'API Kubernetes (operateurs, contrôleurs, observateurs de configuration)
Activer le jeton et accorder uniquement les permissions réellement nécessaires.
# 1. ServiceAccount — activer le jeton pour ce SA
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
automountServiceAccountToken: true # Jeton requis : l'application appelle l'API K8s
# 2. Role — accorder uniquement ce dont l'application a besoin (limité au namespace)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-app-role
namespace: my-namespace
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"] # Lecture seule, ressource spécifique
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["my-app-secrets"] # Limiter au secret spécifique par nom
verbs: ["get"]
# 3. Lier le rôle au ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-rolebinding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: my-namespace
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: my-app-role
# 4. Référencer le SA dans le Deployment
spec:
template:
spec:
serviceAccountName: my-app-sa
# automountServiceAccountToken est par défaut true depuis le SA — le jeton est injecté
Horizontal Pod Autoscaler (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: my-namespace
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2 # Toujours au moins 2 pour la haute disponibilité
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Mise à l'échelle quand la moyenne CPU > 70%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
HPA nécessite que
resources.requestssoit défini sur tous les conteneurs — il calcule l'utilisation commecurrent / request.
PodDisruptionBudget (PDB)
Empêcher trop de pods de tomber pendant les vidanges de nœuds ou les mises à jour progressives :
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
namespace: my-namespace
spec:
minAvailable: 2 # OU utiliser maxUnavailable: 1
selector:
matchLabels:
app: my-app
Namespaces et multi-location
# Créer un namespace avec des quotas de ressources
kubectl create namespace my-namespace
# Appliquer ResourceQuota pour limiter la consommation du namespace
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: my-namespace-quota
namespace: my-namespace
spec:
hard:
requests.cpu: "4"
requests.memory: 4Gi
limits.cpu: "8"
limits.memory: 8Gi
pods: "20"
EOF
Jobs et CronJobs
# Job ponctuel (migration DB, traitement de données)
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: my-namespace
spec:
backoffLimit: 3 # Réessayer jusqu'à 3 fois en cas d'échec
ttlSecondsAfterFinished: 3600 # Suppression automatique après 1h
template:
spec:
restartPolicy: OnFailure # Jamais pour les Jobs (pas Always)
containers:
- name: migrate
image: ghcr.io/org/my-app:1.0.0
command: ["python", "manage.py", "migrate"]
resources:
…
[truncated for translation]
Aide-mémoire de débogage kubectl
# Logs du dernier pod d'un Deployment
kubectl logs deployment/my-app -n my-namespace
# Logs d'un pod spécifique
kubectl logs my-app-6f4b8c9d7-abcde -n my-namespace
# Flux de logs (tail -f)
kubectl logs -f my-app-6f4b8c9d7-abcde -n my-namespace
# Shell interactif dans le conteneur
kubectl exec -it my-app-6f4b8c9d7-abcde -n my-namespace -- /bin/sh
# Annuler la dernière mise à jour (rollback)
kubectl rollout undo deployment/my-app -n my-namespace
# Voir l'historique des mises à jour
kubectl rollout history deployment/my-app -n my-namespace
# Forwarder un port local vers un pod
kubectl port-forward pod/my-app-6f4b8c9d7-abcde 8080:8080 -n my-namespace
# Générer YAML sans appliquer (dry-run)
kubectl create deployment test --image=nginx --dry-run=client -o yaml
# Décrire un pod en panne
kubectl describe pod my-app-6f4b8c9d7-abcde -n my-namespace
# Voir les événements du namespace
kubectl get events -n my-namespace --sort-by='.lastTimestamp'
# Vérifier les limites de ressources (utilisez kubectl top)
kubectl top pod my-app-6f4b8c9d7-abcde -n my-namespace
Diagnostic rapide des erreurs
| Symptôme | Cause probable | Commande de diagnostic |
|---|---|---|
CrashLoopBackOff | Échec de la sonde ou commande défaillante | kubectl logs <pod> + kubectl describe pod <pod> |
OOMKilled | Limite mémoire trop basse | kubectl describe pod <pod> → Last State: OOMKilled |
Pending | Ressources insuffisantes | kubectl describe pod <pod> → Events: Failed to schedule |
ImagePullBackOff | Nom d'image ou secret de registre invalide | kubectl describe pod <pod> → Events: Failed to pull image |
CreateContainerConfigError | Secret ou ConfigMap manquant | kubectl describe pod <pod> → Events: Error: secret "..." not found |
Anti-patrons Kubernetes
Ce qu'il NE FAUT PAS faire :
- Utiliser
:latest— Seulement des tags d'image immuables (sha256:ou version sémantique). - Ometttre
resources.requests— L'ordonnanceur ne peut pas garantir la capacité, ce qui conduit à une éviction en cas de surcharge. - Ometttre
resources.limits— L'application peut consommer toute la mémoire du nœud (OOMKill du nœud). - Ne définir qu'une seule sonde — Utiliser
startupProbe+livenessProbe+readinessProbepour séparer le démarrage, la santé et la disponibilité du trafic. - Configurations codées en dur — Utiliser ConfigMaps et Secrets au lieu de littéraux.
- Jeton RBAC monté par défaut — Désactiver
automountServiceAccountTokensauf si nécessaire. - Exécuter en tant que root — Définir
securityContext.runAsNonRoot: true. - Ignorer PodDisruptionBudget — Sans PDB, une vidange de nœud peut supprimer tous les pods.
- Ne pas définir
terminationGracePeriodSeconds— Arrêt brutal, connexions client perdues. - Ne pas surveiller les logs et les métriques — Impossible de détecter les régressions.
Liste de vérification de déploiement en production
Sécurité
-
runAsNonRoot: trueau niveau du pod -
readOnlyRootFilesystem: truesur le conteneur - Exécution en tant qu'utilisateur non root (
runAsUser: 1001) - Toutes les capabilities sont supprimées (
drop: ["ALL"]) - Le montage automatique du jeton SA est désactivé (sauf si nécessaire)
- Les règles RBAC autorisent uniquement ce qui est requis
- Les images proviennent d'un registre de confiance avec des tags immuables
- NetworkPolicy appliquée
- ResourceQuota définie sur le namespace
Fiabilité
- Au moins 2 réplicas
- PodDisruptionBudget avec
minAvailabledéfini - Toutes les sondes configurées (startup, liveness, readiness)
-
terminationGracePeriodSeconds≥ 30s - Stratégie de mise à jour progressive avec
maxUnavailable: 0 - Resources requests AND limits définis
- HPA configuré pour la mise à l'échelle
-
backoffLimitetttlSecondsAfterFinishedsur les Jobs
Observabilité
- Points de terminaison /health et /ready séparés
- Logs structurés (JSON, avec trace ID)
- Métriques Prometheus exposées
- ReadinessProbe distincte de livenessProbe
Notes complémentaires
Familles de pods de Google Cloud
Les familles de pods peuvent être spécifiées pour influencer l'ordonnancement sur Google Kubernetes Engine (GKE) :
metadata:
annotations:
# Demander un type de machine spécifique (ex. E2, N2, C2)
cloud.google.com/gke-node-family: "e2-standard-4"
Voir la documentation pour plus d'options.
Ingress GCE
Pattern Ingress GCE pour Google Cloud Load Balancer :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-namespace
annotations:
kubernetes.io/ingress.class: "gce"
kubernetes.io/ingress.global-static-ip-name: "my-app-ip"
spec:
tls:
- hosts:
- myapp.example.com
secretName: my-app-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
Règle de 3 réplicas
Le pattern de 3 réplicas garantit la haute disponibilité pendant les mises à jour :
- Avec
replicas: 2et une mise à jour progressive, vous pouvez descendre à 1 pod (50% de perte de capacité). - Avec
replicas: 3etmaxSurge: 1/maxUnavailable: 0, vous maintenez toujours au moins 3 pods. - La configuration RBAC en lecture seule pour le serviceAccount
treboul-userpermet de lister les pods, les services, les deployments, les secrets et les configmaps, mais pas de les modifier.
Conventions et ressources
Principes directeurs
- Toujours utiliser des tags d'image immuables (
sha256:ou version sémantique). - Toujours spécifier les requests ET les limits de ressources.
- Configurer startupProbe + livenessProbe + readinessProbe pour séparer le démarrage, la santé et la disponibilité du trafic.
- Utiliser ConfigMaps et Secrets pour la configuration, pas de valeurs codées en dur.
- Appliquer le moindre privilège pour le RBAC — désactiver le montage automatique du jeton SA sauf si nécessaire.
- Documenter la raison d'un pattern (ex. "50ms de latence, DB en cache").
Conventions de dénomination
- Pods :
<app>-<replicaset-hash>-<pod-id>(généré automatiquement) - Services :
<app>(pas de suffixe superflu) - Ingress :
<app>(correspond au nom du service) - ConfigMaps :
<app>-config - Secrets :
<app>-secrets - ServiceAccounts :
<app>-sa - Roles :
<app>-role - RoleBindings :
<app>-rolebinding - HPAs :
<app>-hpa - PDBs :
<app>-pdb
Utilitaires et polices
- Sealed Secrets
- External Secrets Operator
- kubectx / kubens
- k9s
- Polaris (validation de manifests)
- kube-score (vérification de sécurité et de meilleures pratiques)