☸️ Kubernetes Deep Dive pour Data Engineers
Bienvenue dans ce module avancé où tu vas plonger dans les entrailles de Kubernetes. Tu découvriras comment fonctionne réellement un cluster K8s, comment packager tes déploiements avec Helm, automatiser le déploiement continu avec ArgoCD, et mettre en place un monitoring professionnel avec Prometheus et Grafana — des compétences indispensables pour un Data Engineer Senior !
Prérequis
| Niveau | Compétence |
|---|---|
| ✅ Requis | Avoir suivi les modules 14_docker_for_data_engineers et 15_kubernetes_fundamentals |
| ✅ Requis | Avoir suivi le module 16_k8s_for_data_workloads |
| ✅ Requis | Maîtriser kubectl, Pods, Deployments, Services, ConfigMaps, Secrets |
| ✅ Requis | Connaissances solides en YAML |
| 💡 Recommandé | Un cluster K8s accessible (Minikube, kind, ou cloud) |
🎯 Objectifs du module
À la fin de ce module, tu seras capable de :
- Comprendre l’architecture interne de Kubernetes (etcd, Scheduler, Controllers)
- Sauvegarder et restaurer etcd
- Configurer le scheduling avancé (affinity, taints, tolerations, priority classes)
- Packager et déployer des applications avec Helm
- Mettre en place un workflow GitOps avec ArgoCD
- Déployer et configurer Prometheus et Grafana pour monitorer tes pipelines data
- Créer des dashboards et des alertes personnalisées
Rappel : Ce qu’on a vu vs Ce qu’on va approfondir
| Module | Ce qu’on a couvert | Ce module approfondit |
|---|---|---|
| M15 - Fundamentals | Architecture simplifiée, Pods, Deployments, Services | Architecture interne complète, etcd, Scheduler |
| M16 - Data Workloads | Spark/Airflow sur K8s, HPA, Helm basics | Helm avancé, GitOps, Monitoring pro |
Schéma : Du Fundamentals au Deep Dive
M15 Fundamentals M16 Data Workloads M27 Deep Dive (ce module)
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────────┐
│ • Pods │ │ • Spark on K8s │ │ • etcd internals │
│ • Deployments │ ───▶ │ • Airflow on K8s│ ───▶ │ • Scheduler avancé │
│ • Services │ │ • HPA │ │ • Helm charts custom │
│ • kubectl │ │ • Helm intro │ │ • ArgoCD / GitOps │
└─────────────────┘ └─────────────────┘ │ • Prometheus / Grafana │
└─────────────────────────┘
💡 Ce module est orienté “comprendre et opérer” — tu vas apprendre ce qui se passe sous le capot pour mieux diagnostiquer, optimiser et industrialiser tes déploiements data.
ℹ️ Le savais-tu ?
Google exécute des milliards de containers par semaine sur son système interne Borg, l’ancêtre de Kubernetes.
Le cluster Kubernetes le plus grand documenté publiquement compte plus de 15 000 nodes et gère des centaines de milliers de pods simultanément.
etcd, le cerveau de Kubernetes, utilise l’algorithme de consensus Raft — le même algorithme utilisé par des systèmes critiques comme CockroachDB et Consul.
1. Architecture Interne de Kubernetes
Dans M15, on a vu l’architecture simplifiée. Maintenant, plongeons dans tous les composants du Control Plane.
Vue complète du Control Plane
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONTROL PLANE │
│ │
│ ┌─────────────┐ ┌─────────────────────┐ ┌──────────────────────┐ │
│ │ │ │ │ │ │ │
│ │ etcd │◀──▶│ API Server │◀──▶│ Controller Manager │ │
│ │ (database) │ │ (point d'entrée) │ │ (boucles de contrôle)│ │
│ │ │ │ │ │ │ │
│ └─────────────┘ └──────────┬──────────┘ └──────────────────────┘ │
│ │ │
│ │ ┌──────────────────────┐ │
│ │ │ │ │
│ └─────────────▶│ Scheduler │ │
│ │ (placement pods) │ │
│ │ │ │
│ └──────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Admission Controllers │ │
│ │ (validation, mutation, policies) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ WORKER NODES │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │
│ │ │ kubelet │ │ │ │ kubelet │ │ │ │ kubelet │ │ │
│ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │
│ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │
│ │ │kube-proxy │ │ │ │kube-proxy │ │ │ │kube-proxy │ │ │
│ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
Composants du Control Plane
| Composant | Rôle | Analogie |
|---|---|---|
| etcd | Base de données clé-valeur distribuée, stocke tout l’état du cluster | Le disque dur du cerveau |
| API Server | Point d’entrée unique, valide et persiste les objets | La réception de l’entreprise |
| Controller Manager | Exécute les boucles de contrôle (Deployment, ReplicaSet…) | Les managers qui vérifient que tout tourne |
| Scheduler | Assigne les pods aux nodes | Le RH qui place les employés |
| Admission Controllers | Interceptent les requêtes pour valider/muter | Les vigiles à l’entrée |
Flux d’une requête kubectl
Quand tu fais kubectl apply -f deployment.yaml, voici ce qui se passe :
kubectl apply ───▶ API Server ───▶ Admission Controllers ───▶ etcd (persist)
│
┌───────────────────────────────────────────┘
▼
Controller Manager (voit le nouveau Deployment)
│
▼
Crée un ReplicaSet ───▶ API Server ───▶ etcd
│
▼
ReplicaSet Controller crée des Pods ───▶ etcd
│
▼
Scheduler assigne les Pods aux Nodes ───▶ etcd
│
▼
kubelet (sur chaque node) démarre les containers
2. etcd Deep Dive
etcd est une base de données clé-valeur distribuée, fortement consistante, qui stocke tout l’état de ton cluster Kubernetes.
Pourquoi etcd est critique
| Aspect | Impact |
|---|---|
| Tout est dedans | Pods, Services, Secrets, ConfigMaps, état des Deployments… |
| Single source of truth | Si etcd meurt sans backup = cluster perdu |
| Performance | Latence etcd = latence de tout le cluster |
Algorithme de consensus Raft
etcd utilise Raft pour garantir la consistance entre plusieurs instances :
┌─────────────────────────────────────────────────────────────┐
│ CLUSTER etcd (3 nodes) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ etcd-1 │ │ etcd-2 │ │ etcd-3 │ │
│ │ LEADER │◀─────▶│FOLLOWER │◀─────▶│FOLLOWER │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ │ Toutes les écritures passent par le Leader │
│ │ puis sont répliquées aux Followers │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Quorum = majorité (2/3 nodes OK = OK) │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Règles de dimensionnement etcd
| Nombre de nodes | Tolérance aux pannes | Recommandation |
|---|---|---|
| 1 | 0 (aucune) | Dev/test uniquement |
| 3 | 1 node | Production standard |
| 5 | 2 nodes | Production critique |
| 7 | 3 nodes | Très rare, overhead important |
⚠️ Toujours un nombre impair pour éviter le split-brain !
Commandes etcd essentielles
# Vérifier la santé du cluster etcd
etcdctl endpoint health --cluster
# Lister les membres du cluster
etcdctl member list
# Voir le leader actuel
etcdctl endpoint status --cluster -w table
# Obtenir une clé (exemple: voir les namespaces)
etcdctl get /registry/namespaces --prefix --keys-onlyBackup et Restore etcd
C’est LA compétence critique pour un cluster de production.
# ═══════════════════════════════════════════════════════════
# BACKUP etcd
# ═══════════════════════════════════════════════════════════
# Variables (adapter selon ton cluster)
ETCD_ENDPOINTS="https://127.0.0.1:2379"
ETCD_CACERT="/etc/kubernetes/pki/etcd/ca.crt"
ETCD_CERT="/etc/kubernetes/pki/etcd/server.crt"
ETCD_KEY="/etc/kubernetes/pki/etcd/server.key"
# Créer un snapshot
etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db \
--endpoints=$ETCD_ENDPOINTS \
--cacert=$ETCD_CACERT \
--cert=$ETCD_CERT \
--key=$ETCD_KEY
# Vérifier le snapshot
etcdctl snapshot status /backup/etcd-snapshot-20240115.db -w table# ═══════════════════════════════════════════════════════════
# RESTORE etcd (⚠️ Opération critique !)
# ═══════════════════════════════════════════════════════════
# 1. Arrêter le kubelet et etcd
systemctl stop kubelet
systemctl stop etcd
# 2. Sauvegarder l'ancien data-dir
mv /var/lib/etcd /var/lib/etcd.backup
# 3. Restaurer depuis le snapshot
etcdctl snapshot restore /backup/etcd-snapshot-20240115.db \
--data-dir=/var/lib/etcd \
--name=master-1 \
--initial-cluster=master-1=https://192.168.1.10:2380 \
--initial-advertise-peer-urls=https://192.168.1.10:2380
# 4. Redémarrer les services
systemctl start etcd
systemctl start kubelet
# 5. Vérifier
kubectl get nodes
kubectl get pods -ABonnes pratiques etcd
| Pratique | Pourquoi |
|---|---|
| Backups automatiques (toutes les heures) | Limiter la perte de données |
| Stocker les backups hors du cluster | Si le cluster meurt, les backups survivent |
| Tester les restore régulièrement | Un backup non testé = pas de backup |
| Monitorer les métriques etcd | Latence, espace disque, leader elections |
| SSD obligatoire | etcd est très sensible aux I/O disque |
3. Scheduler Avancé
Le kube-scheduler décide sur quel node placer chaque pod. En niveau avancé, tu dois savoir influencer ces décisions.
Node Selector (basique)
Le plus simple : matcher un label sur le node.
# Labelliser un node
# kubectl label nodes worker-1 disk=ssd
apiVersion: v1
kind: Pod
metadata:
name: spark-driver
spec:
nodeSelector:
disk: ssd # Ce pod ira uniquement sur les nodes avec disk=ssd
containers:
- name: spark
image: apache/spark:3.5.0Node Affinity (avancé)
Plus de contrôle que nodeSelector : règles required vs preferred.
apiVersion: v1
kind: Pod
metadata:
name: spark-executor
spec:
affinity:
nodeAffinity:
# OBLIGATOIRE : le pod ne sera PAS schedulé si non respecté
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: In
values:
- compute
- highmem
# PRÉFÉRÉ : le scheduler essaie, mais schedule quand même si impossible
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80 # Poids de 1 à 100
preference:
matchExpressions:
- key: zone
operator: In
values:
- eu-west-1a
containers:
- name: spark
image: apache/spark:3.5.0Pod Affinity / Anti-Affinity
Placer des pods ensemble ou séparément.
apiVersion: apps/v1
kind: Deployment
metadata:
name: spark-executors
spec:
replicas: 5
selector:
matchLabels:
app: spark-executor
template:
metadata:
labels:
app: spark-executor
spec:
affinity:
# Pod Affinity : placer AVEC les autres spark-executors
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: spark-driver # Proche du driver
topologyKey: kubernetes.io/hostname
# Pod Anti-Affinity : NE PAS placer sur le même node qu'un autre executor
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: spark-executor
topologyKey: kubernetes.io/hostname
containers:
- name: executor
image: apache/spark:3.5.0Taints et Tolerations
Taints = “je repousse certains pods” (sur le node) Tolerations = “je tolère cette taint” (sur le pod)
# Ajouter une taint à un node
kubectl taint nodes gpu-node-1 gpu=true:NoSchedule
# Effets possibles :
# - NoSchedule : nouveaux pods sans toleration rejetés
# - PreferNoSchedule : éviter si possible
# - NoExecute : pods existants sans toleration évincés# Pod qui tolère la taint GPU
apiVersion: v1
kind: Pod
metadata:
name: ml-training
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- name: training
image: pytorch/pytorch:2.0.0-cuda11.7
resources:
limits:
nvidia.com/gpu: 1Priority Classes
Définir des priorités entre pods — les plus prioritaires peuvent préempter les autres.
# Créer une PriorityClass
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: data-pipeline-critical
value: 1000000 # Plus c'est haut, plus c'est prioritaire
globalDefault: false
description: "Pour les pipelines data critiques"
preemptionPolicy: PreemptLowerPriority # Peut évincer des pods moins prioritaires
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: data-pipeline-batch
value: 100000
globalDefault: false
description: "Pour les jobs batch non critiques"
preemptionPolicy: Never # Ne préempte jamais# Utiliser la PriorityClass
apiVersion: batch/v1
kind: Job
metadata:
name: etl-critical
spec:
template:
spec:
priorityClassName: data-pipeline-critical
containers:
- name: etl
image: my-etl:1.0
restartPolicy: OnFailureCas d’usage Data Engineering
| Scénario | Solution |
|---|---|
| Spark executors sur nodes avec SSD | nodeSelector: disk=ssd |
| Répartir Kafka brokers sur différents nodes | Pod Anti-Affinity |
| Réserver des nodes GPU pour le ML | Taints + Tolerations |
| ETL critique doit toujours tourner | PriorityClass élevée |
| Spark driver proche des executors | Pod Affinity |
4. Helm — Le Package Manager Kubernetes
Helm est le gestionnaire de packages pour Kubernetes. Il te permet de packager, versionner et déployer des applications complexes en une seule commande.
Pourquoi Helm ?
| Sans Helm | Avec Helm |
|---|---|
| 10+ fichiers YAML à maintenir | 1 chart versionné |
| Copier/coller pour chaque environnement | Variables par environnement |
| Pas de rollback facile | helm rollback en 1 commande |
| Difficile de partager | Charts publics sur Artifact Hub |
Concepts Helm
| Concept | Description |
|---|---|
| Chart | Package Helm (dossier avec templates + values) |
| Release | Instance déployée d’un chart |
| Repository | Serveur qui héberge des charts |
| Values | Variables de configuration |
Structure d’un Chart
my-data-pipeline/
├── Chart.yaml # Métadonnées du chart
├── values.yaml # Valeurs par défaut
├── values-dev.yaml # Override pour dev
├── values-prod.yaml # Override pour prod
├── templates/ # Templates Kubernetes
│ ├── _helpers.tpl # Fonctions réutilisables
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── cronjob.yaml
│ └── NOTES.txt # Message post-install
└── charts/ # Dépendances (sub-charts)
Créer un Chart pour un Pipeline ETL
# Créer la structure de base
helm create etl-pipeline
cd etl-pipelineChart.yaml
apiVersion: v2
name: etl-pipeline
description: Pipeline ETL pour Data Engineering
type: application
version: 1.0.0 # Version du chart
appVersion: "2.1.0" # Version de l'application
maintainers:
- name: Data Team
email: data@company.com
dependencies:
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabledvalues.yaml
# Configuration globale
replicaCount: 1
image:
repository: my-registry/etl-pipeline
tag: "2.1.0"
pullPolicy: IfNotPresent
# Configuration ETL
etl:
schedule: "0 2 * * *" # Tous les jours à 2h
sourceBucket: "raw-data"
destBucket: "processed-data"
batchSize: 10000
# Configuration base de données
database:
host: "postgres"
port: 5432
name: "analytics"
user: "etl_user"
# Le password vient d'un secret existant
existingSecret: "db-credentials"
secretKey: "password"
# Ressources
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2000m"
memory: "2Gi"
# PostgreSQL subchart
postgresql:
enabled: true
auth:
database: analytics
username: etl_usertemplates/cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: {{ include "etl-pipeline.fullname" . }}
labels:
{{- include "etl-pipeline.labels" . | nindent 4 }}
spec:
schedule: {{ .Values.etl.schedule | quote }}
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
metadata:
labels:
{{- include "etl-pipeline.selectorLabels" . | nindent 12 }}
spec:
restartPolicy: OnFailure
containers:
- name: etl
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: SOURCE_BUCKET
value: {{ .Values.etl.sourceBucket | quote }}
- name: DEST_BUCKET
value: {{ .Values.etl.destBucket | quote }}
- name: BATCH_SIZE
value: {{ .Values.etl.batchSize | quote }}
- name: DB_HOST
value: {{ .Values.database.host | quote }}
- name: DB_PORT
value: {{ .Values.database.port | quote }}
- name: DB_NAME
value: {{ .Values.database.name | quote }}
- name: DB_USER
value: {{ .Values.database.user | quote }}
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.database.existingSecret }}
key: {{ .Values.database.secretKey }}
resources:
{{- toYaml .Values.resources | nindent 14 }}**templates/_helpers.tpl**
{{/*
Nom complet de l'application
*/}}
{{- define "etl-pipeline.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{/*
Labels communs
*/}}
{{- define "etl-pipeline.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "etl-pipeline.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}Commandes Helm essentielles
# ═══════════════════════════════════════════════════════════
# GESTION DES REPOSITORIES
# ═══════════════════════════════════════════════════════════
# Ajouter un repo
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
# Mettre à jour les repos
helm repo update
# Chercher un chart
helm search repo kafka
helm search hub airflow # Cherche sur Artifact Hub
# ═══════════════════════════════════════════════════════════
# INSTALLATION ET DÉPLOIEMENT
# ═══════════════════════════════════════════════════════════
# Installer un chart depuis un repo
helm install my-kafka bitnami/kafka -n data --create-namespace
# Installer avec des values custom
helm install my-etl ./etl-pipeline -f values-prod.yaml -n production
# Dry-run : voir ce qui serait généré sans installer
helm install my-etl ./etl-pipeline --dry-run --debug
# Template : générer les manifests YAML
helm template my-etl ./etl-pipeline -f values-prod.yaml > manifests.yaml
# ═══════════════════════════════════════════════════════════
# MISE À JOUR ET ROLLBACK
# ═══════════════════════════════════════════════════════════
# Mettre à jour une release
helm upgrade my-etl ./etl-pipeline -f values-prod.yaml -n production
# Install ou upgrade (idempotent)
helm upgrade --install my-etl ./etl-pipeline -f values-prod.yaml -n production
# Voir l'historique des releases
helm history my-etl -n production
# Rollback à une version précédente
helm rollback my-etl 2 -n production
# ═══════════════════════════════════════════════════════════
# INSPECTION ET DEBUG
# ═══════════════════════════════════════════════════════════
# Lister les releases
helm list -A
# Voir les values d'une release
helm get values my-etl -n production
# Voir tous les manifests déployés
helm get manifest my-etl -n production
# Voir les notes post-install
helm get notes my-etl -n production
# ═══════════════════════════════════════════════════════════
# SUPPRESSION
# ═══════════════════════════════════════════════════════════
# Désinstaller une release
helm uninstall my-etl -n production
# Garder l'historique (permet rollback après uninstall)
helm uninstall my-etl -n production --keep-historyHelm vs Kustomize
| Aspect | Helm | Kustomize |
|---|---|---|
| Approche | Templating | Patching/Overlay |
| Complexité | Plus riche | Plus simple |
| Dépendances | Sub-charts | Non natif |
| Rollback | Intégré | Via kubectl |
| Cas d’usage | Apps complexes | Customisations simples |
💡 En pratique, Helm est le standard pour les charts communautaires et les applications complexes. Kustomize est souvent utilisé en complément pour des overlays simples.
5. GitOps avec ArgoCD
GitOps est une pratique où Git est la source de vérité pour l’état de ton infrastructure. ArgoCD surveille ton repo Git et synchronise automatiquement ton cluster Kubernetes.
Pourquoi GitOps ?
| Approche Traditionnelle | GitOps |
|---|---|
kubectl apply manuel |
Git push → déploiement auto |
| Qui a déployé quoi ? | Historique Git complet |
| Rollback complexe | git revert |
| État du cluster inconnu | État = ce qui est dans Git |
Schéma GitOps avec ArgoCD
┌─────────────────────────────────────────────────────────────────────────┐
│ WORKFLOW GITOPS │
│ │
│ Développeur │
│ │ │
│ │ 1. git push (manifests/charts) │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Git Repo │ │
│ │ (GitHub/GitLab) │ │
│ └────────┬────────┘ │
│ │ │
│ │ 2. ArgoCD détecte le changement │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────────────────────────┐ │
│ │ ArgoCD │────────▶│ Cluster Kubernetes │ │
│ │ (dans le K8s) │ 3. Sync │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ └─────────────────┘ │ │ Pod │ │ Pod │ │ Pod │ │ │
│ │ │ └─────┘ └─────┘ └─────┘ │ │
│ │ └─────────────────────────────────────┘ │
│ │ 4. Compare état réel vs état Git │
│ │ (et corrige les drifts) │
│ ▼ │
│ ┌─────────────────┐ │
│ │ UI ArgoCD │ Visualisation, alertes, rollback │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Installation d’ArgoCD
# Créer le namespace
kubectl create namespace argocd
# Installer ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Attendre que tous les pods soient prêts
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=argocd-server -n argocd --timeout=300s
# Récupérer le mot de passe admin initial
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Exposer l'UI (pour dev local)
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Accéder à https://localhost:8080
# User: admin, Password: (celui récupéré ci-dessus)Installer le CLI ArgoCD
# Linux
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd
sudo mv argocd /usr/local/bin/
# macOS
brew install argocd
# Se connecter
argocd login localhost:8080 --username admin --password <password> --insecureCréer une Application ArgoCD
Une Application ArgoCD pointe vers un repo Git et un path contenant les manifests.
# argocd-app-etl.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: etl-pipeline
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
# Source : où sont les manifests
source:
repoURL: https://github.com/myorg/data-platform.git
targetRevision: main # Branche à suivre
path: kubernetes/etl-pipeline # Dossier contenant les manifests ou chart Helm
# Si c'est un chart Helm
helm:
valueFiles:
- values-prod.yaml
# Destination : où déployer
destination:
server: https://kubernetes.default.svc
namespace: production
# Politique de synchronisation
syncPolicy:
automated:
prune: true # Supprimer les ressources qui ne sont plus dans Git
selfHeal: true # Corriger les drifts (si quelqu'un modifie manuellement)
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m# Créer l'application
kubectl apply -f argocd-app-etl.yaml
# Ou via CLI
argocd app create etl-pipeline \
--repo https://github.com/myorg/data-platform.git \
--path kubernetes/etl-pipeline \
--dest-server https://kubernetes.default.svc \
--dest-namespace production \
--sync-policy automated \
--auto-prune \
--self-healApplicationSets
Déployer la même application dans plusieurs environnements ou clusters.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: etl-pipeline-envs
namespace: argocd
spec:
generators:
- list:
elements:
- env: dev
namespace: dev
valuesFile: values-dev.yaml
- env: staging
namespace: staging
valuesFile: values-staging.yaml
- env: prod
namespace: production
valuesFile: values-prod.yaml
template:
metadata:
name: 'etl-pipeline-{{env}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/data-platform.git
targetRevision: main
path: kubernetes/etl-pipeline
helm:
valueFiles:
- '{{valuesFile}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: trueCommandes ArgoCD essentielles
# Lister les applications
argocd app list
# Voir le statut détaillé
argocd app get etl-pipeline
# Synchroniser manuellement
argocd app sync etl-pipeline
# Voir l'historique
argocd app history etl-pipeline
# Rollback
argocd app rollback etl-pipeline <revision>
# Voir les différences (ce qui va changer)
argocd app diff etl-pipeline
# Supprimer une application (et ses ressources)
argocd app delete etl-pipeline --cascadeBonnes pratiques GitOps
| Pratique | Pourquoi |
|---|---|
| Un repo dédié pour les manifests K8s | Séparation code applicatif / config infra |
| Branches par environnement ou values files | Promotion claire dev → staging → prod |
| PR obligatoires pour main/prod | Review avant déploiement |
| Secrets chiffrés (Sealed Secrets, SOPS) | Ne jamais commiter de secrets en clair |
| Notifications (Slack, Teams) | Savoir quand un sync échoue |
6. Monitoring avec Prometheus et Grafana
Prometheus collecte et stocke les métriques. Grafana les visualise. Ensemble, ils forment le stack de monitoring standard de Kubernetes.
Architecture du Stack Monitoring
┌────────────────────────────────────────────────────────────────────────────┐
│ STACK MONITORING K8S │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ PROMETHEUS │ │
│ │ │ │
│ │ ┌──────────────┐ ┌───────────────────┐ │ │
│ │ │ Scraper │──── pull metrics ───▶│ Time Series DB │ │ │
│ │ │ (discovery) │ │ (local storage) │ │ │
│ │ └──────────────┘ └─────────┬─────────┘ │ │
│ │ │ │ │
│ │ │ PromQL queries │ │
│ │ ┌──────────────┐ ▼ │ │
│ │ │ AlertManager │◀──── alerting rules ─── ┌───────────┐ │ │
│ │ │ (Slack/PD) │ │ Rules │ │ │
│ │ └──────────────┘ └───────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ PromQL │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ GRAFANA │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Dashboard 1 │ │ Dashboard 2 │ │ Dashboard 3 │ │ │
│ │ │ K8s Cluster │ │ Data Pipelines│ │ Spark │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ SOURCES DE MÉTRIQUES │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ kubelet │ │ node- │ │ kube- │ │ App │ │ │
│ │ │ /metrics │ │ exporter │ │ state │ │ metrics │ │ │
│ │ │ │ │ │ │ metrics │ │ (custom) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────┘
Installation avec kube-prometheus-stack
Le moyen le plus simple d’installer tout le stack :
# Ajouter le repo Helm
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# Créer le namespace
kubectl create namespace monitoring
# Installer le stack complet
helm install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--set grafana.adminPassword=admin123 \
--set prometheus.prometheusSpec.retention=15d \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi
# Vérifier l'installation
kubectl get pods -n monitoring
# Accéder à Grafana
kubectl port-forward svc/prometheus-grafana -n monitoring 3000:80
# http://localhost:3000 (admin / admin123)
# Accéder à Prometheus
kubectl port-forward svc/prometheus-kube-prometheus-prometheus -n monitoring 9090:9090
# http://localhost:9090Prometheus : Concepts Clés
| Concept | Description |
|---|---|
| Metric | Donnée numérique avec timestamp (ex: cpu_usage) |
| Label | Clé-valeur pour filtrer (ex: pod="etl-123") |
| Scrape | Prometheus tire les métriques des targets |
| Target | Endpoint exposant des métriques (/metrics) |
| PromQL | Langage de requête Prometheus |
Types de métriques
| Type | Description | Exemple |
|---|---|---|
| Counter | Valeur croissante uniquement | http_requests_total |
| Gauge | Valeur qui monte et descend | memory_usage_bytes |
| Histogram | Distribution de valeurs | request_duration_seconds |
| Summary | Quantiles pré-calculés | request_latency_seconds |
PromQL : Requêtes Essentielles
# ═══════════════════════════════════════════════════════════
# REQUÊTES DE BASE
# ═══════════════════════════════════════════════════════════
# CPU utilisé par namespace
sum(rate(container_cpu_usage_seconds_total{namespace="production"}[5m])) by (pod)
# Mémoire utilisée par pod
container_memory_usage_bytes{namespace="production", container!=""}
# Pods en état non-Running
kube_pod_status_phase{phase!="Running", phase!="Succeeded"}
# ═══════════════════════════════════════════════════════════
# MÉTRIQUES DATA ENGINEERING
# ═══════════════════════════════════════════════════════════
# Jobs CronJob échoués dans les dernières 24h
kube_job_status_failed{namespace="data-pipeline"} > 0
# Durée moyenne des jobs ETL
avg(kube_job_status_completion_time - kube_job_status_start_time) by (job_name)
# Taux de redémarrage des pods (signe de problème)
rate(kube_pod_container_status_restarts_total{namespace="production"}[1h]) > 0
# Utilisation PVC (espace disque)
(kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) * 100
# ═══════════════════════════════════════════════════════════
# FONCTIONS UTILES
# ═══════════════════════════════════════════════════════════
# rate() : taux de changement par seconde (pour counters)
rate(http_requests_total[5m])
# increase() : augmentation sur une période (pour counters)
increase(etl_rows_processed_total[1h])
# sum() by () : agrégation
sum(rate(cpu_usage[5m])) by (namespace)
# topk() : top N
topk(5, sum(rate(container_cpu_usage_seconds_total[5m])) by (pod))
# histogram_quantile() : percentiles
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
ServiceMonitor : Scraper des Applications Custom
Pour que Prometheus scrape automatiquement ton application :
# 1. Ton application expose /metrics
apiVersion: v1
kind: Service
metadata:
name: etl-pipeline
namespace: production
labels:
app: etl-pipeline
spec:
ports:
- name: metrics
port: 8080
targetPort: 8080
selector:
app: etl-pipeline
---
# 2. ServiceMonitor pour Prometheus
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: etl-pipeline
namespace: monitoring
labels:
release: prometheus # Important : matcher le label du Prometheus
spec:
selector:
matchLabels:
app: etl-pipeline
namespaceSelector:
matchNames:
- production
endpoints:
- port: metrics
interval: 30s
path: /metricsAlerting avec PrometheusRule
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: data-pipeline-alerts
namespace: monitoring
labels:
release: prometheus
spec:
groups:
- name: data-pipeline
rules:
# Alerte : Job ETL échoué
- alert: ETLJobFailed
expr: kube_job_status_failed{namespace="production", job_name=~"etl-.*"} > 0
for: 1m
labels:
severity: critical
team: data
annotations:
summary: "ETL Job {{ $labels.job_name }} a échoué"
description: "Le job {{ $labels.job_name }} dans {{ $labels.namespace }} est en échec depuis plus d'1 minute."
# Alerte : Pod restart trop fréquent
- alert: PodRestartingTooMuch
expr: rate(kube_pod_container_status_restarts_total{namespace="production"}[15m]) > 0.1
for: 5m
labels:
severity: warning
team: data
annotations:
summary: "Pod {{ $labels.pod }} redémarre trop souvent"
description: "Le pod {{ $labels.pod }} a redémarré plus de 3 fois en 15 minutes."
# Alerte : Espace disque PVC > 80%
- alert: PVCAlmostFull
expr: (kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) * 100 > 80
for: 10m
labels:
severity: warning
team: data
annotations:
summary: "PVC {{ $labels.persistentvolumeclaim }} presque plein"
description: "Le PVC {{ $labels.persistentvolumeclaim }} est utilisé à {{ $value }}%."Grafana : Dashboard pour Data Pipelines
Voici les panels essentiels pour un dashboard Data Engineering :
| Panel | PromQL | Type |
|---|---|---|
| Jobs actifs | kube_job_status_active{namespace="production"} |
Stat |
| Jobs échoués (24h) | sum(increase(kube_job_status_failed{namespace="production"}[24h])) |
Stat |
| CPU par pod | sum(rate(container_cpu_usage_seconds_total{namespace="production"}[5m])) by (pod) |
Time series |
| Mémoire par pod | container_memory_usage_bytes{namespace="production"} |
Time series |
| Durée des jobs | kube_job_status_completion_time - kube_job_status_start_time |
Histogram |
| Pods non-Ready | kube_pod_status_ready{condition="false", namespace="production"} |
Table |
💡 Dashboards pré-faits : Import ID
315pour le dashboard “Kubernetes cluster monitoring” et13770pour “Kubernetes All-in-one Cluster Monitoring”.
7. Exercices Pratiques
Exercice 1 : Backup etcd
Objectif : Créer un CronJob qui sauvegarde etcd toutes les heures.
Instructions : 1. Créer un CronJob qui exécute etcdctl snapshot save 2. Stocker le backup dans un PVC 3. Garder les 24 derniers backups (rotation)
💡 Indice
Tu auras besoin : - D’un PVC pour stocker les backups - Des certificats etcd montés dans le pod - D’un script shell pour la rotation
Exercice 2 : Scheduling Spark
Objectif : Configurer le scheduling d’un job Spark avec les contraintes suivantes :
- Le driver doit tourner sur un node avec le label
role=driver - Les executors doivent être répartis sur des nodes différents (anti-affinity)
- Les executors doivent préférer les nodes avec
disk=ssd
Instructions : 1. Écrire le manifest YAML du driver avec nodeSelector 2. Écrire le manifest des executors avec podAntiAffinity et nodeAffinity
Exercice 3 : Chart Helm Kafka
Objectif : Créer un chart Helm pour déployer un cluster Kafka simple.
Le chart doit inclure : - Un StatefulSet Kafka (3 replicas) - Un Service headless - Un ConfigMap pour la config Kafka - Des values pour : replicas, resources, retention.ms
Exercice 4 : GitOps Pipeline
Objectif : Mettre en place un workflow GitOps complet.
Instructions : 1. Créer un repo Git avec la structure : data-platform/ ├── apps/ │ └── etl-pipeline/ │ ├── Chart.yaml │ ├── values.yaml │ ├── values-dev.yaml │ └── values-prod.yaml └── argocd/ └── applications.yaml 2. Créer un ApplicationSet ArgoCD qui déploie en dev et prod 3. Tester le workflow : modifier les values → git push → observer le sync
Exercice 5 : Dashboard Grafana
Objectif : Créer un dashboard Grafana pour monitorer un pipeline ETL.
Panels requis : 1. Nombre de jobs ETL en cours 2. Taux de succès/échec sur 24h 3. Durée moyenne des jobs (gauge) 4. Top 5 des jobs les plus lents 5. Alerte visuelle si un job échoue
Bonus : Exporter le dashboard en JSON et le versionner dans Git.
8. Mini-Projet : Pipeline Data avec GitOps & Monitoring
Objectif
Mettre en place un pipeline ETL complet déployé via GitOps avec monitoring professionnel.
Architecture cible
┌─────────────────────────────────────────────────────────────────────────┐
│ MINI-PROJET │
│ │
│ ┌──────────────┐ │
│ │ Git Repo │ │
│ │ (manifests) │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────────────────────────────┐ │
│ │ ArgoCD │────────▶│ Namespace: data-pipeline │ │
│ └──────────────┘ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ PostgreSQL │ │ CronJob │ │ │
│ │ │ (Helm) │ │ ETL │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ └──────────────────────────────────────┘ │
│ │ │
│ │ métriques │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Namespace: monitoring │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │ │
│ │ │ Prometheus │──▶│ Grafana │ │ ServiceMonitor │ │ │
│ │ └────────────┘ │ (dashboard)│ │ PrometheusRule │ │ │
│ │ └────────────┘ └────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Instructions
Étape 1 : Préparer le repo Git
Structure requise :
k8s-data-platform/
├── README.md
├── apps/
│ ├── etl-pipeline/ # Chart Helm custom
│ │ ├── Chart.yaml
│ │ ├── values.yaml
│ │ └── templates/
│ │ ├── namespace.yaml
│ │ ├── configmap.yaml
│ │ ├── secret.yaml
│ │ └── cronjob.yaml
│ └── monitoring/
│ ├── servicemonitor.yaml
│ └── prometheusrule.yaml
└── argocd/
└── applications.yaml # ApplicationSet
Étape 2 : Créer le Chart ETL
- CronJob qui s’exécute toutes les heures
- Se connecte à PostgreSQL (dependency Helm)
- Expose des métriques sur
/metrics
Étape 3 : Configurer ArgoCD
- Créer l’Application ArgoCD
- Activer le sync automatique
Étape 4 : Monitoring
- ServiceMonitor pour scraper les métriques ETL
- PrometheusRule avec alerte si job échoue
- Dashboard Grafana
Étape 5 : Tester le workflow
- Modifier le schedule dans
values.yaml - Git commit & push
- Observer ArgoCD synchroniser
- Vérifier dans Grafana
✅ Solution du mini-projet
📥 Afficher la solution complète
1. apps/etl-pipeline/Chart.yaml
apiVersion: v2
name: etl-pipeline
description: Pipeline ETL avec monitoring
type: application
version: 1.0.0
appVersion: "1.0.0"
dependencies:
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"2. apps/etl-pipeline/values.yaml
namespace: data-pipeline
etl:
image: python:3.11-slim
schedule: "0 * * * *"
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
database:
host: "postgresql"
port: "5432"
name: "analytics"
user: "etl_user"
postgresql:
enabled: true
auth:
username: etl_user
password: etl_password
database: analytics
primary:
persistence:
size: 5Gi3. apps/etl-pipeline/templates/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.namespace }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}4. apps/etl-pipeline/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: etl-config
namespace: {{ .Values.namespace }}
data:
DB_HOST: {{ .Values.database.host | quote }}
DB_PORT: {{ .Values.database.port | quote }}
DB_NAME: {{ .Values.database.name | quote }}
DB_USER: {{ .Values.database.user | quote }}5. apps/etl-pipeline/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: etl-secret
namespace: {{ .Values.namespace }}
type: Opaque
stringData:
DB_PASSWORD: {{ .Values.postgresql.auth.password | quote }}6. apps/etl-pipeline/templates/cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: etl-job
namespace: {{ .Values.namespace }}
labels:
app: etl-pipeline
spec:
schedule: {{ .Values.etl.schedule | quote }}
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
labels:
app: etl-job
spec:
restartPolicy: OnFailure
containers:
- name: etl
image: {{ .Values.etl.image }}
command: ["python", "-c"]
args:
- |
import os
import time
print("🚀 Starting ETL job...")
print(f"DB_HOST: {os.environ.get('DB_HOST')}")
print(f"DB_NAME: {os.environ.get('DB_NAME')}")
# Simulate ETL work
time.sleep(10)
print("✅ ETL completed successfully!")
envFrom:
- configMapRef:
name: etl-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: etl-secret
key: DB_PASSWORD
resources:
{{- toYaml .Values.etl.resources | nindent 14 }}7. apps/monitoring/servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: etl-pipeline-monitor
namespace: monitoring
labels:
release: prometheus
spec:
selector:
matchLabels:
app: etl-pipeline
namespaceSelector:
matchNames:
- data-pipeline
endpoints:
- port: metrics
interval: 30s8. apps/monitoring/prometheusrule.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: etl-alerts
namespace: monitoring
labels:
release: prometheus
spec:
groups:
- name: etl-pipeline
rules:
- alert: ETLJobFailed
expr: kube_job_status_failed{namespace="data-pipeline", job_name=~"etl-.*"} > 0
for: 1m
labels:
severity: critical
annotations:
summary: "ETL Job failed"
description: "Job {{ $labels.job_name }} has failed."
- alert: ETLJobTooLong
expr: time() - kube_job_status_start_time{namespace="data-pipeline", job_name=~"etl-.*"} > 3600
for: 5m
labels:
severity: warning
annotations:
summary: "ETL Job running too long"
description: "Job {{ $labels.job_name }} is running for more than 1 hour."9. argocd/applications.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: etl-pipeline
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/YOUR_ORG/k8s-data-platform.git
targetRevision: main
path: apps/etl-pipeline
helm:
valueFiles:
- values.yaml
destination:
server: https://kubernetes.default.svc
namespace: data-pipeline
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: etl-monitoring
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/YOUR_ORG/k8s-data-platform.git
targetRevision: main
path: apps/monitoring
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true10. Commandes de déploiement
# 1. S'assurer qu'ArgoCD est installé
kubectl get pods -n argocd
# 2. S'assurer que le monitoring stack est installé
kubectl get pods -n monitoring
# 3. Appliquer les applications ArgoCD
kubectl apply -f argocd/applications.yaml
# 4. Vérifier le sync
argocd app list
argocd app get etl-pipeline
# 5. Tester manuellement le job
kubectl create job --from=cronjob/etl-job test-etl -n data-pipeline
# 6. Voir les logs
kubectl logs -f job/test-etl -n data-pipeline
# 7. Accéder à Grafana
kubectl port-forward svc/prometheus-grafana -n monitoring 3000:80📚 Ressources pour aller plus loin
🌐 Documentation officielle
- Kubernetes Docs - Scheduling — Scheduling avancé
- etcd Docs — Documentation etcd
- Helm Docs — Documentation Helm
- ArgoCD Docs — Documentation ArgoCD
- Prometheus Docs — Documentation Prometheus
- Grafana Docs — Documentation Grafana
🎓 Certifications
- CKA - Certified Kubernetes Administrator — Certification officielle CNCF
- CKAD - Certified Kubernetes Application Developer — Pour les développeurs
🎮 Pratique
- Killercoda — Labs Kubernetes interactifs
- Play with Kubernetes — Cluster K8s gratuit
- Artifact Hub — Catalogue de charts Helm
📖 Livres
- Kubernetes Patterns — Bilgin Ibryam & Roland Huß
- GitOps and Kubernetes — Billy Yuen et al.
- Prometheus: Up & Running — Brian Brazil
🔧 Outils
- k9s — Terminal UI pour Kubernetes
- Lens — IDE Kubernetes
- Helm Dashboard — UI pour Helm
- Argo CD Autopilot — Bootstrap GitOps
➡️ Prochaine étape
Maintenant que tu maîtrises Kubernetes en profondeur, passons à l’orchestration avancée des pipelines data !
👉 Module suivant : 28_advanced_orchestration — Orchestration avancée
Tu vas apprendre : - Airflow sur Kubernetes (KubernetesExecutor) - TaskFlow API - Comparatif Airflow vs Dagster vs Prefect - OpenLineage pour le data lineage
🎉 Félicitations ! Tu as terminé le module Kubernetes Deep Dive pour Data Engineers.
Comment le Scheduler fonctionne