Aller au contenu

Module 4r · Exposer une app : le chemin d'une requête

Objectifs

  • Les 4 types de Service et quand les choisir.
  • Le DNS interne : comment les pods se joignent sans IP.
  • L'Ingress et le TLS : du navigateur au pod.
  • Durée : ~1 h 15 · Pré-requis : Module 4 - Gouvernance.
graph LR
    U[Navigateur] --> I[Ingress]
    I --> S[Service]
    S --> P1[Pod]
    S --> P2[Pod]

Une requête qui arrive sur ton app traverse, dans l'ordre : Ingress → Service → Pod. Ce chemin est le fil conducteur du module - et, à l'envers, c'est exactement la checklist de diagnostic du module suivant.

Les 4 types de Service

Type Ce qu'il fait Quand l'utiliser
ClusterIP IP virtuelle interne au cluster - le défaut communication entre apps du cluster
NodePort ouvre un port (30000-32767) sur chaque nœud exposer sans load balancer, fréquent on-premise
LoadBalancer demande une IP externe à un fournisseur de LB (cloud : auto ; bare-metal : MetalLB/ServiceLB) exposition publique
ExternalName simple alias DNS (CNAME) vers un nom externe pointer vers un service hors cluster

Les trois premiers s'empilent : un LoadBalancer est aussi un NodePort, qui est aussi un ClusterIP.

Pourquoi ClusterIP est le défaut

La majorité des services ne doivent jamais être exposés à l'extérieur (une base de données, une API interne…). Le défaut est donc le plus fermé : on n'ouvre que ce qu'il faut.

D'où vient l'IP publique d'un LoadBalancer ?

type: LoadBalancer ne fabrique pas l'IP : il la demande à un fournisseur de LB. Qui répond dépend de l'environnement - ce n'est pas « impossible hors cloud », c'est pas automatique hors cloud :

Environnement Qui répond EXTERNAL-IP
Cloud managé (EKS/GKE/AKS) le cloud-controller-manager vrai LB dédié, facturé + IP/DNS publique
Bare-metal + MetalLB MetalLB IP d'un pool que tu possèdes
k3s (ServiceLB intégré) Klipper l'IP du nœud
Rien d'installé personne reste <pending> à vie

Sur le cloud, le LB managé arrive tout seul (et coûte) ; ailleurs, c'est toi qui installes le fournisseur (MetalLB) et fournis l'IP. Détail cloud au module EKS.

Dans ta sandbox

Essaie (crée d'abord la cible) :

kubectl create deployment web --image nginx:1.27-alpine
kubectl expose deploy/web --port 80 --type LoadBalancer
kubectl get svc

L'EXTERNAL-IP reste <pending> - le vcluster n'a aucun fournisseur de LB. Le Service ouvre quand même un NodePort (un LoadBalancer est un NodePort, qui est un ClusterIP). Ici, l'exposition publique ne passe donc pas par une IP par app, mais par Ingress → Traefik (un seul point d'entrée + TLS), comme détaillé plus bas.

Le DNS interne : se parler sans IP

Chaque Service reçoit un nom DNS interne - <service>.<namespace>.svc.cluster.local, résolu par CoreDNS - si bien que dans le même namespace, http://api suffit pour joindre le Service api. Les pods ne se parlent jamais par IP : une IP de pod change à chaque redémarrage, le nom du Service est stable.

# depuis un pod, joindre le service "api" du même namespace
curl http://api
# depuis un autre namespace : nom complet
curl http://api.dev.svc.cluster.local

Exercice - Du Service aux endpoints

  1. Crée un deployment web + un Service ClusterIP.
  2. kubectl get endpoints web : le Service pointe-t-il bien sur les pods ?
  3. Change un label du selector et observe les endpoints disparaître : c'est la panne réseau n°1 (Service qui ne pointe sur rien).

Ingress + TLS : du navigateur au pod

Le Service règle le trafic dans le cluster. Mais une requête venue d'Internet arrive en HTTP(S) sur un seul point d'entrée, et il faut l'aiguiller vers le bon Service selon l'URL demandée. C'est le rôle de l'Ingress.

C'est quoi un Ingress ?

Un Ingress est un objet k8s qui décrit des règles de routage HTTP(S) : « telle adresse (api.monsite.fr) ou tel chemin (/blog) → tel Service ». C'est, en somme, un reverse-proxy déclaré en YAML.

Un Ingress seul ne fait rien

L'objet Ingress n'est qu'une liste de règles. Pour qu'elles s'appliquent, il faut un Ingress Controller : le composant qui tourne réellement dans le cluster, lit tous les Ingress et configure un proxy en conséquence. Dans l'infra de ce cours, c'est Traefik (ailleurs : nginx-ingress, HAProxy…). Pas de controller = un Ingress qui reste lettre morte.

graph TB
    U[Navigateur<br/>https://...] --> T[Ingress Controller<br/>Traefik]
    T -->|api.monsite.fr| SA[Service api] --> PA[Pods api]
    T -->|monsite.fr/blog| SB[Service blog] --> PB[Pods blog]

Un seul point d'entrée public, qui distribue vers autant de Services qu'on veut selon l'hôte et le chemin.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: monapp
spec:
  rules:
    - host: monsite.fr
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web        # → le Service "web" (ClusterIP suffit)
                port:
                  number: 80
  tls:
    - hosts: [monsite.fr]
      secretName: monsite-tls    # le certificat (voir plus bas)
kubectl get ingress              # les routes hôte/chemin → service
kubectl describe ingress monapp  # règles, backend, certif TLS

Et le TLS, c'est quoi son rôle ?

TLS (l'ancien « SSL ») chiffre la connexion entre le navigateur et le cluster - c'est le https:// et le cadenas. Sans lui, mot de passe et données circulent en clair.

Point clé : le chiffrement est terminé au bord, sur l'Ingress Controller. Le navigateur parle HTTPS à Traefik ; Traefik déchiffre et parle HTTP au Service à l'intérieur du cluster (réseau déjà privé). Le certificat (la pièce d'identité du site) est rangé dans un Secret k8s, référencé par le champ tls.secretName de l'Ingress.

Qui fabrique le certificat ?

Dans cette infra, cert-manager demande et renouvelle automatiquement les certificats auprès de Let's Encrypt (gratuits, valables 90 jours), et dépose le Secret que l'Ingress va utiliser. Tu déclares « je veux du TLS sur monsite.fr », la machinerie s'occupe de l'obtenir et de le garder à jour.

Un seul LB devant plusieurs apps

Sur un cloud, chaque Service LoadBalancer = un (vrai) LB facturé. L'intérêt de l'Ingress : un seul LoadBalancer en frontal (devant le controller), qui distribue vers autant de Services qu'on veut par hôte/chemin. On le revoit concrètement au module EKS.

Pratique

Le TP de ce module, dans le terminal de ta sandbox - une fois la lecture faite :

tp start 04r-exposer   # exposer un deployment : Service, endpoints, DNS par le nom, port-forward

fais la manip puis tp check (ou tp watch pour l'auto-validation) · tp hint / tp solution si tu bloques.

L'Ingress, lui, s'exerce à la main :

Exercice - Du Service à l'Ingress

Crée un Ingress qui route web.local → Service web. Vérifie la route dans k9s (:ing), puis le certificat TLS s'il y en a un.

Ce qu'il faut retenir

  • 4 types de Service : ClusterIP (défaut) ⊂ NodePortLoadBalancer, + ExternalName (alias DNS).
  • Chaque Service a un nom DNS interne stable - les pods se parlent par nom, jamais par IP.
  • kubectl get endpoints dit si un Service pointe vraiment sur des pods : le premier réflexe réseau.
  • L'Ingress = des règles de routage HTTP(S) par hôte/chemin, appliquées par un Ingress Controller (Traefik) ; un seul LB pour plusieurs apps.
  • Le TLS chiffre navigateur ↔ cluster, terminé sur l'Ingress ; certificat dans un Secret, fourni/renouvelé par cert-manager + Let's Encrypt.

Quiz éclair

Teste-toi : réponds de tête, puis déplie.

1. Quel type de Service pour : une API interne ? un site public sur EKS ?

API interne → ClusterIP (le défaut). Site public sur EKSLoadBalancer (ou mieux : un Ingress devant un seul LoadBalancer). NodePort dépanne surtout on-premise ; ExternalName n'expose rien - c'est un alias DNS vers l'extérieur.

2. Deux pods du même namespace : comment l'un joint-il l'autre ?

Par le nom du Service : http://<service> (ou <service>.<ns>.svc.cluster.local depuis un autre namespace), résolu par CoreDNS. Jamais par l'IP du pod, qui change.

3. Tu crées un Ingress mais l'URL ne répond pas. Premier réflexe ?

Vérifier qu'un Ingress Controller tourne bien (sans lui, l'Ingress n'est qu'une liste de règles inertes), puis que le Service backend a des endpoints. L'Ingress aiguille, mais c'est toujours Service → Pod qui sert la requête.

4. Une requête n'arrive pas jusqu'au pod. Par où regarder en premier ?

kubectl get endpoints <service> : le Service pointe-t-il sur des pods ? Un selector qui ne matche aucun label = endpoints vides = requête dans le vide. (Méthode complète au module Diagnostic.)

5. Tu crées un Service LoadBalancer sur ta sandbox (un k8s sans fournisseur de LB). Quel EXTERNAL-IP ?

Il reste <pending> indéfiniment : type: LoadBalancer demande une IP à un fournisseur de LB, mais ici personne ne répond. Sur le cloud, le cloud-controller-manager la fournit automatiquement ; en bare-metal il faut MetalLB (ou ServiceLB sur k3s, qui prête l'IP du nœud). Le Service ouvre tout de même un NodePort au passage.

➡️ Suite : Module 4t - Diagnostiquer : la méthode