Gateway API en production
Pourquoi
Le cours précédent a exposé Signalements avec une Gateway et une HTTPRoute dans le namespace de l'application (Déployer Signalements). Pour un seul service, cela suffit. Pour un cluster qui héberge les applications de plusieurs équipes ou de plusieurs clients, trois questions se posent aussitôt.
Qui possède quoi ? Qui décide qu'un port 443 est ouvert, qu'un certificat est servi, qu'un domaine est réservé à telle équipe ? Et qui, au contraire, décide qu'/api/v2 part vers la nouvelle version ? Avec Ingress, ces deux niveaux de décision vivent dans le même objet, et les droits RBAC ne savent pas les séparer.
Comment éviter qu'une équipe en dérange une autre ? Si deux équipes déclarent la même route sur le même nom d'hôte, laquelle l'emporte ? Si une équipe envoie du trafic vers le Service d'une autre, qui l'a autorisé ?
Comment déployer progressivement ? Envoyer 10 % du trafic vers une nouvelle version, réécrire un chemin, rediriger une ancienne adresse : Ingress ne sait pas le dire, chaque contrôleur invente donc ses annotations, et la configuration cesse d'être portable.
Gateway API répond à ces trois questions par construction : des ressources séparées par rôle, des règles d'attachement explicites entre elles, et un vocabulaire standard pour le routage. Cette leçon la fait fonctionner comme un opérateur de cluster la fait fonctionner, avec Traefik comme implémentation, sur le modèle de ce que Lyneko exploite sur Kapsule.
Les concepts
Trois rôles, trois ressources
La documentation de Gateway API décrit trois profils. Ils n'ont pas besoin d'être trois équipes : sur un petit cluster, ce sont trois casquettes d'une même personne. Mais le modèle permet de les séparer sans changer d'objets.
| Rôle | Ressource | Possède |
|---|---|---|
| Fournisseur d'infrastructure | GatewayClass | le contrôleur et ses capacités (Traefik, Cilium, Envoy Gateway, un répartiteur de cloud) |
| Opérateur du cluster | Gateway | l'entrée : adresse, ports, protocoles, noms d'hôte, certificats, namespaces autorisés |
| Développeur d'application | HTTPRoute, GRPCRoute... | les règles de routage vers ses Services |
Le lien entre les niveaux est déclaré des deux côtés. La Gateway désigne sa classe (gatewayClassName) ; la route désigne sa Gateway (parentRefs) ; et la Gateway dit quelles routes elle accepte (allowedRoutes). Tant que ces trois déclarations ne concordent pas, rien n'est programmé. Les droits RBAC se calquent sur ces objets : l'équipe applicative reçoit create sur les HTTPRoute de son namespace, l'équipe plateforme seule sur les Gateway.
Note
Une GatewayClass a pour contrôleur un nom d'identifiant (controllerName). Celui de Traefik est traefik.io/gateway-controller. Le contrôleur écrit dans le statut de la classe qu'il l'a acceptée ; sans cette condition Accepted, aucune Gateway de cette classe ne sera servie.
La Gateway et ses listeners
Une Gateway décrit un ou plusieurs listeners, des points d'écoute. Chaque listener a un nom, un port, un protocole (HTTP, HTTPS, TLS, TCP, UDP), un nom d'hôte facultatif et des règles sur les routes qui peuvent s'y attacher. Les champs que présente le schéma 1.6.2 d'un listener sont : name, port, protocol, hostname, allowedRoutes (avec namespaces et kinds) et tls (avec mode, certificateRefs, options).
Pourquoi plusieurs listeners dans une même Gateway ? Parce qu'ils correspondent à des publics différents. Un listener pour les applications des équipes, un autre pour les outils de la plateforme (tableau de bord, métriques), chacun avec son nom d'hôte et ses propres namespaces autorisés. Deux listeners sur le même port sont possibles s'ils se distinguent par leur nom d'hôte : le contrôleur choisit celui qui correspond.
allowedRoutes : qui peut s'attacher
C'est le contrôle d'accès de l'entrée. allowedRoutes.namespaces.from prend trois valeurs :
Same(la valeur par défaut) : seules les routes du namespace de la Gateway ;All: les routes de tous les namespaces (rarement une bonne idée) ;Selector: les routes des namespaces dont les étiquettes correspondent à un sélecteur.
allowedRoutes.kinds restreint de surcroît les types de routes acceptés (par exemple HTTPRoute seulement). Une route qui désigne une Gateway sans y être autorisée reçoit une condition Accepted: False avec la raison NotAllowedByListeners, et n'est pas servie.
ReferenceGrant : autoriser ce qui franchit un namespace
Une HTTPRoute envoie normalement vers des Services de son namespace. Qu'elle désigne un Service d'un autre namespace est une opération sensible : l'équipe du namespace A ferait recevoir du trafic à l'équipe B, éventuellement un trafic qu'elle n'a pas demandé. Gateway API refuse donc les références croisées par défaut, et exige une ressource ReferenceGrant créée dans le namespace de la cible.
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: routes-de-la-plateforme
namespace: signalements # le namespace de la cible
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: passerelle # qui a le droit de référencer
to:
- group: ""
kind: ServiceLisez-la comme une phrase : « les HTTPRoute du namespace passerelle peuvent référencer les Services de ce namespace ». Le principe est celui d'une permission donnée par le propriétaire de la ressource, pas prise par le demandeur : sans quoi n'importe qui pourrait s'attribuer l'accès. Les mêmes grants servent aux Gateways qui référencent un Secret de certificat dans un autre namespace (leçon 7). Notez que le champ spec est obligatoire dans le schéma depuis la version 1.6.
Les correspondances
Une règle d'HTTPRoute contient des matches (quand elle s'applique) et des backendRefs (où envoyer). Quatre critères sont possibles dans une correspondance : path, headers, queryParams et method. À l'intérieur d'une correspondance, tous les critères se combinent en ET ; entre plusieurs correspondances d'une même règle, c'est un OU.
Pour le chemin, type vaut Exact, PathPrefix (le défaut), ou RegularExpression : ce dernier est de support spécifique à l'implémentation, donc moins portable. Un PathPrefix: /api correspond à /api et /api/signalements, mais pas à /apiary : la comparaison se fait par éléments de chemin.
Quand plusieurs règles correspondent, la spécification fixe un ordre de priorité : la correspondance exacte du chemin d'abord, puis le préfixe le plus long, puis la méthode, puis le plus grand nombre d'en-têtes, puis le plus grand nombre de paramètres de requête. Si deux règles de routes différentes restent à égalité, la plus ancienne (date de création) gagne. Ce dernier critère mérite qu'on s'en souvienne : deux équipes qui déclarent la même route ne produisent pas une erreur, l'une des deux est simplement ignorée.
Les filtres
Un filtre modifie la requête ou la réponse. Les types que contient le schéma 1.6.2 sont : RequestHeaderModifier, ResponseHeaderModifier, RequestMirror, RequestRedirect, URLRewrite, CORS, ExternalAuth et ExtensionRef (le point d'extension propre à une implémentation). Les filtres se posent sur une règle, ou sur une backendRef pour ne toucher qu'un des destinataires.
Les modificateurs d'en-têtes sont Core ; redirections, réécritures et miroir sont Extended (portables mais facultatifs). Le miroir copie les requêtes vers un second destinataire dont la réponse est ignorée : on éprouve une nouvelle version avec du trafic réel sans impact visible.
La répartition pondérée
Chaque backendRef porte un weight (1 par défaut). La part de trafic d'un destinataire est son poids divisé par la somme des poids de la règle. Avec 90 et 10, 10 % des requêtes vont au second ; avec 9 et 1, c'est la même chose. Un poids de 0 désactive le destinataire sans le retirer : c'est utile pour préparer un déploiement. La répartition porte sur des requêtes, pas sur des clients : le même navigateur peut tomber alternativement sur les deux versions, à moins d'activer la persistance de session (expérimentale).
Timeouts et retries
La règle d'une HTTPRoute accepte un champ timeouts avec deux durées : request (temps total depuis la requête reçue jusqu'à la fin de la réponse) et backendRequest (temps d'une requête individuelle vers le destinataire). Ce champ est dans le canal standard depuis la version 1.2. Une valeur 0s désactive le délai ; backendRequest ne doit pas dépasser request.
Le champ retry (attempts, backoff, codes) n'est lui pas dans le canal standard : une comparaison des schémas de la version 1.6.2 le montre, il n'existe que dans le canal expérimental, avec sessionPersistence. La conséquence est pratique : pour l'utiliser, il faut installer le fichier experimental-install.yaml, avec le risque de rupture d'une API expérimentale, et vérifier que votre contrôleur le prend en charge. Règle de prudence : ne construisez aucune dépendance critique sur un champ expérimental.
Les autres routes
L'API ne se limite pas à HTTP. GRPCRoute route le gRPC par service et méthode. TLSRoute et ListenerSet sont passés dans le canal standard à la version 1.5, TCPRoute et UDPRoute à la version 1.6 (notes de version). Pour Traefik, la documentation fait pourtant passer TCPRoute et TLSRoute par l'option experimentalChannel : vérifiez la page de votre contrôleur avant de vous appuyer sur l'une d'elles.
Le statut, ou comment l'API parle
Chaque objet reçoit du contrôleur un statut, sous forme de conditions (type, état, raison, message). Trois sont à connaître :
Accepted: la configuration est valide et acceptée par le contrôleur. Sur une route, elle est par parent (chaque Gateway désignée) ;Programmed: la configuration est traduite en fonctionnement réel, une adresse existe. Sur une Gateway seulement ;ResolvedRefs: toutes les références ont été trouvées et sont permises (Services, Secrets). Sur les listeners et les routes.
Un False s'accompagne d'une raison normalisée : NotAllowedByListeners, NoMatchingListenerHostname, BackendNotFound, RefNotPermitted, InvalidCertificateRef... C'est la grande amélioration par rapport à Ingress : la cause d'un refus est dans l'API, avec un vocabulaire commun à tous les contrôleurs.
En pratique
Les manifestes ci-dessous ont été validés comme du YAML et vérifiés champ par champ contre les schémas de la version 1.6.2. Les commandes qui demandent un cluster sont expliquées, et leur résultat est décrit sans être reproduit.
1. Installer les CRD et Traefik
Les définitions de ressources, canal standard, version prise en charge par Traefik 3.7 :
$ kubectl apply --server-side \
-f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.2/standard-install.yaml
Puis Traefik, avec un fichier de valeurs plutôt que des --set, qui se relit et se versionne :
# traefik-values.yaml (chart 41.6.1)
providers:
kubernetesGateway:
enabled: true # active le fournisseur Gateway API et la GatewayClass « traefik »
gateway:
enabled: false # pas de Gateway par défaut : c'est l'opérateur qui écrit la sienne$ helm install traefik traefik/traefik --version 41.6.1 \
--namespace traefik --create-namespace -f traefik-values.yaml
$ kubectl get gatewayclass
Dans le chart, ports.web écoute sur 8000 dans le pod (exposé sur 80 par le Service), et ports.websecure sur 8443 (exposé sur 443). Une Gateway ne peut utiliser que des ports déclarés dans la section ports du chart : le commentaire du fichier de valeurs le dit pour chaque listener. Si votre listener est sur un port inconnu, la Gateway est refusée.
2. La Gateway de la plateforme
L'opérateur du cluster crée, dans un namespace dédié, la Gateway partagée.
apiVersion: v1
kind: Namespace
metadata:
name: passerelle
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: entree
namespace: passerelle
spec:
gatewayClassName: traefik
listeners:
- name: apps
protocol: HTTP
port: 8000 # point d'entrée « web » de Traefik
hostname: "*.apps.example.com"
allowedRoutes:
kinds:
- kind: HTTPRoute
namespaces:
from: Selector
selector:
matchLabels:
acces-passerelle: apps
- name: plateforme
protocol: HTTP
port: 8000
hostname: "plateforme.example.com"
allowedRoutes:
namespaces:
from: Same # seules les routes de l'équipe plateformeLes deux listeners partagent le port 8000 et se distinguent par leur nom d'hôte. Le premier est ouvert aux namespaces qui portent l'étiquette acces-passerelle: apps ; le second est réservé au namespace de la Gateway. On donne alors l'étiquette au namespace de l'application :
$ kubectl label namespace signalements acces-passerelle=apps
$ kubectl get gateway entree -n passerelle
La seconde commande doit afficher la classe traefik, une adresse (celle du répartiteur de charge Scaleway sur Kapsule) et PROGRAMMED à True.
3. La route de l'application
L'équipe de Signalements écrit sa route, dans son namespace :
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: signalements
namespace: signalements
spec:
parentRefs:
- name: entree
namespace: passerelle
sectionName: apps
hostnames:
- signalements.apps.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: signalements
port: 80parentRefs désigne la Gateway et son namespace (par défaut, c'est celui de la route), et sectionName le listener visé. Le nom d'hôte de la route doit être compatible avec celui du listener : signalements.apps.example.com correspond à *.apps.example.com. Un nom qui ne correspondrait à aucun listener donne Accepted: False, raison NoMatchingListenerHostname.
4. Un déploiement canari
On a déployé une version 1.3.0 de l'API sous un second Deployment, derrière un second Service signalements-canari (même port, sélecteur sur la nouvelle version). Les deux Services reçoivent le trafic dans les proportions de la règle :
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: signalements
namespace: signalements
spec:
parentRefs:
- name: entree
namespace: passerelle
sectionName: apps
hostnames:
- signalements.apps.example.com
rules:
# 1. Les équipes internes forcent la nouvelle version avec un en-tête.
- matches:
- headers:
- name: X-Version
value: canari
backendRefs:
- name: signalements-canari
port: 80
# 2. Tous les autres : 95 % / 5 %.
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: signalements
port: 80
weight: 95
- name: signalements-canari
port: 80
weight: 5La première règle utilise une correspondance d'en-tête : une requête portant X-Version: canari va toujours au canari, ce qui permet de l'éprouver à la main. La seconde envoie 5 % du reste. Pour augmenter la part, on change les poids (95/5, puis 75/25, 50/50, 0/100) en les commitant, avec Argo CD comme pour le reste. Un poids à 0 pour l'ancienne version la garde prête pour un retour arrière en un commit.
Warning
La répartition est par requête et sans affinité. Si la nouvelle version change le format d'une réponse que le client enchaîne avec une autre requête, un même utilisateur verra les deux versions en alternance. Le canari suppose des versions compatibles entre elles, ce que la leçon sur la mise à jour du cours précédent exigeait déjà.
5. Filtres : redirection, réécriture, en-têtes
Trois cas typiques, dans une même route :
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: signalements-compat
namespace: signalements
spec:
parentRefs:
- name: entree
namespace: passerelle
sectionName: apps
hostnames:
- signalements.apps.example.com
rules:
# L'ancienne adresse /v1/... est redirigée définitivement vers /api/...
- matches:
- path:
type: PathPrefix
value: /v1
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /api
statusCode: 301
# Le préfixe public /api est retiré avant d'atteindre l'application.
- matches:
- path:
type: PathPrefix
value: /api
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Entree
value: passerelle
- type: ResponseHeaderModifier
responseHeaderModifier:
set:
- name: Cache-Control
value: no-store
backendRefs:
- name: signalements
port: 80La redirection répond au client (code 301, nouvelle adresse) : il refait la requête. La réécriture, elle, est invisible : l'application reçoit /sante alors que le client a appelé /api/sante. Le filtre d'en-têtes de requête propose add, set et remove ; celui de réponse en fait de même sur ce que reçoit le client.
6. Une route de la plateforme vers un Service de l'application
Admettons que l'équipe plateforme veuille exposer, depuis son namespace, une page de supervision de Signalements. Sa route référence un Service d'un autre namespace :
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: supervision-signalements
namespace: passerelle
spec:
parentRefs:
- name: entree
sectionName: plateforme
hostnames:
- plateforme.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /signalements
backendRefs:
- name: signalements
namespace: signalements # référence entre namespaces
port: 80Tant que la ReferenceGrant de la section « Les concepts » n'existe pas dans le namespace signalements, la route est acceptée (Accepted: True) mais sa condition ResolvedRefs est à False, raison RefNotPermitted. Créez-la, et la condition passe à True sans autre action : le contrôleur réagit à la ReferenceGrant.
7. Timeouts
Pour la route d'export de Signalements, longue par nature, et le reste :
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: signalements-delais
namespace: signalements
spec:
parentRefs:
- name: entree
namespace: passerelle
sectionName: apps
hostnames:
- signalements.apps.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api/export
timeouts:
request: 60s
backendRequest: 60s
backendRefs:
- name: signalements
port: 80
- matches:
- path:
type: PathPrefix
value: /api
timeouts:
request: 10s
backendRequest: 5s
backendRefs:
- name: signalements
port: 80Le délai fait partie du canal standard, mais comme toute fonction Extended il reste facultatif pour un contrôleur : sa documentation indique ce qu'il en fait. Le retry, lui, s'écrit ainsi dans le canal expérimental (CRD expérimentales requises) :
# Canal expérimental seulement
retry:
attempts: 2
codes: [502, 503]
backoff: 100ms8. Lire le statut
$ kubectl get gateway,httproute -A
$ kubectl describe httproute signalements -n signalements
$ kubectl get gateway entree -n passerelle -o jsonpath='{range .status.listeners[*]}{.name}{"\t"}{range .conditions[*]}{.type}={.status}({.reason}) {end}{"\n"}{end}'
La première vue d'ensemble. La deuxième affiche, dans la partie Status > Parents, une entrée par Gateway visée avec ses conditions Accepted et ResolvedRefs. La troisième extrait, listener par listener, les conditions de la Gateway : chacun doit afficher Accepted=True, Programmed=True, ResolvedRefs=True. Un listener qui échoue le dit lui-même, sans qu'une autre le masque.
9. Migrer depuis Ingress
L'outil ingress2gateway du projet Kubernetes lit des objets Ingress (et, selon le fournisseur, les ressources propres au contrôleur) et émet des ressources Gateway API. Sa dernière version (1.2.0) prend en charge, d'après son README, plusieurs fournisseurs, dont ingress-nginx et traefik.
$ ingress2gateway print --providers=ingress-nginx -n signalements > gateway-api.yaml
La commande lit le namespace indiqué dans le cluster courant et écrit les manifestes sur la sortie standard, avec des avertissements pour les annotations qu'elle n'a pas pu traduire. Relisez la sortie comme un brouillon, jamais comme un résultat : les annotations sans équivalent portable (certaines règles de limitation de débit, des extraits de configuration) sont à reprendre à la main, avec un filtre ExtensionRef ou un objet propre au contrôleur. Une migration sans surprise se fait en parallèle : on déploie les routes Gateway API sur un nom d'hôte de test, on compare, puis on bascule le DNS.
Sous le capot
Le contrôleur est un client de l'API. Traefik, comme les autres implémentations, ne lit pas des fichiers : il ouvre des watches sur les GatewayClass, Gateways, routes, ReferenceGrants, Services, EndpointSlices et Secrets, et recalcule sa configuration à chaque événement. L'état « programmé » veut dire : la configuration est chargée dans le proxy. La table de routage vit en mémoire de chaque pod Traefik, ce qui explique qu'un redémarrage de Traefik la reconstruise en quelques secondes depuis l'API.
Pourquoi la ReferenceGrant est dans la cible. Une route est créée par un acteur du namespace A ; un Service est la propriété d'un acteur du namespace B. Si l'autorisation vivait côté route, A s'autoriserait lui-même. Dans la cible, la permission suppose un droit d'écriture dans le namespace de B, que A n'a pas. C'est la même logique que le RBAC : on accorde de l'accès à d'autres, on ne se l'attribue pas.
Trafic direct aux pods. Comme le rappelait la leçon 11 du cours précédent, Traefik envoie le trafic à l'adresse des pods, tirée des EndpointSlices, sans passer par l'adresse virtuelle du Service (kube-proxy et ses alternatives). Votre répartition pondérée s'applique donc requête par requête, dans Traefik. Le Service n'est ici qu'une liste de pods et un nom stable.
Pièges courants
Les ports de la Gateway ne sont pas ceux du Service Traefik. Le listener s'écrit en 8000 ou 8443 (les ports du pod Traefik), alors que les clients se connectent aux ports 80 et 443 du Service. Écrire port: 80 donne une Gateway refusée par Traefik : les ports d'un listener doivent correspondre aux points d'entrée déclarés dans le chart.
Accepted: True ne veut pas dire « ça marche ». Une route peut être acceptée et pourtant ne rien servir, parce que ResolvedRefs est à False (Service absent, référence non permise). Lisez toujours les deux.
Une CRD absente ou trop ancienne. Installer Traefik avant les CRD ou avec des CRD d'une version que le contrôleur ne gère pas produit des erreurs de watch dans ses journaux, pas dans le statut des objets. Le contrôle est : kubectl get crd | grep gateway.networking.k8s.io après chaque mise à jour de Gateway API ou du contrôleur.
Mélanger les canaux. Les notes de version 1.5 signalent qu'une règle d'admission (la safe-upgrades ValidatingAdmissionPolicy) empêche d'installer les CRD du canal expérimental par-dessus celles du canal standard. Choisissez un canal par cluster, et gardez la même version dans les environnements.
Sécurité
- Les droits RBAC reflètent les rôles. Donnez aux équipes applicatives
create,updateetdeletesur les HTTPRoute de leur namespace seulement. Les Gateways, GatewayClasses et ReferenceGrants entre namespaces restent à l'équipe plateforme. Une équipe qui peut créer une ReferenceGrant dans son propre namespace n'ouvre que ses Services, ce qui est voulu. - Les étiquettes de namespace sont un contrôle d'accès. Avec
from: Selector, la personne qui peut poser l'étiquetteacces-passerelle: appssur un namespace lui donne l'entrée. Réservez cette permission à l'équipe plateforme, ou utilisez une politique d'admission qui l'interdit. - Réduisez
allowedRoutes.from: Allsur un listener de production est l'équivalent de « n'importe qui peut publier sur ce domaine ». PréférezSelector, avec un nom d'hôte précis par listener. - Limitez les types de route. Une Gateway HTTP n'a pas à accepter les routes TCP ou TLS d'équipes applicatives.
- Les filtres modifient des en-têtes de confiance. Si l'application s'appuie sur
X-Forwarded-Forou sur un en-tête d'identité posé par la passerelle, vérifiez qu'un client ne peut pas les poser lui-même : supprimez-les avec un filtreRequestHeaderModifierà l'entrée avant de les remplacer. - Contrôler ce qui est dans le canal expérimental. Un champ expérimental est un contrat qui peut changer : un contrôleur qui l'ignore silencieusement rend un contrôle de sécurité (par exemple un retry sur une méthode non idempotente) inopérant.
En production
- Une Gateway par périmètre de confiance, pas une par application : une pour les applications internes, une pour les clients, chacune avec son répartiteur de charge Scaleway (donc son coût et son adresse). Plusieurs équipes se partagent une Gateway par les listeners et les sélecteurs.
- Haute disponibilité de Traefik. Au moins deux répliques, un
PodDisruptionBudgetet une répartition sur plusieurs nœuds, comme toute charge dont dépend le trafic entrant. - Le canari se pilote par Git. Les poids se changent par commit ; l'automatisation (Argo Rollouts, Flagger) sait piloter les poids d'une HTTPRoute pour promouvoir ou annuler selon des métriques. C'est le sujet du cours GitOps.
- Versions. Mettez à jour les CRD avant le contrôleur, et lisez les notes de version de Gateway API : la 1.5 et la 1.6 ont déplacé TLSRoute, TCPRoute et UDPRoute vers le canal standard et supprimé d'anciennes versions d'API. Testez sur un cluster de pré-production.
- Migration d'Ingress. Gateway API et Ingress cohabitent : Traefik sait servir les deux. On migre route par route, et on retire l'Ingress seulement quand le trafic a basculé. La page de Kubernetes sur Gateway API précise que l'API Ingress est gelée.
- Surveiller le statut. Une alerte sur
Programmed != True(Gateways) et surAcceptedouResolvedRefsdifférents deTrue(routes) repère les erreurs avant les utilisateurs.
Exercices
Exercice 1 : deux listeners, deux publics
Une équipe facturation demande à publier facturation.apps.example.com. Son namespace n'a pas l'étiquette acces-passerelle. Qu'observez-vous sur sa HTTPRoute, quelle commande l'indique, et que faites-vous pour l'autoriser sans ouvrir from: All ?
Solution
La route est refusée pour ce parent : kubectl describe httproute -n facturation affiche dans Status > Parents la condition Accepted: False avec la raison NotAllowedByListeners (le nom d'hôte, lui, est compatible). On lui donne accès en étiquetant son namespace : kubectl label namespace facturation acces-passerelle=apps. Dans un environnement géré par GitOps, l'étiquette est dans le manifeste du Namespace, relu par l'équipe plateforme : c'est précisément le contrôle voulu. La route passe à Accepted: True sans autre action.
Exercice 2 : le canari à 20 %
Écrivez la règle qui envoie 20 % du trafic vers signalements-canari et 80 % vers signalements, avec un poids exprimé en nombres entiers les plus petits possibles. Que se passe-t-il si vous mettez 80 et 20 ? Et 8 et 2 ?
Solution
backendRefs:
- name: signalements
port: 80
weight: 4
- name: signalements-canari
port: 80
weight: 1La part de chacun est son poids divisé par la somme : 4/5 et 1/5. Les poids 80 et 20, ou 8 et 2, donnent exactement la même répartition, seule la proportion compte. Écrire 80/20 est plus lisible pour un pourcentage ; 4/1 est plus compact. L'essentiel est de n'utiliser que des poids positifs et de garder une somme non nulle.
Exercice 3 : référence entre namespaces
La route supervision-signalements du namespace passerelle est Accepted: True, mais les requêtes reçoivent une erreur. Quelle condition regardez-vous, quelle valeur attendez-vous, et quel manifeste corrige le problème ? Dans quel namespace le créez-vous ?
Solution
On regarde la condition ResolvedRefs du parent dans kubectl describe httproute supervision-signalements -n passerelle : elle est à False avec la raison RefNotPermitted. La ReferenceGrant de la section « Les concepts » règle le problème. Elle se crée dans le namespace de la cible, signalements, avec from désignant les HTTPRoute du namespace passerelle et to désignant les Services. La créer dans passerelle n'aurait aucun effet : l'autorisation doit venir du propriétaire du Service.
Récapitulatif
- Gateway API sépare GatewayClass (fournisseur), Gateway (opérateur) et routes (développeur), liées par des déclarations des deux côtés.
- Une Gateway a des listeners (port, protocole, nom d'hôte) ;
allowedRoutes(Same,All,Selector) contrôle qui peut s'y attacher. - Une référence vers un autre namespace exige une ReferenceGrant dans le namespace de la cible.
- Une règle de HTTPRoute combine
matches(ET dans une correspondance, OU entre elles),filtersetbackendRefspondérés ; la répartition parweightpermet le canari, par requête. - Dans le canal standard : timeouts, GRPCRoute, ReferenceGrant, ListenerSet, TLSRoute, TCPRoute et UDPRoute ; expérimental :
retryet la persistance de session. - Le statut dit pourquoi :
Accepted,Programmed,ResolvedRefs, avec une raison normalisée. - Traefik : les ports des listeners sont ceux de ses points d'entrée (8000, 8443), pas les ports publics.
- ingress2gateway produit un brouillon de migration à relire.
Pour aller plus loin
- La suite logique : TLS et cert-manager, qui ajoute le listener HTTPS et ses certificats.
- Pour limiter ce que la passerelle peut atteindre en aval, Les NetworkPolicies.
- Pour la panne « Gateway non programmée faute de ReferenceGrant » en situation, Diagnostiquer le réseau d'un cluster.
- La documentation de Gateway API, en particulier ses pages sur les rôles, les GEP et la matrice d'implémentations et leur niveau de conformité.
- Les notes de version de Gateway API (1.2, 1.4, 1.5, 1.6) pour suivre les graduations vers le canal standard.
- Le cours Sécurité de Kubernetes pour les droits RBAC sur ces objets.
- Glossaire : Gateway API, HTTPRoute, Ingress.
Sources
- Gateway API, notes de version v1.2.0 à v1.6.0 (graduations par canal)
- Gateway API, modèle de ressources et rôles
- Gateway API, ReferenceGrant
- Gateway API, schémas des CRD du canal standard et du canal expérimental, version 1.6.2
- Traefik, fournisseur Kubernetes Gateway API
- traefik/traefik-helm-chart, values.yaml (version 41.6.1)
- kubernetes-sigs/ingress2gateway, README
- Kubernetes, documentation de Gateway API