Kubernetes pour développeurs : ce qu'il faut vraiment maîtriser
Guide Kubernetes pour développeurs : Pods, Services, Deployments, ConfigMaps. L'essentiel sans le superflu pour déployer vos applications.
Kubernetes est partout. Mais en tant que développeur, avez-vous vraiment besoin de comprendre les CRD, les Operators, et les Network Policies ? Non. Voici ce qui compte vraiment pour votre quotidien.
Pourquoi Kubernetes concerne les développeurs
Kubernetes n'est plus réservé aux ops. Aujourd'hui, les développeurs doivent comprendre où et comment leur code s'exécute. Pas pour devenir DevOps, mais pour :
- Debugger efficacement : comprendre pourquoi votre application ne démarre pas
- Optimiser les ressources : éviter les OOMKilled et les throttling CPU
- Collaborer avec les ops : parler le même langage
- Écrire du code cloud-native : health checks, graceful shutdown, configuration externe
Les 5 concepts essentiels
1. Pod : l'unité de base
Un Pod est le plus petit objet déployable dans Kubernetes. Il contient un ou plusieurs containers qui partagent le même réseau et stockage.
# pod-simple.yaml
apiVersion: v1
kind: Pod
metadata:
name: mon-api
labels:
app: mon-api
spec:
containers:
- name: api
image: mon-registry/mon-api:1.0.0
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"Ce que vous devez retenir :
- Un Pod = une instance de votre application
- Les Pods sont éphémères (ils peuvent être supprimés à tout moment)
- Toujours définir
resourcespour éviter les problèmes de scheduling
2. Deployment : gérer le cycle de vie
Un Deployment gère la création et la mise à jour des Pods. C'est ce que vous utiliserez 90% du temps.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mon-api
spec:
replicas: 3
selector:
matchLabels:
app: mon-api
template:
metadata:
labels:
app: mon-api
spec:
containers:
- name: api
image: mon-registry/mon-api:1.0.0
ports:
- containerPort: 8080
# Health checks obligatoires
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"Pourquoi les health checks sont critiques :
| Probe | Question posée | Conséquence si échec |
|---|---|---|
livenessProbe | "L'app est-elle vivante ?" | Kubernetes redémarre le Pod |
readinessProbe | "L'app peut-elle recevoir du trafic ?" | Kubernetes retire le Pod du load balancer |
Implémentation côté code (Spring Boot) :
@RestController
public class HealthController {
@Autowired
private DataSource dataSource;
@GetMapping("/health/live")
public ResponseEntity liveness() {
// Vérification basique : l'app répond
return ResponseEntity.ok("OK");
}
@GetMapping("/health/ready")
public ResponseEntity readiness() {
// Vérifier les dépendances critiques
try {
dataSource.getConnection().isValid(1);
return ResponseEntity.ok("OK");
} catch (SQLException e) {
return ResponseEntity.status(503).body("Database unavailable");
}
}
}3. Service : exposer votre application
Un Service donne une adresse stable à un groupe de Pods. Sans Service, impossible d'accéder à vos Pods de manière fiable.
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: mon-api
spec:
selector:
app: mon-api # Cible les Pods avec ce label
ports:
- port: 80 # Port exposé par le Service
targetPort: 8080 # Port du container
type: ClusterIP # Accessible uniquement dans le clusterLes types de Service :
| Type | Usage | Exemple |
|---|---|---|
ClusterIP | Communication interne | API appelée par d'autres services |
NodePort | Exposer sur un port du node | Tests, debugging |
LoadBalancer | Exposer via cloud provider | API publique |
DNS automatique : Kubernetes crée automatiquement une entrée DNS pour chaque Service.
# Depuis n'importe quel Pod du même namespace
curl http://mon-api/endpoint
# Depuis un autre namespace
curl http://mon-api.mon-namespace.svc.cluster.local/endpoint4. ConfigMap et Secret : configuration externe
Ne jamais hardcoder la configuration. Kubernetes fournit ConfigMap (données non sensibles) et Secret (données sensibles).
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mon-api-config
data:
DATABASE_HOST: "postgres.database.svc"
LOG_LEVEL: "INFO"
FEATURE_FLAG_NEW_UI: "true"# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mon-api-secrets
type: Opaque
data:
DATABASE_PASSWORD: cGFzc3dvcmQxMjM= # Base64 encoded
API_KEY: c2VjcmV0LWtleQ==Injection dans le Deployment :
spec:
containers:
- name: api
image: mon-registry/mon-api:1.0.0
envFrom:
- configMapRef:
name: mon-api-config
- secretRef:
name: mon-api-secrets
# Ou injection sélective
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: mon-api-secrets
key: DATABASE_PASSWORD5. Namespace : isolation logique
Les Namespaces séparent les ressources. En développement, vous travaillerez probablement dans un namespace dédié.
# Voir les namespaces
kubectl get namespaces
# Travailler dans un namespace spécifique
kubectl -n mon-equipe get pods
# Définir un namespace par défaut
kubectl config set-context --current --namespace=mon-equipeBonnes pratiques :
- Un namespace par environnement (
dev,staging,prod) - Ou un namespace par équipe/projet
- Ne jamais déployer dans
default
Les commandes kubectl indispensables
Voir ce qui se passe
# Lister les pods (avec état)
kubectl get pods -o wide
# Voir les logs
kubectl logs mon-api-7d9f8b6c5-x2k4n
# Suivre les logs en temps réel
kubectl logs -f mon-api-7d9f8b6c5-x2k4n
# Logs de tous les pods d'un deployment
kubectl logs -l app=mon-api --all-containers
# Décrire un pod (événements, état détaillé)
kubectl describe pod mon-api-7d9f8b6c5-x2k4nDebugger un problème
# Pourquoi mon pod ne démarre pas ?
kubectl describe pod mon-api-7d9f8b6c5-x2k4n | grep -A 20 "Events:"
# Exécuter une commande dans le container
kubectl exec -it mon-api-7d9f8b6c5-x2k4n -- /bin/sh
# Tester la connectivité réseau
kubectl exec -it mon-api-7d9f8b6c5-x2k4n -- curl http://autre-service/health
# Port-forward pour tester localement
kubectl port-forward pod/mon-api-7d9f8b6c5-x2k4n 8080:8080Déployer et mettre à jour
# Appliquer une configuration
kubectl apply -f deployment.yaml
# Mettre à jour l'image
kubectl set image deployment/mon-api api=mon-registry/mon-api:1.1.0
# Voir l'historique des déploiements
kubectl rollout history deployment/mon-api
# Rollback si problème
kubectl rollout undo deployment/mon-api
# Scaler manuellement
kubectl scale deployment/mon-api --replicas=5Ce que vous pouvez ignorer (au début)
En tant que développeur, ces concepts peuvent attendre :
| Concept | Pourquoi attendre | Quand l'apprendre |
|---|---|---|
| Operators | Gestion avancée, souvent par les ops | Quand vous gérez des bases de données |
| CRD | Extension de l'API Kubernetes | Quand vous créez des outils internes |
| Network Policies | Sécurité réseau avancée | Quand vous travaillez sur la sécurité |
| RBAC | Gestion des permissions | Quand vous configurez les accès |
| Helm | Packaging d'applications | Quand vous avez plusieurs environnements |
| Service Mesh | Istio, Linkerd | Quand vous avez des centaines de services |
Patterns essentiels pour développeurs
Graceful shutdown
Kubernetes envoie un signal SIGTERM avant de tuer un Pod. Votre application doit terminer proprement.
// Spring Boot : configuration automatique
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}# application.yaml
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30s# Dans le Deployment
spec:
containers:
- name: api
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"] # Attendre que le LB se mette à jour
terminationGracePeriodSeconds: 45Configuration par environnement
Utilisez des ConfigMaps différentes par environnement, même image Docker.
# Structure recommandée
k8s/
├── base/
│ ├── deployment.yaml
│ └── service.yaml
├── dev/
│ └── configmap.yaml
├── staging/
│ └── configmap.yaml
└── prod/
└── configmap.yamlLogs structurés
Kubernetes collecte stdout/stderr. Utilisez des logs JSON pour faciliter l'analyse.
// logback-spring.xml
{"@timestamp":"2026-01-12T10:30:00.000Z","level":"INFO","message":"Request processed","requestId":"abc123","duration":45}Checklist avant déploiement
Avant de déployer votre application sur Kubernetes :
- [ ] Health checks implémentés (
/health/live,/health/ready) - [ ] Graceful shutdown configuré
- [ ] Configuration externalisée (pas de secrets dans le code)
- [ ] Ressources définies (
requestsetlimits) - [ ] Logs en JSON sur stdout
- [ ] Image Docker optimisée (multi-stage build)
- [ ] Variables d'environnement documentées
Debugging : les erreurs courantes
CrashLoopBackOff
L'application crash au démarrage.
# Voir les logs du crash
kubectl logs mon-api-7d9f8b6c5-x2k4n --previous
# Causes fréquentes :
# - Variable d'environnement manquante
# - Base de données inaccessible
# - Port déjà utiliséImagePullBackOff
Kubernetes ne peut pas télécharger l'image.
# Vérifier le nom de l'image
kubectl describe pod mon-api-7d9f8b6c5-x2k4n | grep "Image:"
# Causes fréquentes :
# - Nom d'image incorrect
# - Registry privé sans credentials
# - Tag inexistantOOMKilled
Le container a dépassé sa limite mémoire.
# Voir la raison du restart
kubectl describe pod mon-api-7d9f8b6c5-x2k4n | grep -A 5 "Last State:"
# Solution : augmenter les limits ou optimiser l'application
resources:
limits:
memory: "1Gi" # Augmenter si nécessaireConclusion
Kubernetes peut sembler complexe, mais pour un développeur, l'essentiel tient en 5 concepts : Pod, Deployment, Service, ConfigMap/Secret, Namespace. Maîtrisez ces fondamentaux et les commandes kubectl de base, et vous serez capable de déployer, debugger et collaborer efficacement avec les équipes ops.
Le reste (Operators, Service Mesh, CRD) viendra naturellement quand vous en aurez besoin. Pour l'instant, concentrez-vous sur écrire du code cloud-native : health checks, graceful shutdown, configuration externe, logs structurés.
---
Pour aller plus loin : Kubernetes 1.35 : les nouveautés cloud-native et Docker Desktop 4.50 : Kubernetes local simplifié