KUBERNETES
Avancé

Kubernetes Networking : Guide Complet CNI, Services et Ingress

Maîtrisez le networking Kubernetes : modèle réseau, plugins CNI (Calico, Cilium), Services, Ingress Controllers, Network Policies et troubleshooting.

Florian Courouge
25 min de lecture
5,123 mots
0 vues
Kubernetes
Networking
CNI
Calico
Cilium
Ingress
Services
Network Policies

Kubernetes Networking : Guide Complet CNI, Services et Ingress

Le networking est l'un des aspects les plus complexes de Kubernetes. Comprendre comment les Pods communiquent entre eux, avec les Services, et avec le monde extérieur est essentiel pour déployer et opérer des applications en production.

Architecture Réseau Kubernetes

Le Modèle Réseau K8s

Kubernetes impose un modèle réseau "flat" avec ces règles fondamentales :

┌─────────────────────────────────────────────────────────────────────────────┐
│                    MODÈLE RÉSEAU KUBERNETES                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │  RÈGLE 1: Chaque Pod a sa propre adresse IP unique                   │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │  RÈGLE 2: Tous les Pods peuvent communiquer entre eux sans NAT       │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │  RÈGLE 3: Les agents sur un Node peuvent communiquer avec tous Pods  │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │  RÈGLE 4: L'IP vue par le Pod est la même que celle vue par les     │   │
│  │           autres Pods (pas de NAT interne)                           │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Les 4 Problèmes Réseau Résolus par K8s

┌─────────────────────────────────────────────────────────────────────────────┐
│                      COMMUNICATIONS KUBERNETES                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   1. CONTAINER ↔ CONTAINER (même Pod)                                       │
│      └── Via localhost (partage network namespace)                          │
│                                                                              │
│   2. POD ↔ POD (même Node)                                                  │
│      └── Via bridge virtuel (veth pairs)                                    │
│                                                                              │
│   3. POD ↔ POD (Nodes différents)                                           │
│      └── Via overlay network ou routage direct (CNI)                        │
│                                                                              │
│   4. POD ↔ EXTERNE                                                          │
│      └── Via Services (ClusterIP, NodePort, LoadBalancer, Ingress)          │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Container Network Interface (CNI)

Qu'est-ce que CNI ?

CNI est la spécification standard pour configurer le réseau des conteneurs. Kubernetes délègue la configuration réseau aux plugins CNI.

┌─────────────────────────────────────────────────────────────────────────────┐
│                        ARCHITECTURE CNI                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────┐                                                           │
│   │   kubelet   │                                                           │
│   └──────┬──────┘                                                           │
│          │ 1. Crée Pod                                                      │
│          ▼                                                                  │
│   ┌─────────────┐      2. Appelle CNI        ┌─────────────────────┐       │
│   │ Container   │ ───────────────────────────▶│   Plugin CNI        │       │
│   │  Runtime    │                             │   (Calico/Cilium)   │       │
│   └─────────────┘                             └──────────┬──────────┘       │
│                                                          │                  │
│                                               3. Configure│                  │
│                                                  réseau  │                  │
│                                                          ▼                  │
│                                               ┌─────────────────────┐       │
│                                               │  - Crée veth pair   │       │
│                                               │  - Assigne IP       │       │
│                                               │  - Configure routes │       │
│                                               │  - Applique rules   │       │
│                                               └─────────────────────┘       │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Comparaison des Plugins CNI

Plugin Mode Performance Features Complexité
Calico BGP/VXLAN/IPIP Excellente Network Policies, eBPF Moyenne
Cilium eBPF natif Excellente L7 Policies, Observabilité Haute
Flannel VXLAN/host-gw Bonne Basique Faible
Weave Mesh overlay Moyenne Encryption native Faible
Canal Flannel + Calico Bonne Network Policies Moyenne

Installation et Configuration de Calico

# calico-installation.yaml
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  # Configuration du pool d'IPs
  calicoNetwork:
    ipPools:
    - blockSize: 26
      cidr: 10.244.0.0/16
      encapsulation: VXLANCrossSubnet
      natOutgoing: Enabled
      nodeSelector: all()

    # Mode de données
    linuxDataplane: Iptables  # ou BPF pour eBPF

    # MTU automatique
    mtu: 0

    # BGP configuration
    bgp: Enabled

  # Ressources des composants
  typhaDeployment:
    spec:
      template:
        spec:
          containers:
          - name: calico-typha
            resources:
              requests:
                cpu: 200m
                memory: 256Mi
              limits:
                cpu: 1000m
                memory: 512Mi

---
# Configuration BGP pour bare-metal
apiVersion: crd.projectcalico.org/v1
kind: BGPConfiguration
metadata:
  name: default
spec:
  logSeverityScreen: Info
  nodeToNodeMeshEnabled: true
  asNumber: 64512

---
# BGP Peer pour router externe
apiVersion: crd.projectcalico.org/v1
kind: BGPPeer
metadata:
  name: rack-tor-switch
spec:
  peerIP: 192.168.1.1
  asNumber: 64513
  nodeSelector: rack == 'rack-1'

Installation et Configuration de Cilium

# Installation via Helm
helm repo add cilium https://helm.cilium.io/
helm repo update

helm install cilium cilium/cilium --version 1.15.0 \
  --namespace kube-system \
  --set kubeProxyReplacement=true \
  --set k8sServiceHost=<API_SERVER_IP> \
  --set k8sServicePort=6443 \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set ipam.mode=kubernetes \
  --set bpf.masquerade=true \
  --set loadBalancer.mode=dsr \
  --set bandwidthManager.enabled=true
# cilium-config.yaml - Configuration avancée
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
  name: production-pool
spec:
  cidrs:
  - cidr: 192.168.100.0/24

---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeeringPolicy
metadata:
  name: bgp-peering
spec:
  nodeSelector:
    matchLabels:
      bgp-policy: production
  virtualRouters:
  - localASN: 64512
    exportPodCIDR: true
    neighbors:
    - peerAddress: 192.168.1.1/32
      peerASN: 64513
      connectRetryTimeSeconds: 30
      holdTimeSeconds: 90
      keepAliveTimeSeconds: 30
      gracefulRestart:
        enabled: true
        restartTimeSeconds: 120

Services Kubernetes

Types de Services

┌─────────────────────────────────────────────────────────────────────────────┐
│                        TYPES DE SERVICES                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │ CLUSTERIP (défaut)                                                   │    │
│  │ ┌─────────┐                                                          │    │
│  │ │ Pod A   │───────▶ 10.96.0.100:80 ───────▶ ┌─────────┐             │    │
│  │ └─────────┘         (Virtual IP)             │ Pod B   │             │    │
│  │                                              │ Pod C   │             │    │
│  │  Accessible uniquement dans le cluster       └─────────┘             │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │ NODEPORT                                                             │    │
│  │ ┌─────────┐                                                          │    │
│  │ │ Client  │───▶ NodeIP:30080 ───▶ ClusterIP ───▶ ┌─────────┐        │    │
│  │ │ Externe │     (30000-32767)                    │ Pods    │        │    │
│  │ └─────────┘                                      └─────────┘        │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │ LOADBALANCER                                                         │    │
│  │ ┌─────────┐      ┌──────────┐                                        │    │
│  │ │ Client  │───▶  │ Cloud LB │───▶ NodePort ───▶ ┌─────────┐         │    │
│  │ │ Externe │      │ (L4)     │                   │ Pods    │         │    │
│  │ └─────────┘      └──────────┘                   └─────────┘         │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │ EXTERNALNAME                                                         │    │
│  │ ┌─────────┐                                                          │    │
│  │ │ Pod     │───▶ my-db.default.svc ───▶ db.external.com              │    │
│  │ └─────────┘     (DNS CNAME)                                          │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Service ClusterIP avec Session Affinity

apiVersion: v1
kind: Service
metadata:
  name: api-service
  namespace: production
  labels:
    app: api
    tier: backend
spec:
  type: ClusterIP
  selector:
    app: api
    tier: backend
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP
  - name: grpc
    port: 9090
    targetPort: 9090
    protocol: TCP

  # Session affinity pour applications stateful
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 3600

  # Traffic policy
  internalTrafficPolicy: Local  # Préfère les pods locaux

Service LoadBalancer avec MetalLB

# Installation MetalLB
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: production-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.100-192.168.1.150
  autoAssign: true

---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: production-l2
  namespace: metallb-system
spec:
  ipAddressPools:
  - production-pool
  interfaces:
  - eth0

---
# Service LoadBalancer
apiVersion: v1
kind: Service
metadata:
  name: frontend
  namespace: production
  annotations:
    metallb.universe.tf/address-pool: production-pool
    metallb.universe.tf/loadBalancerIPs: 192.168.1.100
spec:
  type: LoadBalancer
  loadBalancerIP: 192.168.1.100
  externalTrafficPolicy: Local  # Préserve l'IP client
  ports:
  - name: http
    port: 80
    targetPort: 8080
  - name: https
    port: 443
    targetPort: 8443
  selector:
    app: frontend

Headless Service pour StatefulSets

apiVersion: v1
kind: Service
metadata:
  name: kafka-headless
  namespace: kafka
spec:
  type: ClusterIP
  clusterIP: None  # Headless!
  publishNotReadyAddresses: true
  selector:
    app: kafka
  ports:
  - name: broker
    port: 9092
    targetPort: 9092
  - name: controller
    port: 9093
    targetPort: 9093

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kafka
  namespace: kafka
spec:
  serviceName: kafka-headless  # Lié au headless service
  replicas: 3
  selector:
    matchLabels:
      app: kafka
  template:
    metadata:
      labels:
        app: kafka
    spec:
      containers:
      - name: kafka
        image: confluentinc/cp-kafka:7.5.0
        env:
        - name: KAFKA_ADVERTISED_LISTENERS
          value: "PLAINTEXT://$(POD_NAME).kafka-headless.kafka.svc.cluster.local:9092"
        # DNS: kafka-0.kafka-headless.kafka.svc.cluster.local
        # DNS: kafka-1.kafka-headless.kafka.svc.cluster.local
        # DNS: kafka-2.kafka-headless.kafka.svc.cluster.local

Ingress Controllers

Architecture Ingress

┌─────────────────────────────────────────────────────────────────────────────┐
│                        ARCHITECTURE INGRESS                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   Internet                                                                   │
│      │                                                                       │
│      ▼                                                                       │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                    Load Balancer (L4)                                │   │
│   │                    192.168.1.100:80/443                              │   │
│   └───────────────────────────────┬─────────────────────────────────────┘   │
│                                   │                                          │
│                                   ▼                                          │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                  INGRESS CONTROLLER                                  │   │
│   │              (NGINX, Traefik, HAProxy, etc.)                        │   │
│   │                                                                      │   │
│   │  ┌───────────────────────────────────────────────────────────────┐  │   │
│   │  │  Ingress Rules                                                 │  │   │
│   │  │                                                                │  │   │
│   │  │  api.example.com/* ────────────▶ api-service:80               │  │   │
│   │  │  app.example.com/* ────────────▶ frontend-service:80          │  │   │
│   │  │  example.com/api/* ────────────▶ api-service:80               │  │   │
│   │  │  example.com/*     ────────────▶ frontend-service:80          │  │   │
│   │  └───────────────────────────────────────────────────────────────┘  │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Installation NGINX Ingress Controller

# Via Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --set controller.replicaCount=3 \
  --set controller.metrics.enabled=true \
  --set controller.podAnnotations."prometheus\.io/scrape"=true \
  --set controller.podAnnotations."prometheus\.io/port"=10254
# nginx-ingress-values.yaml - Configuration production
controller:
  replicaCount: 3

  # Ressources
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 2Gi

  # Autoscaling
  autoscaling:
    enabled: true
    minReplicas: 3
    maxReplicas: 10
    targetCPUUtilizationPercentage: 70
    targetMemoryUtilizationPercentage: 80

  # Pod Disruption Budget
  podDisruptionBudget:
    enabled: true
    minAvailable: 2

  # Anti-affinity pour HA
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app.kubernetes.io/name: ingress-nginx
        topologyKey: kubernetes.io/hostname

  # Configuration NGINX
  config:
    use-gzip: "true"
    gzip-level: "6"
    worker-processes: "auto"
    max-worker-connections: "65535"
    use-http2: "true"
    keep-alive: "75"
    keep-alive-requests: "10000"
    upstream-keepalive-connections: "200"
    proxy-body-size: "50m"
    proxy-buffer-size: "16k"
    proxy-buffers: "4 16k"
    ssl-protocols: "TLSv1.2 TLSv1.3"
    ssl-ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"
    enable-real-ip: "true"
    forwarded-for-header: "X-Forwarded-For"

  # Métriques
  metrics:
    enabled: true
    serviceMonitor:
      enabled: true
      namespace: monitoring

Configuration Ingress Avancée

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: production-ingress
  namespace: production
  annotations:
    # TLS
    cert-manager.io/cluster-issuer: letsencrypt-prod

    # Rate limiting
    nginx.ingress.kubernetes.io/limit-rps: "100"
    nginx.ingress.kubernetes.io/limit-connections: "50"
    nginx.ingress.kubernetes.io/limit-rpm: "1000"

    # Timeouts
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"

    # CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"

    # Sécurité
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-XSS-Protection: 1; mode=block";
      more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains";

    # Canary deployment
    # nginx.ingress.kubernetes.io/canary: "true"
    # nginx.ingress.kubernetes.io/canary-weight: "20"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    - app.example.com
    secretName: example-tls
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: api-v1
            port:
              number: 80
      - path: /v2
        pathType: Prefix
        backend:
          service:
            name: api-v2
            port:
              number: 80
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend
            port:
              number: 80

Traefik Ingress Controller

# traefik-values.yaml
deployment:
  replicas: 3

resources:
  requests:
    cpu: 200m
    memory: 256Mi
  limits:
    cpu: 1000m
    memory: 512Mi

# Entrypoints
ports:
  web:
    port: 8000
    exposedPort: 80
    redirectTo: websecure
  websecure:
    port: 8443
    exposedPort: 443
    tls:
      enabled: true

# Dashboard
ingressRoute:
  dashboard:
    enabled: true
    matchRule: Host(`traefik.example.com`)
    entryPoints:
    - websecure

# Logs
logs:
  general:
    level: INFO
  access:
    enabled: true
    format: json

# Metrics
metrics:
  prometheus:
    enabled: true
    entryPoint: metrics

---
# IngressRoute Traefik CRD
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: api-route
  namespace: production
spec:
  entryPoints:
  - websecure
  routes:
  - match: Host(`api.example.com`) && PathPrefix(`/v1`)
    kind: Rule
    services:
    - name: api-v1
      port: 80
      weight: 100
    middlewares:
    - name: rate-limit
    - name: headers-security
  tls:
    certResolver: letsencrypt

---
# Middleware Rate Limiting
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: rate-limit
  namespace: production
spec:
  rateLimit:
    average: 100
    burst: 200
    period: 1s
    sourceCriterion:
      ipStrategy:
        depth: 1

---
# Middleware Headers Sécurité
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: headers-security
  namespace: production
spec:
  headers:
    frameDeny: true
    contentTypeNosniff: true
    browserXssFilter: true
    stsIncludeSubdomains: true
    stsSeconds: 31536000
    customResponseHeaders:
      X-Robots-Tag: "noindex,nofollow"

Network Policies

Comprendre les Network Policies

┌─────────────────────────────────────────────────────────────────────────────┐
│                       NETWORK POLICIES                                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Sans Network Policy: TOUT est autorisé par défaut                          │
│                                                                              │
│   ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐              │
│   │ Pod A   │◀───▶│ Pod B   │◀───▶│ Pod C   │◀───▶│ Pod D   │              │
│   └─────────┘     └─────────┘     └─────────┘     └─────────┘              │
│                                                                              │
│  Avec Network Policy: Whitelist des flux autorisés                          │
│                                                                              │
│   ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐              │
│   │ Pod A   │────▶│ Pod B   │────▶│ Pod C   │     │ Pod D   │              │
│   └─────────┘     └─────────┘     └─────────┘     └─────────┘              │
│                        │                               ▲                     │
│                        └───────────────────────────────┘                     │
│                                                                              │
│  Policy Types:                                                               │
│  • Ingress: Contrôle le trafic ENTRANT vers les pods sélectionnés           │
│  • Egress: Contrôle le trafic SORTANT des pods sélectionnés                 │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Default Deny All

# Deny all ingress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}  # Sélectionne tous les pods
  policyTypes:
  - Ingress

---
# Deny all egress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress

---
# Allow DNS egress (nécessaire!)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

Network Policies Complètes pour Microservices

# Frontend peut recevoir du trafic Ingress et appeler l'API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # Depuis l'Ingress Controller
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
  egress:
  # Vers l'API
  - to:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 8080
  # DNS
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53

---
# API peut recevoir du frontend et appeler la DB
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # Depuis le frontend
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
  # Depuis l'Ingress (API publique)
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8080
  egress:
  # Vers PostgreSQL
  - to:
    - podSelector:
        matchLabels:
          app: postgresql
    ports:
    - protocol: TCP
      port: 5432
  # Vers Redis
  - to:
    - podSelector:
        matchLabels:
          app: redis
    ports:
    - protocol: TCP
      port: 6379
  # Vers Kafka
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kafka
    - podSelector:
        matchLabels:
          app: kafka
    ports:
    - protocol: TCP
      port: 9092
  # DNS
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53

---
# PostgreSQL isolé
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: postgresql-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: postgresql
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # Uniquement depuis l'API
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 5432
  egress:
  # Réplication vers autre PostgreSQL (si HA)
  - to:
    - podSelector:
        matchLabels:
          app: postgresql
    ports:
    - protocol: TCP
      port: 5432

Cilium Network Policies (L7)

# Policy L7 avec Cilium
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-l7-policy
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: api
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: GET
          path: "/api/v1/.*"
        - method: POST
          path: "/api/v1/users"
          headers:
          - "Content-Type: application/json"
        - method: DELETE
          path: "/api/v1/users/[0-9]+"

---
# Policy DNS avec Cilium
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: egress-dns-policy
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: api
  egress:
  - toFQDNs:
    - matchName: "api.external-service.com"
    - matchPattern: "*.googleapis.com"
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP

DNS dans Kubernetes

Architecture CoreDNS

┌─────────────────────────────────────────────────────────────────────────────┐
│                        ARCHITECTURE COREDNS                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────┐        ┌─────────────────────────────────────────┐        │
│   │    Pod      │        │              CoreDNS                     │        │
│   │             │        │                                          │        │
│   │ /etc/resolv.conf     │  ┌─────────────────────────────────┐    │        │
│   │ nameserver: │───────▶│  │  Corefile                       │    │        │
│   │ 10.96.0.10  │        │  │                                 │    │        │
│   └─────────────┘        │  │  cluster.local {                │    │        │
│                          │  │    kubernetes cluster.local     │    │        │
│                          │  │  }                              │    │        │
│                          │  │  . {                            │    │        │
│                          │  │    forward . /etc/resolv.conf   │    │        │
│   Résolution:            │  │  }                              │    │        │
│                          │  └─────────────────────────────────┘    │        │
│   my-svc                 │                                          │        │
│   └─▶ my-svc.default.svc.cluster.local                             │        │
│                          │                                          │        │
│   pod-ip.ns.pod.cluster.local                                       │        │
│   └─▶ 10-244-1-5.default.pod.cluster.local                         │        │
│                          │                                          │        │
│   SRV records pour ports nommés:                                    │        │
│   _http._tcp.my-svc.default.svc.cluster.local                       │        │
│                          └──────────────────────────────────────────┘        │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Configuration CoreDNS Avancée

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready

        # Cluster DNS
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }

        # External DNS zones
        example.com:53 {
            forward . 10.0.0.53
        }

        # Cache
        cache 30 {
            success 9984 30
            denial 9984 5
        }

        # Forward external queries
        forward . /etc/resolv.conf {
            max_concurrent 1000
            policy sequential
        }

        # Prometheus metrics
        prometheus :9153

        # Logging
        log . {
            class denial error
        }

        loop
        reload
        loadbalance
    }

DNS Debugging

# Pod de debug DNS
kubectl run dns-debug --image=busybox:1.36 --restart=Never -- sleep 3600

# Tester la résolution
kubectl exec dns-debug -- nslookup kubernetes.default
kubectl exec dns-debug -- nslookup my-service.my-namespace.svc.cluster.local

# Vérifier les records SRV
kubectl exec dns-debug -- nslookup -type=SRV _http._tcp.my-service.my-namespace.svc.cluster.local

# Logs CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100 -f

# Métriques CoreDNS
kubectl port-forward -n kube-system svc/kube-dns 9153:9153
curl localhost:9153/metrics | grep coredns_dns_requests_total

Troubleshooting Réseau

Script de Diagnostic Complet

#!/bin/bash
# k8s-network-diag.sh - Diagnostic réseau Kubernetes

set -e

NAMESPACE=${1:-default}
POD_NAME=${2:-}

echo "=== Diagnostic Réseau Kubernetes ==="
echo "Namespace: $NAMESPACE"
echo ""

# 1. État des nodes
echo "=== 1. État des Nodes ==="
kubectl get nodes -o wide
echo ""

# 2. État des pods
echo "=== 2. État des Pods ==="
kubectl get pods -n $NAMESPACE -o wide
echo ""

# 3. Services
echo "=== 3. Services ==="
kubectl get svc -n $NAMESPACE -o wide
echo ""

# 4. Endpoints
echo "=== 4. Endpoints ==="
kubectl get endpoints -n $NAMESPACE
echo ""

# 5. Network Policies
echo "=== 5. Network Policies ==="
kubectl get networkpolicies -n $NAMESPACE
echo ""

# 6. État CNI
echo "=== 6. État du CNI ==="
# Calico
if kubectl get pods -n calico-system &>/dev/null; then
    echo "Calico détecté:"
    kubectl get pods -n calico-system
    kubectl get ippool -o wide 2>/dev/null || true
fi
# Cilium
if kubectl get pods -n kube-system -l k8s-app=cilium &>/dev/null; then
    echo "Cilium détecté:"
    kubectl get pods -n kube-system -l k8s-app=cilium
    kubectl exec -n kube-system -l k8s-app=cilium -- cilium status 2>/dev/null || true
fi
echo ""

# 7. CoreDNS
echo "=== 7. État CoreDNS ==="
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=20 2>/dev/null || true
echo ""

# 8. Ingress
echo "=== 8. Ingress Controllers ==="
kubectl get pods -n ingress-nginx 2>/dev/null || echo "NGINX Ingress non trouvé"
kubectl get pods -n traefik 2>/dev/null || echo "Traefik non trouvé"
echo ""
kubectl get ingress -n $NAMESPACE
echo ""

# 9. Test de connectivité si pod spécifié
if [ -n "$POD_NAME" ]; then
    echo "=== 9. Tests de connectivité depuis $POD_NAME ==="

    # DNS
    echo "Test DNS:"
    kubectl exec -n $NAMESPACE $POD_NAME -- nslookup kubernetes.default 2>/dev/null || echo "DNS test failed"

    # Kubernetes API
    echo ""
    echo "Test API Server:"
    kubectl exec -n $NAMESPACE $POD_NAME -- wget -qO- --timeout=5 https://kubernetes.default/healthz 2>/dev/null || echo "API test failed"

    # Service local
    echo ""
    echo "Services accessibles:"
    for svc in $(kubectl get svc -n $NAMESPACE -o jsonpath='{.items[*].metadata.name}'); do
        echo -n "  $svc: "
        kubectl exec -n $NAMESPACE $POD_NAME -- nc -zv $svc 80 2>&1 | grep -o "succeeded\|failed" || echo "unknown"
    done
fi

echo ""
echo "=== Diagnostic terminé ==="

Debugging avec Netshoot

# Pod de debug réseau avancé
apiVersion: v1
kind: Pod
metadata:
  name: netshoot
  namespace: production
spec:
  containers:
  - name: netshoot
    image: nicolaka/netshoot:latest
    command: ["sleep", "infinity"]
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
        - NET_RAW
  hostNetwork: false  # true pour debug host network
# Lancer netshoot
kubectl run netshoot --image=nicolaka/netshoot -it --rm -- /bin/bash

# Tests courants
# TCP connect
nc -zv my-service 80

# DNS lookup détaillé
dig +trace my-service.default.svc.cluster.local

# Trace route
mtr --tcp -P 80 my-service

# Capture packets
tcpdump -i eth0 -n port 80

# HTTP debug
curl -v http://my-service/

# Test TLS
openssl s_client -connect my-service:443 -servername my-service

# Vérifier les routes
ip route
ip addr

# Tester avec différentes IP sources
curl --interface eth0 http://my-service/

# iperf pour performance
iperf3 -c my-service -p 5201

Problèmes Courants et Solutions

┌─────────────────────────────────────────────────────────────────────────────┐
│                   PROBLÈMES RÉSEAU COURANTS                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  PROBLÈME: Pod ne peut pas résoudre DNS                                     │
│  ─────────────────────────────────────────                                  │
│  Symptôme: nslookup kubernetes échoue                                       │
│  Causes:                                                                     │
│    • CoreDNS pods down                                                       │
│    • Network Policy bloque DNS (UDP 53)                                     │
│    • /etc/resolv.conf mal configuré                                         │
│  Debug:                                                                      │
│    kubectl get pods -n kube-system -l k8s-app=kube-dns                      │
│    cat /etc/resolv.conf dans le pod                                         │
│                                                                              │
│  PROBLÈME: Service non accessible (Connection refused)                      │
│  ─────────────────────────────────────────────────────                      │
│  Symptôme: curl http://my-svc échoue                                        │
│  Causes:                                                                     │
│    • Aucun endpoint (pods non ready)                                        │
│    • Selector ne match pas                                                  │
│    • Port incorrect                                                         │
│  Debug:                                                                      │
│    kubectl get endpoints my-svc                                             │
│    kubectl describe svc my-svc                                              │
│                                                                              │
│  PROBLÈME: Pods ne communiquent pas entre nodes                             │
│  ────────────────────────────────────────────────                           │
│  Symptôme: ping pod-ip-other-node timeout                                   │
│  Causes:                                                                     │
│    • CNI mal configuré                                                       │
│    • Firewall bloque overlay (VXLAN 4789, IPIP)                            │
│    • Routes inter-nodes manquantes                                          │
│  Debug:                                                                      │
│    kubectl get pods -n calico-system                                        │
│    iptables -L -n sur les nodes                                             │
│                                                                              │
│  PROBLÈME: Ingress retourne 502/503                                         │
│  ─────────────────────────────────────                                      │
│  Symptôme: Bad Gateway depuis l'extérieur                                   │
│  Causes:                                                                     │
│    • Backend pods non healthy                                               │
│    • Service mal configuré                                                  │
│    • Network Policy bloque Ingress→Pods                                     │
│  Debug:                                                                      │
│    kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx    │
│    kubectl describe ingress my-ingress                                       │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Performance Réseau

Optimisation CNI

# Calico avec eBPF pour meilleures performances
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  calicoNetwork:
    linuxDataplane: BPF  # eBPF au lieu d'iptables
    hostPorts: Disabled  # Désactive hostPorts pour perf
    ipPools:
    - cidr: 10.244.0.0/16
      encapsulation: None  # Pas d'overlay si possible
      natOutgoing: Enabled

---
# Cilium avec DSR et bandwidth manager
# helm values
kubeProxyReplacement: true
loadBalancer:
  mode: dsr  # Direct Server Return
bandwidthManager:
  enabled: true
  bbr: true  # BBR congestion control
bpf:
  masquerade: true
  hostRouting: true

Tests de Performance

# iperf3 entre pods
kubectl run iperf-server --image=networkstatic/iperf3 -- -s
kubectl run iperf-client --image=networkstatic/iperf3 --rm -it -- -c iperf-server -t 30

# Latence
kubectl exec netshoot -- hping3 -S -p 80 -c 100 my-service

# HTTP performance
kubectl exec netshoot -- ab -n 10000 -c 100 http://my-service/

# wrk pour load testing
kubectl exec netshoot -- wrk -t12 -c400 -d30s http://my-service/

Conclusion

Le networking Kubernetes est complexe mais essentiel. Points clés à retenir :

  1. Choisissez le bon CNI : Calico pour la polyvalence, Cilium pour les features avancées
  2. Utilisez les Network Policies : Sécurisez vos workloads dès le départ
  3. Configurez bien vos Services : Comprenez les différences entre ClusterIP, NodePort, LoadBalancer
  4. Ingress Controller en HA : 3 replicas minimum avec anti-affinity
  5. Monitorez CoreDNS : Le DNS est critique, surveillez-le
  6. Testez régulièrement : Scripts de diagnostic et tests de connectivité

Le networking est souvent la source de problèmes subtils. Investissez du temps pour bien le comprendre et le documenter dans votre contexte.

F

Florian Courouge

Expert DevOps & Kafka | Consultant freelance specialise dans les architectures distribuees et le streaming de donnees.

Articles similaires