Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

☸️ Partie 4 : Réseau & Stockage (Deep Dive)

CNI (Calico, Flannel), DNS (CoreDNS), Ingress (Nginx, Traefik), Storage (PV, PVC, StorageClass).

4.1 Moyen

1. Modèle Réseau K8s

Les 3 règles : 1 IP par Pod (flat network). Pods <-> Pods. Pods <-> Services.

Réseau IP-per-Pod
4.2 Avancé

2. CNI (Le "Plugin" Réseau)

Container Network Interface. L'implémentation (Calico, Flannel, Cilium).

CNI Calico Cilium
4.3 Moyen

3. DNS (Service Discovery)

CoreDNS. Résolution service.namespace.svc.cluster.local.

DNS CoreDNS
4.4 Moyen

4. Service (Rappel Réseau)

kube-proxy (iptables/ipvs). (ClusterIP, NodePort, LoadBalancer).

Service kube-proxy
4.5 Avancé

5. Ingress (Rappel Réseau)

Routeur L7 (HTTP/S). Ingress (Règle) vs Ingress Controller (Moteur).

Ingress Nginx Traefik
4.6 Avancé

6. NetworkPolicy (Firewall)

Le "Firewall" L3/L4 des Pods. (Défaut : Allow All). (Nécessite un CNI compatible).

NetworkPolicy Firewall
4.7 Moyen

7. Stockage (PV / PVC)

PV (L'Offre, Admin) vs PVC (La Demande, Dev). Statique vs Dynamique.

PV PVC
4.8 Avancé

8. StorageClass (Provisioning)

Le "Provisioner" (modèle) pour le stockage dynamique. (aws-ebs, gce-pd, ceph).

StorageClass Dynamique
4.9 Avancé

9. Stockage (Access Modes)

RWO (ReadWriteOnce), ROX (ReadOnlyMany), RWX (ReadWriteMany).

RWO RWX
4.1 Modèle Réseau Kubernetes

K8s impose un modèle réseau (implémenté par le CNI, voir 4.2) simple mais puissant :

  1. Chaque Pod a sa propre adresse IP unique : C'est le modèle "IP-per-Pod". Il n'y a pas de "NAT" (translation d'adresse) complexe entre les Pods.
  2. Tous les Pods peuvent communiquer avec tous les autres Pods : (Sans NAT, quel que soit le Nœud sur lequel ils se trouvent).
  3. Tous les Services peuvent communiquer avec tous les Pods.

Le réseau est "flat" (plat). Un Pod sur le Nœud A (10.1.1.5) peut joindre un Pod sur le Nœud B (10.1.2.10) directement.

Ceci est généralement réalisé via un **Overlay Network** (ex: VXLAN, IP-in-IP) géré par le CNI.

4.2 CNI (Container Network Interface)

Le "Modèle Réseau" (4.1) est la spécification. Le CNI (Container Network Interface) est le "plugin" (le "driver") qui l'implémente.

Lorsque vous installez un cluster (ex: kubeadm), une des premières étapes est kubectl apply -f cni.yaml. C'est là que vous choisissez votre CNI.

CNIMéthode (Simplifié)Point Fort
Flannel (CoreOS)Overlay (VXLAN). Simple.Très simple à installer et à débugger. (Défaut K3s).
Calico (Tigera)Routage L3 (BGP) (pas d'overlay par défaut).Performance. Implémente NetworkPolicy (Firewall).
Cilium (Isovalent)eBPF (in-kernel).Moderne, ultra-performant. Implémente NetworkPolicy et Observabilité avancée (Hubble).
(Cloud-specific)(Ex: AWS VPC CNI, GKE CNI)Intégration native (IPs du VPC).
4.3 DNS (Service Discovery)

Comment un Pod "Frontend" trouve-t-il l'IP (ClusterIP) du Service "Backend" ? Par DNS.

K8s exécute son propre serveur DNS interne : CoreDNS (un Deployment/Service dans kube-system).

Le kubelet configure automatiquement chaque Pod (dans son /etc/resolv.conf) pour utiliser ce CoreDNS.

Résolution de Noms

CoreDNS crée des enregistrements A (DNS) pour chaque Service :

  • service-name.namespace-name.svc.cluster.local (Nom complet - FQDN)
  • (Un Pod dans le même namespace peut juste appeler service-name).
Exemple (/etc/resolv.conf d'un Pod)
# (Fichier à l'intérieur d'un Pod dans le namespace 'prod')
nameserver 10.96.0.10 # (IP du Service 'kube-dns' (CoreDNS))

# (Domaines de recherche)
search prod.svc.cluster.local svc.cluster.local cluster.local

# (Quand vous appelez "api-backend" dans votre code...)
# (Le résolveur essaie :)
# 1. api-backend.prod.svc.cluster.local -> (TROUVÉ)
# 2. api-backend.svc.cluster.local
# 3. api-backend.cluster.local
4.4 Service (Rappel Réseau - kube-proxy)

Un Service (voir 3.3) est un **load balancer L4 (TCP/UDP)** interne. Il fournit une **IP virtuelle (ClusterIP)** stable.

Comment ? Grâce à kube-proxy.

kube-proxy est un DaemonSet (voir 3.9) qui tourne sur **chaque Nœud**. Il observe l'API Server. Quand un Service (ou un Pod) est créé/supprimé, kube-proxy met à jour les règles iptables (ou ipvs) sur le Nœud hôte.

Diagramme (Flux kube-proxy)
(Pod A veut joindre "10.96.0.5" (ClusterIP du Service B))
     |
     ▼
(Nœud 1: Règle iptables (créée par kube-proxy))
"Paquet pour 10.96.0.5 ? 
 -> Choisir aléatoirement (Load Balance):
    - 10.1.1.2 (Pod B1)
    - 10.1.2.3 (Pod B2)
 -> Réécrire (DNAT) et envoyer."
     |
     ▼
(Paquet arrive au Pod B1)
4.5 Ingress (Rappel Réseau - L7)

Un Ingress (voir 3.4) est un **routeur L7 (HTTP/S)**. Il gère le trafic externe (Internet) vers les Services (internes).

Attention : Il y a deux parties :

  1. L'Objet Ingress : C'est le YAML. Une simple "Règle" (ex: host: a.com -> service-a).
  2. L'Ingress Controller : C'est le **vrai moteur** (un Pod NGINX, Traefik, HAProxy...). C'est un Deployment que vous devez installer (ex: via Helm) dans votre cluster. Il lit les "Règles" Ingress et configure son routage.
Diagramme (Flux Ingress)
(Internet)
     |
     ▼
[Load Balancer Cloud (Service type: LoadBalancer)]
     |
     ▼
+-----------------------+
| Pod Ingress Controller| (Ex: NGINX)
| (Service: 'nginx')    |
+-----------------------+
     | (Lit l'objet 'Ingress')
     | (Règle: "Host: a.com -> service-a")
     ▼
+-----------------------+
| Service A (ClusterIP) |
+-----------------------+
     |
     ▼
[Pod App A]
4.6 NetworkPolicy (Le "Firewall")

Par défaut, K8s a un réseau "flat" (plat) : **tous les Pods peuvent parler à tous les Pods** (zéro-confiance non-activée).

Une NetworkPolicy (NetPol) est un "Firewall" L3/L4 (règles IP/Port) pour les Pods. (Nécessite un CNI compatible, ex: Calico, Cilium. Flannel ne les supporte pas).

Dès qu'une NetPol cible un Pod (via podSelector), ce Pod devient **"Deny All"** (isolé) et n'accepte que le trafic explicitement autorisé (ingress/egress).

Exemple YAML (Isoler un Backend)

"Le Pod api-backend (dans le namespace prod) ne doit accepter du trafic (ingress) que des Pods app:frontend sur le port 8080."

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-backend-policy
  namespace: prod
spec:
  # 1. Quels Pods sont ciblés (isolés) ?
  podSelector:
    matchLabels:
      app: api-backend
      
  policyTypes:
  - Ingress # (On applique des règles 'Ingress' (entrantes))
  
  # 2. Règles 'Ingress'
  ingress:
  - from:
    # (Autoriser les Pods qui ont ce label)
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    # (Sur ce port)
    - protocol: TCP
      port: 8080
7. Stockage (PV / PVC) (Rappel)

Problème : Les Pods sont éphémères. Si un Pod de base de données (Postgres) plante, ses données sont perdues.

Solution : Le Stockage Persistant. C'est une abstraction pour attacher un "vrai" disque (ex: AWS EBS) à un Pod.

Il y a deux objets (séparation des rôles) :

  • PersistentVolume (PV) : "L'Offre". (L'Admin Infra) "J'ai créé un disque EBS de 100Go (pv-100go) et je le mets à dispo du cluster." (Provisioning Statique).
  • PersistentVolumeClaim (PVC) : "La Demande". (Le Développeur) "J'ai besoin de 10Go de stockage rapide (postgres-pvc) pour mon Pod." (Le PVC "réclame" (claim) un PV disponible).
Diagramme (Provisioning Statique)
+-------------------------+
| Admin (Infra)           |
| (Crée le disque (ex: EBS))|
| (Crée le YAML 'PV')     |
| (PV "disque-rapide-50Go") |
+-------------------------+
      | (1. `kubectl apply -f pv.yaml`)
      ▼
+-------------------------+
| Cluster (Pool de PVs)   | (PV "disque-rapide-50Go" [Available])
+-------------------------+
      | (3. K8s "lie" le PV au PVC)
      ▲
      | (2. `kubectl apply -f pvc.yaml`)
+-------------------------+
| Dev (App)               |
| (Crée le YAML 'PVC')    |
| (PVC "db-claim" 10Go)   |
+-------------------------+
      |
      ▼ (4. Pod utilise le PVC)
+-------------------------+
| Pod (ex: Postgres)      |
+-------------------------+
8. StorageClass (Provisioning Dynamique)

Le "Provisioning Statique" (4.7) est lourd (l'Admin doit pré-créer les disques manuellement).

Le Provisioning Dynamique (via StorageClass) est le standard.

Un StorageClass (SC) est un "template" (modèle) de stockage. (Ex: "fast-ssd", "slow-hdd", "backup-ceph").

Workflow :

  1. L'Admin crée un StorageClass (ex: "aws-ebs-gp3").
  2. Le Dev crée un PVC (Demande) qui **référence** ce StorageClass (storageClassName: "aws-ebs-gp3").
  3. K8s (via le "Provisioner" du SC) appelle l'API AWS, **crée (provisionne) dynamiquement** un nouveau disque EBS, et crée le PV (Offre) correspondant.
  4. K8s "lie" (bind) le PV au PVC.
Exemple YAML (storageclass.yaml)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard-ebs # (Le nom que le PVC utilisera)
  
# (Le "driver" qui sait comment appeler AWS)
provisioner: kubernetes.io/aws-ebs 

parameters:
  type: gp3 # (Type de disque EBS)
  fsType: ext4
  
reclaimPolicy: Retain # (Garde le disque si le PVC est supprimé)
# (ou 'Delete')
9. Stockage (Access Modes)

Les "Access Modes" (dans le PV/PVC) définissent *comment* le disque peut être "monté" (attaché) aux Nœuds.

ModeNom CompletDescriptionCas d'usage / Backends
RWOReadWriteOnceLe volume peut être monté (en lecture/écriture) par **UN SEUL** Nœud à la fois.(Standard) Bases de données (Postgres, MySQL), Caches (Redis). (AWS EBS, GCE PD, Ceph RBD, Longhorn).
ROXReadOnlyManyLe volume peut être monté (en lecture seule) par **PLUSIEURS** Nœuds.(Rare) Partager des assets/config (ex: modèles ML).
RWXReadWriteManyLe volume peut être monté (en lecture/écriture) par **PLUSIEURS** Nœuds simultanément.(Complexe/Coûteux) CMS (WordPress), stockage partagé. (Nécessite un VRAI système de fichiers réseau : NFS, CephFS, GlusterFS).

Piège classique : Vous ne pouvez pas faire de RWX (ReadWriteMany) avec un StorageClass AWS EBS (Disque bloc). Vous devez utiliser EFS (NFS).