☸️ 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.

📖 Borg: The Predecessor to Kubernetes


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-only

Backup 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 -A

Bonnes 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.

Comment le Scheduler fonctionne

Pod à scheduler
      │
      ▼
┌─────────────────────────────────────────────────┐
│              PHASE 1 : FILTERING                │
│  Éliminer les nodes qui ne conviennent pas      │
│  • Ressources insuffisantes (CPU, RAM)          │
│  • Taints non tolérées                          │
│  • NodeSelector non matché                      │
│  • Affinity rules non respectées                │
└─────────────────────────────────────────────────┘
      │
      ▼
┌─────────────────────────────────────────────────┐
│              PHASE 2 : SCORING                  │
│  Classer les nodes restants par score           │
│  • Spread (répartir les pods)                   │
│  • Resource balancing                           │
│  • Preferred affinity                           │
└─────────────────────────────────────────────────┘
      │
      ▼
Node avec le meilleur score sélectionné

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.0

Node 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.0

Pod 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.0

Taints 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: 1

Priority 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: OnFailure

Cas 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-pipeline

Chart.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.enabled

values.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_user

templates/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-history

Helm 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> --insecure

Cré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-heal

ApplicationSets

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: true

Commandes 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 --cascade

Bonnes 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:9090

Prometheus : 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: /metrics

Alerting 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 315 pour le dashboard “Kubernetes cluster monitoring” et 13770 pour “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

  1. Modifier le schedule dans values.yaml
  2. Git commit & push
  3. Observer ArgoCD synchroniser
  4. 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: 5Gi

3. 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: 30s

8. 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: true

10. 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

🎓 Certifications

🎮 Pratique

📖 Livres

  • Kubernetes Patterns — Bilgin Ibryam & Roland Huß
  • GitOps and Kubernetes — Billy Yuen et al.
  • Prometheus: Up & Running — Brian Brazil

🔧 Outils


➡️ 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.

Retour au sommet