Aller au contenu
Retour aux Tutoriels

Comment mettre en place une AI Gateway sur Kubernetes pour les charges de travail d'inférence

Intermédiaire · 1 hour · 26 min de lecture · Byte Smith ·

Avant de commencer

  • Un cluster Kubernetes avec un contrôleur compatible Gateway API installé
  • Au moins un service d'inférence ou endpoint de modèle déjà déployé
  • Un accès au cluster avec les permissions de créer des Namespaces, des ressources Gateway API et des NetworkPolicies
  • Une stack d'observabilité de base comme Prometheus, OpenTelemetry ou des métriques natives du contrôleur
  • Un environnement de staging ou un namespace isolé où vous pouvez tester des scénarios de burst et de défaillance

Ce que vous apprendrez

  • Identifier quels patterns de trafic IA nécessitent un comportement de gateway différent
  • Concevoir une AI gateway v1 minimale sans surengineering
  • Déployer une couche d'entrée Gateway API basique pour les services d'inférence
  • Ajouter le routage par version de modèle, les limites par tenant et les contrôles de déploiement progressif
  • Appliquer des timeouts, une réflexion sur la contrepression et l'observabilité pour le trafic d'inférence
  • Sécuriser la gateway avec des limites de namespace, réseau et audit
  • Tester la conception avec du trafic en rafale, des requêtes mixtes et des défaillances contrôlées
1
2
3
4
5
6
7
8
9
10
Sur cette page

Le trafic IA n’est pas simplement du “trafic API normal avec du JSON plus volumineux.” Les requêtes d’inférence sont souvent plus coûteuses, plus sensibles à la latence, plus longues et plus variables que le trafic web standard. Les réponses en streaming maintiennent les connexions ouvertes. Les agents avec appel d’outils génèrent des rafales de requêtes plus petites. L’inférence par lots peut ressembler à du débit en arrière-plan plutôt qu’à de la latence interactive. Et dans de nombreux environnements, la gateway devient aussi l’endroit où le contrôle d’accès aux modèles, la maîtrise des coûts et les limites entre tenants commencent à compter.

C’est pourquoi les équipes plateforme Kubernetes devraient s’en préoccuper maintenant. Le Kubernetes AI Gateway Working Group a été lancé spécifiquement pour définir des standards et bonnes pratiques pour l’infrastructure réseau qui supporte les charges de travail IA, et le projet officiel Gateway API Inference Extension travaille déjà sur le routage orienté modèle, la sélection d’endpoints et d’autres patterns spécifiques à l’inférence au-dessus de Gateway API. En d’autres termes, ce n’est plus seulement une catégorie de produit spécifique à un fournisseur. Cela devient une préoccupation de plateforme Kubernetes.

Ce tutoriel montre comment construire une AI gateway v1 pratique sur Kubernetes sans prétendre que les standards sont plus matures qu’ils ne le sont. Vous allez mettre en place une couche d’entrée Gateway API basique, router les requêtes vers les services d’inférence, ajouter des patterns orientés version de modèle et tenant, ajuster les contrôles de fiabilité, ajouter l’observabilité, sécuriser la conception, puis la tester sous une charge réaliste. L’objectif n’est pas de construire la gateway d’inférence la plus avancée possible dès le premier jour. L’objectif est de construire une base de plateforme propre que vous pourrez faire évoluer en toute sécurité. Pour un contexte plus large sur la façon dont le réseau Kubernetes s’adapte aux charges de travail IA, consultez Kubernetes AI Workloads and Networking.

Étape 1 : Identifier vos types de trafic IA

Avant d’écrire la moindre règle de routage, décidez quels types de trafic d’inférence vous avez réellement. Kubernetes dispose désormais d’un effort officiel AI Gateway parce que les charges de travail IA introduisent des patterns de trafic qui nécessitent un comportement réseau différent, notamment la limitation de débit orientée tokens, l’inspection de charge utile, le routage spécifique à l’IA et les protocoles spécifiques à l’IA. Le projet d’extension d’inférence va encore plus loin et introduit des concepts comme le routage orienté modèle, les priorités de service, la sélection d’endpoints et la planification sensible à la latence basée sur les métriques du serveur de modèles.

Classifier l’inférence interactive

L’inférence interactive est ce que la plupart des équipes désignent en premier : complétions de chat, résumé, embeddings à la demande, UX d’assistant et appels similaires orientés utilisateur. Ces requêtes sont généralement sensibles à :

  • la latence de bout en bout
  • le temps jusqu’au premier token
  • la continuité du streaming
  • la sélection du modèle
  • les quotas par tenant

Si vous avez du trafic interactif, votre gateway devrait être optimisée pour un comportement de réponse prévisible et un déploiement progressif contrôlé plutôt que pour le débit maximal seul.

Classifier l’inférence par lots

L’inférence par lots est généralement différente :

  • des rafales plus importantes
  • moins de sensibilité à la latence du premier token
  • plus de tolérance à la mise en file d’attente
  • plus d’emphase sur le débit et l’équité
  • des patterns d’exécution planifiés ou asynchrones

Vous ne voulez pas ajuster toute votre gateway autour du chat interactif si la moitié de votre charge est constituée d’embeddings hors ligne ou de tâches d’enrichissement nocturnes.

Classifier les agents avec appel d’outils

Les agents avec appel d’outils produisent souvent un trafic facile à sous-estimer :

  • beaucoup de petits appels
  • des rafales après les phases de planification
  • des tentatives de reprise côté appelant si une étape d’outil échoue
  • des charges de travail mixtes à travers plusieurs modèles ou endpoints

Cela compte parce que la gateway peut nécessiter des quotas plus stricts, une conscience de l’idempotence ou une observabilité plus forte par route et par tenant.

Classifier les réponses en streaming

Le streaming d’inférence est là où les équipes rencontrent des problèmes le plus rapidement. Gateway API dispose maintenant d’un support standard pour les timeouts de route, mais le support des tentatives de reprise est encore en évolution active et est particulièrement nuancé autour des patterns de streaming ou bidirectionnels. Traitez les flux de longue durée comme une classe distincte, pas simplement comme “la même route avec un corps différent.”

Créez un simple document de classification du trafic avant de continuer.

Fichier : traffic-profile.yaml

interactive_inference:
  examples:
    - chat-completions
    - real-time-summarization
  latency_sensitive: true
  streaming: true
  retry_friendly: false

batch_inference:
  examples:
    - offline-embeddings
    - nightly-document-labeling
  latency_sensitive: false
  streaming: false
  retry_friendly: true

tool_calling_agents:
  examples:
    - planner-executor-agents
    - retrieval-agents
  latency_sensitive: mixed
  streaming: mixed
  retry_friendly: mixed

streaming_responses:
  examples:
    - server-sent-events
    - token-streaming-chat
  latency_sensitive: true
  streaming: true
  retry_friendly: false
Astuce

Gardez votre première version de la gateway opinionée sur les classes de trafic. Une route qui sert du chat à faible latence ne devrait pas hériter des mêmes hypothèses de timeout et de contrepression qu’un job d’embedding en arrière-plan.

Vous devriez maintenant avoir un profil de trafic qui vous indique quels chemins nécessitent une faible latence, lesquels peuvent tolérer la mise en file d’attente et lesquels devraient éviter entièrement les tentatives de reprise.

Étape 2 : Décider ce que la gateway doit faire

Une gateway devient désordonnée quand elle prend des responsabilités par accident. L’effort Kubernetes AI Gateway encadre explicitement les AI gateways comme une infrastructure qui peut appliquer des politiques, le contrôle d’accès, l’inspection de charge utile, la limitation orientée tokens et le routage spécifique à l’IA. Cela ne signifie pas que votre première version devrait faire toutes ces choses en même temps. Cela signifie que vous devriez décider du périmètre dès le départ.

Commencer avec un ensemble restreint de responsabilités

Pour une première release, votre AI gateway devrait généralement faire ces choses :

  • exposer un ou plusieurs points d’entrée stables
  • router les requêtes vers le bon service d’inférence
  • isoler les tenants ou environnements
  • appliquer des limites basiques d’auth et d’admission
  • émettre des logs et métriques fiables
  • supporter les déploiements progressifs de modèles en toute sécurité

Ce qu’elle ne devrait généralement pas faire en v1 :

  • effectuer une inspection sémantique complète des prompts en ligne
  • devenir votre seul système de quotas
  • implémenter tous les patterns de fallback de fournisseurs
  • masquer tout le comportement du serveur de modèles à l’équipe applicative

Définir les dimensions de routage

La plupart des équipes ont besoin d’une ou plusieurs de celles-ci :

  • router par famille de modèle comme chat versus embeddings
  • router par version de modèle comme v1 versus v2
  • router par tenant en utilisant des hostnames, chemins ou headers
  • router par classe de trafic comme interactif versus batch

Mettez la politique par écrit. Ne la laissez pas dans des valeurs Helm ou des défauts de contrôleur.

Fichier : ai-gateway-responsibilities.yaml

entrypoints:
  - tenant-hostnames
  - shared-api-domain

routing_dimensions:
  - route_by_path
  - route_by_model_version
  - route_by_tenant

required_controls:
  - authn
  - authz
  - request_logging
  - per_route_timeouts
  - rollout_support

deferred_for_v2:
  - semantic_payload_inspection
  - provider_failover
  - token_based_rate_limiting
  - body_based_model_routing

Décider si la gateway ou un service routeur possède la sélection de modèle

C’est l’une des décisions de conception les plus importantes.

Si vos clients appellent des endpoints distincts comme /v1/chat/completions et /v1/embeddings, l’HTTPRoute standard suffit pour une bonne conception v1. Si vos clients envoient une requête compatible OpenAI où le nom du modèle est uniquement dans le corps de la requête, Gateway API standard seul ne suffit pas pour le routage orienté modèle. C’est précisément pourquoi le projet d’extension d’inférence introduit le routage basé sur le corps et les patterns de sélection d’endpoints.

Pour la v1, choisissez l’une de ces options :

  • Routage simple par chemin ou hostname si votre surface API sépare déjà proprement les charges de travail
  • Un service routeur interne léger si le nom du modèle n’existe que dans le corps et que vous voulez garder l’API externe stable
  • Une extension orientée inférence plus tard, si le routage basé sur le corps en vaut la complexité
Note

Si votre API est compatible OpenAI et que le nom du modèle est dans le corps JSON, ne prétendez pas que de simples règles Gateway basées sur les chemins peuvent résoudre le routage orienté modèle par elles-mêmes.

Vous devriez maintenant savoir ce que votre gateway possède, ce qu’elle ne possède pas, et si le choix de modèle se fait dans des règles Gateway standard, dans un service routeur ou dans une couche orientée inférence plus avancée ultérieurement.

Étape 3 : Déployer une couche gateway basique

Le point de départ le plus propre est un Gateway partagé dans un namespace de plateforme, des services de modèles dans un namespace de service de modèles, et des routes de tenants dans des namespaces de tenants. Gateway API est conçu pour ce type de séparation, et le routage cross-namespace est un pattern de première classe. Quand une route pointe vers un backend dans un autre namespace, le namespace cible doit explicitement le permettre avec un ReferenceGrant.

Créer des namespaces et des labels

Fichier : namespaces.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: ai-gateway
---
apiVersion: v1
kind: Namespace
metadata:
  name: ai-models
---
apiVersion: v1
kind: Namespace
metadata:
  name: tenant-a
  labels:
    ai-routes: "enabled"

Appliquez-les :

kubectl apply -f namespaces.yaml

Créer le Gateway partagé

Cet exemple suppose que votre contrôleur a déjà installé une GatewayClass. Remplacez your-gateway-class par le vrai nom de classe de votre environnement.

Fichier : gateway.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: ai-shared-gateway
  namespace: ai-gateway
spec:
  gatewayClassName: your-gateway-class
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "*.ai.example.com"
      tls:
        mode: Terminate
        certificateRefs:
          - name: ai-example-com-tls
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              ai-routes: "enabled"

Appliquez-le :

kubectl apply -f gateway.yaml
kubectl get gateway -n ai-gateway

Exposer vos services d’inférence

Ce tutoriel suppose que vous avez déjà des Deployments de service de modèles en cours d’exécution. Créez des Services stables pour eux.

Fichier : model-services.yaml

apiVersion: v1
kind: Service
metadata:
  name: chat-llama3-8b-v1
  namespace: ai-models
spec:
  selector:
    app: chat-llama3-8b-v1
  ports:
    - name: http
      port: 8000
      targetPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: embed-bge-small-v1
  namespace: ai-models
spec:
  selector:
    app: embed-bge-small-v1
  ports:
    - name: http
      port: 8000
      targetPort: 8000

Appliquez-le :

kubectl apply -f model-services.yaml

Autoriser les références de backend cross-namespace

Parce que l’HTTPRoute sera dans tenant-a et les backends dans ai-models, vous avez besoin d’un ReferenceGrant dans le namespace du backend.

Fichier : referencegrant.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
  name: allow-tenant-a-routes
  namespace: ai-models
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: tenant-a
  to:
    - group: ""
      kind: Service

Appliquez-le :

kubectl apply -f referencegrant.yaml

Créer l’HTTPRoute initial

Fichier : tenant-a-routes.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tenant-a-inference
  namespace: tenant-a
spec:
  parentRefs:
    - name: ai-shared-gateway
      namespace: ai-gateway
      sectionName: https
  hostnames:
    - "tenant-a.ai.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v1/chat/completions
      backendRefs:
        - name: chat-llama3-8b-v1
          namespace: ai-models
          port: 8000
    - matches:
        - path:
            type: PathPrefix
            value: /v1/embeddings
      backendRefs:
        - name: embed-bge-small-v1
          namespace: ai-models
          port: 8000

Appliquez-le et vérifiez :

kubectl apply -f tenant-a-routes.yaml
kubectl get httproute -n tenant-a
kubectl describe httproute tenant-a-inference -n tenant-a
Info

Utilisez HTTPRoute pour les API HTTP ou compatibles OpenAI, et GRPCRoute quand votre chemin de service est véritablement natif gRPC. Les deux sont GA, mais gardez gRPC et HTTP classique sur des hostnames séparés quand c’est possible pour des opérations plus propres.

Vous devriez maintenant avoir une AI gateway partagée basique, deux Services de modèles, et une route de tenant qui transfère le trafic de chat et d’embeddings via Gateway API.

Étape 4 : Ajouter le routage orienté IA

Maintenant que la base fonctionne, ajoutez les types de routage qui comptent spécifiquement pour l’inférence. Le projet officiel d’extension d’inférence se concentre sur le routage orienté modèle, la priorité de service, les déploiements progressifs et la sélection d’endpoints basée sur les métriques du serveur de modèles comme l’état du cache et la profondeur de file d’attente. C’est la direction à long terme. Pour la v1, restez plus simple : utilisez Gateway API pour le déploiement progressif de version de modèle et les limites de tenant d’abord, et n’introduisez le routage basé sur le corps ou la sélection d’endpoints que quand vous avez un besoin clair.

Ajouter le routage canary par version de modèle

Gateway API supporte la répartition de trafic pondérée via backendRefs, ce qui en fait un bon choix pour les déploiements progressifs de modèles.

Fichier : tenant-a-chat-canary.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tenant-a-chat-canary
  namespace: tenant-a
spec:
  parentRefs:
    - name: ai-shared-gateway
      namespace: ai-gateway
      sectionName: https
  hostnames:
    - "tenant-a.ai.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v1/chat/completions
      backendRefs:
        - name: chat-llama3-8b-v1
          namespace: ai-models
          port: 8000
          weight: 90
        - name: chat-llama3-8b-v2
          namespace: ai-models
          port: 8000
          weight: 10

C’est la manière la plus propre de faire des déploiements progressifs de modèles quand l’API externe reste la même et que seule l’implémentation de service change.

Ajouter l’isolation de tenant par hostname ou propriété de route

Les recommandations de multi-tenancy Kubernetes préconisent les limites de namespace, RBAC, quotas et network policies comme contrôles fondamentaux pour les clusters partagés. En pratique, le modèle d’isolation AI gateway le plus simple est :

  • un Gateway partagé
  • un namespace propriétaire de route par tenant ou équipe applicative
  • un namespace de service de modèles ou des namespaces de modèles par tenant si nécessaire
  • un ReferenceGrant explicite là où l’accès cross-namespace est autorisé

Cela garde la propriété du routage des tenants séparée des points d’entrée appartenant à la plateforme.

Garder le fallback simple en v1

Le vrai fallback d’inférence est plus subtil qu’un failover HTTP normal. Vous pourriez vouloir basculer d’une version de modèle à une autre, d’un pool à un autre, ou de l’inférence auto-hébergée à un fournisseur externe. Les propositions d’egress actives du AI Gateway Working Group visent explicitement les services IA externes, le failover, le routage de conformité et l’injection sécurisée de tokens, ce qui vous indique que c’est encore un domaine de standard en évolution.

Pour la v1, utilisez l’une de ces options :

  • un service routeur dédié derrière votre Gateway pour une logique de fallback complexe
  • une route spécifique au modèle avec une répartition canary contrôlée
  • une extension d’inférence spécifique à l’implémentation si vous vous êtes déjà engagé sur cette stack

Un pattern propre est de garder la route publique stable et d’envoyer la logique de fallback complexe vers un service routeur interne :

Fichier : tenant-a-chat-router.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tenant-a-chat-router
  namespace: tenant-a
spec:
  parentRefs:
    - name: ai-shared-gateway
      namespace: ai-gateway
      sectionName: https
  hostnames:
    - "tenant-a.ai.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v1/chat/completions
      backendRefs:
        - name: llm-router
          namespace: tenant-a
          port: 8080

Ce routeur peut prendre des décisions de fallback orientées politique sans forcer chaque préoccupation d’inférence dans du YAML Gateway.

Astuce

Gateway API excelle dans les points d’entrée stables, les répartitions de trafic pour déploiement progressif et les limites de propriété. Utilisez-le pour cela d’abord. N’ajoutez le routage basé sur le corps ou la sélection d’endpoints que quand votre trafic en a vraiment besoin.

Vous devriez maintenant avoir un moyen de faire un déploiement progressif de version de modèle en toute sécurité, un pattern clair d’isolation de tenant, et une position réaliste v1 sur la logique de fallback.

Étape 5 : Ajouter des contrôles de fiabilité

Le trafic d’inférence échoue différemment d’une API CRUD normale. Certaines requêtes sont coûteuses et de longue durée. Certains flux ne devraient jamais être retentés automatiquement. Certains serveurs de modèles mettent en file d’attente en interne avant de répondre. Cela signifie que la fiabilité est un mélange de paramètres de gateway et de comportement du serveur de modèles.

Définir des timeouts de route explicites

Gateway API fournit désormais des champs de timeout de route standard sur les règles HTTPRoute. Utilisez-les. Ne laissez pas les chemins d’inférence critiques entièrement aux défauts du contrôleur.

Fichier : tenant-a-route-timeouts.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tenant-a-inference-with-timeouts
  namespace: tenant-a
spec:
  parentRefs:
    - name: ai-shared-gateway
      namespace: ai-gateway
      sectionName: https
  hostnames:
    - "tenant-a.ai.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v1/chat/completions
      timeouts:
        request: 120s
        backendRequest: 115s
      backendRefs:
        - name: chat-llama3-8b-v1
          namespace: ai-models
          port: 8000
    - matches:
        - path:
            type: PathPrefix
            value: /v1/embeddings
      timeouts:
        request: 30s
        backendRequest: 25s
      backendRefs:
        - name: embed-bge-small-v1
          namespace: ai-models
          port: 8000

Ces chiffres sont des exemples. Les bonnes valeurs dépendent de vos modèles et des attentes de vos utilisateurs. Le point important est que chat et embeddings ne devraient pas hériter de la même politique de timeout aveuglément.

Être conservateur avec les retries

Le travail sur les retries Gateway existe, mais c’est encore un domaine où la sémantique varie et le streaming est particulièrement délicat. Pour le chat en streaming, par défaut ne faites pas de retries automatiques de gateway à moins d’avoir explicitement testé le comportement de bout en bout. Pour les requêtes idempotentes non-streaming comme certaines charges de travail d’embedding, des retries limités peuvent être acceptables si votre implémentation les supporte et que la sémantique de votre backend est sûre.

Ajouter les bases de fiabilité du backend

Ne vous concentrez pas uniquement sur la gateway. Vos charges de travail de service de modèles ont aussi besoin d’un comportement de disruption stable.

Fichier : chat-pdb.yaml

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: chat-llama3-8b-v1
  namespace: ai-models
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: chat-llama3-8b-v1

Cela ne résoudra pas la surcharge, mais cela vous protège contre les disruptions volontaires évitables pendant la maintenance.

Décider où vivent la mise en file d’attente et la contrepression

Pour la v1, la règle la plus sûre est :

  • Gateway : appliquer les limites au niveau de la connexion et de la route
  • Serveur de modèles ou routeur : posséder les décisions de mise en file d’attente et de délestage de requêtes
  • Autoscaling : réagir aux signaux de demande réels quand c’est possible

Si votre stack supporte plus tard la visibilité de file d’attente orientée inférence ou la sélection d’endpoints, vous pouvez évoluer vers cela. Le projet d’extension d’inférence est spécifiquement construit autour de la sélection d’endpoints et des métriques du serveur de modèles comme la longueur de file d’attente et l’état du cache, ce qui est un signal fort que l’équilibrage de charge L7 générique n’est pas suffisant pour les charges de travail d’inférence matures.

Attention

N’activez pas les retries sur les routes en streaming juste parce que votre contrôleur supporte les retries quelque part. Les échecs en streaming nécessitent souvent une récupération consciente de l’appelant, pas un rejeu aveugle.

Vous devriez maintenant avoir des timeouts explicites, une position conservatrice sur les retries, et une séparation claire entre les contrôles de fiabilité de la gateway et le comportement de contrepression du serveur de modèles.

Étape 6 : Ajouter l’observabilité

Une AI gateway sans observabilité devient un amplificateur de coûts et un goulot d’étranglement de débogage. Au minimum, vous voulez comprendre :

  • le volume de requêtes
  • la latence des requêtes
  • le taux d’erreur
  • la distribution par tenant
  • la distribution par modèle
  • streaming versus non-streaming
  • les signaux de tokens et de coût quand disponibles

Le travail officiel d’extension d’inférence met aussi en évidence les métriques du serveur de modèles, les objectifs de type time-to-first-token et les décisions de planification orientées modèle, ce qui est un bon signal de ce que l’observabilité mature devra inclure.

Standardiser un contrat de log de gateway

Même si votre pipeline de métriques exact change plus tard, définissez un contrat de log structuré maintenant.

Fichier : gateway-log-example.json

{
  "timestamp": "2026-03-10T15:22:11.418Z",
  "request_id": "req_01JPN8XQZ0Y1M0AX3R0D4M9J7E",
  "tenant": "tenant-a",
  "hostname": "tenant-a.ai.example.com",
  "route": "/v1/chat/completions",
  "model_route": "chat-llama3-8b-v1",
  "stream": true,
  "http_status": 200,
  "latency_ms": 1840,
  "ttft_ms": 420,
  "prompt_tokens": 612,
  "completion_tokens": 238,
  "estimated_cost_usd": 0.0194,
  "gateway_backend": "chat-llama3-8b-v1.ai-models.svc.cluster.local:8000"
}

Si vous ne pouvez pas obtenir chaque champ dès le premier jour, ce n’est pas grave. Mais tenant, route, backend, status, latence et streaming/non-streaming devraient être présents dès le départ.

Créer des règles d’enregistrement pour les métriques possédées

Si vous opérez un routeur personnalisé ou une couche d’adaptation, exportez vos propres métriques avec des noms et labels stables.

Fichier : prometheus-rules.yaml

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: ai-gateway-recording-rules
  namespace: ai-gateway
spec:
  groups:
    - name: ai-gateway.rules
      rules:
        - record: ai_gateway:requests_per_second
          expr: sum(rate(ai_gateway_requests_total[5m])) by (tenant, route, model_route)
        - record: ai_gateway:error_rate
          expr: sum(rate(ai_gateway_requests_total{status=~"5.."}[5m])) by (tenant, route, model_route)
        - record: ai_gateway:p95_latency_ms
          expr: histogram_quantile(0.95, sum(rate(ai_gateway_request_duration_ms_bucket[5m])) by (le, tenant, route, model_route))

Ce sont des exemples de noms de métriques pour votre adaptation ou télémétrie de gateway. La source exacte peut être votre contrôleur, votre service routeur, ou les deux.

Suivre les métriques de gateway et de backend séparément

Gardez ces catégories distinctes :

  • latence de requête de la gateway
  • latence du modèle backend
  • profondeur de file d’attente
  • saturation ou délestage
  • débit de tokens
  • coût ou coût estimé
  • taux de succès par modèle

Si vous fusionnez tout dans un seul nombre de “latence IA”, vous ne saurez pas si le problème vient du routage, du contrôleur, du serveur de modèles ou de la pression GPU en amont.

Info

L’observabilité de l’inférence n’est pas juste de l’observabilité HTTP. Vous avez besoin de suffisamment de contexte pour répondre : quel tenant, quelle route, quel modèle, quelle latence, combien de tokens, et combien cela a coûté.

Vous devriez maintenant avoir un plan d’observabilité structuré qui couvre le comportement de la gateway, le comportement du modèle et la visibilité des coûts au niveau du tenant ou du modèle.

Étape 7 : Sécuriser

Votre AI gateway est à la fois une frontière réseau et une frontière de politique. Cela en fait un endroit naturel pour appliquer l’accès, la séparation des tenants et la visibilité d’audit. Les recommandations de multi-tenancy Kubernetes elles-mêmes soulignent les namespaces, RBAC, quotas et network policies comme blocs de construction fondamentaux pour isoler les tenants et éviter les problèmes de voisin bruyant ou de surpermission dans les clusters partagés.

Isoler les services de modèles du reste du cluster

Ne laissez pas chaque charge de travail appeler directement votre namespace de service de modèles. Utilisez une NetworkPolicy pour que seul le namespace de la gateway puisse atteindre les pods de service de modèles.

Fichier : model-networkpolicy.yaml

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: only-gateway-to-models
  namespace: ai-models
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ai-gateway
      ports:
        - protocol: TCP
          port: 8000

Appliquez-la :

kubectl apply -f model-networkpolicy.yaml

Mettre les budgets des tenants quelque part d’explicite

Les quotas de requêtes ou de tokens sont souvent spécifiques au contrôleur ou à l’application, mais vous devriez quand même isoler la consommation de ressources des tenants au niveau du namespace.

Fichier : tenant-a-quota.yaml

apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-a-ai-quota
  namespace: tenant-a
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 64Gi
    limits.cpu: "40"
    limits.memory: 128Gi
    pods: "50"

Ce n’est pas un quota de requêtes par minute. C’est une frontière d’équité de cluster. Gardez les quotas au niveau du trafic dans votre couche gateway ou routeur, mais n’oubliez pas l’équité au niveau du cluster.

Rendre l’auth et l’audit explicites

L’authentification et l’autorisation au niveau de la gateway dépendront de votre implémentation. Certaines stacks utiliseront l’attachement de politique JWT ou mTLS. D’autres utiliseront des services d’auth externes. Votre base minimale sécurisée devrait quand même être la même :

  • authentifier les appelants avant l’accès à l’inférence
  • autoriser par tenant et route
  • logger qui a appelé quoi
  • éviter de passer du contenu de prompt brut sensible dans des logs larges
  • enregistrer suffisamment de métadonnées d’audit pour reconstruire l’accès plus tard

Un simple contrat d’audit suffit pour commencer.

Fichier : audit-log-example.json

{
  "timestamp": "2026-03-10T15:40:02.112Z",
  "tenant": "tenant-a",
  "subject": "svc:agent-platform",
  "route": "/v1/chat/completions",
  "model_route": "chat-llama3-8b-v1",
  "decision": "allow",
  "request_id": "req_01JPN92C7S49YJ1E0QY6T5G6P3",
  "sensitive_payload_logged": false
}

Protéger les données sensibles de prompt et de réponse

Pour la v1, gardez cela simple :

  • ne loggez pas les prompts complets par défaut
  • ne loggez pas les réponses streamées complètes par défaut
  • masquez les secrets ou identifiants évidents dans le middleware quand c’est possible
  • réservez l’inspection de charge utile pour des cas d’utilisation de politique explicites

Le AI Gateway Working Group travaille activement sur des propositions de traitement de charge utile et de garde-fous pour le trafic IA, ce qui est un indicateur fort que l’inspection inline de prompt/réponse est un vrai territoire de plateforme, mais c’est encore un domaine de standard émergent. Ne le surdimensionnez pas dès le premier jour.

Attention

Votre gateway devrait être capable de répondre “qui a appelé quelle route de modèle et que s’est-il passé” sans stocker des prompts ou réponses entiers dans des logs à usage général.

Vous devriez maintenant avoir une isolation réseau autour des services de modèles, des frontières de tenant au niveau du namespace, et un point de départ clair pour les contrôles d’auth et d’audit.

Étape 8 : Tester avec une charge de travail réaliste

Maintenant validez la conception dans des conditions qui ressemblent plus à la production. Le trafic IA est rarement uniforme. Vous voulez du trafic en rafale, des routes mixtes, du streaming et au moins une défaillance de backend.

Envoyer du trafic en rafale vers une route non-streaming

Créez une charge utile d’embeddings.

Fichier : embeddings.json

{
  "input": [
    "hello world",
    "design a safe ai gateway on kubernetes",
    "measure latency, error rate, and cost"
  ],
  "model": "bge-small"
}

Exécutez un test en rafale :

export GATEWAY_ADDR=http://YOUR_GATEWAY_ADDRESS
hey -n 200 -c 20 \
  -m POST \
  -T application/json \
  -H "Host: tenant-a.ai.example.com" \
  -D embeddings.json \
  ${GATEWAY_ADDR}/v1/embeddings

Cela valide la gestion des rafales sur une route qui est généralement plus sûre à retenter et plus facile à comparer entre les exécutions.

Tester le comportement de streaming explicitement

Créez une requête en streaming.

Fichier : chat-stream.json

{
  "model": "llama3-8b",
  "stream": true,
  "messages": [
    { "role": "user", "content": "Explain why AI gateways need different timeout and routing rules." }
  ]
}

Exécutez-la :

curl -N \
  -H "Host: tenant-a.ai.example.com" \
  -H "Content-Type: application/json" \
  -X POST \
  --data @chat-stream.json \
  ${GATEWAY_ADDR}/v1/chat/completions

Surveillez :

  • le temps jusqu’au premier token
  • la continuité régulière du flux
  • les déconnexions prématurées
  • les surprises de buffering du proxy
  • le comportement incorrect de timeout

Mixer les routes et types de trafic

Une simple boucle shell suffit pour une première validation.

for i in $(seq 1 20); do
  curl -s \
    -H "Host: tenant-a.ai.example.com" \
    -H "Content-Type: application/json" \
    -X POST \
    --data @embeddings.json \
    ${GATEWAY_ADDR}/v1/embeddings > /dev/null &

  curl -s \
    -H "Host: tenant-a.ai.example.com" \
    -H "Content-Type: application/json" \
    -X POST \
    --data @chat-stream.json \
    ${GATEWAY_ADDR}/v1/chat/completions > /dev/null &
done

wait

Ce n’est pas un benchmark parfait. C’est suffisant pour révéler les inadéquations de routes, la saturation et les comportements par défaut médiocres.

Injecter une défaillance de backend

Maintenant prouvez que vos timeouts, votre répartition de déploiement progressif et votre observabilité se comportent comme vous le pensez.

kubectl -n ai-models scale deployment chat-llama3-8b-v2 --replicas=0
kubectl -n ai-models get pods -w

Puis envoyez à nouveau du trafic et observez :

  • est-ce que la route canary a échoué uniquement pour la part canary
  • est-ce que la gateway a retourné les bonnes erreurs
  • est-ce que les logs ont identifié clairement le backend
  • est-ce que les routes en streaming sont restées accrochées plus longtemps que prévu
  • est-ce que vos métriques ont séparé la défaillance de la gateway de la défaillance du backend
Astuce

N’appelez pas une gateway prête pour la production tant que vous ne l’avez pas vue gérer une rafale, un flux et un backend défaillant dans le même environnement.

Vous devriez maintenant avoir la preuve que la gateway fonctionne sous charge en rafale, utilisation mixte de routes et défaillance contrôlée, au lieu de seulement sous des tests curl en chemin heureux.

Problèmes courants de configuration

Traiter l’AI gateway comme un ingress ordinaire

Symptômes :

  • un timeout générique unique pour tout
  • aucune distinction entre chat et embeddings
  • les routes en streaming s’interrompent de manière inattendue
  • le comportement de déploiement progressif est trop grossier

Cause racine : la gateway a été conçue comme un ingress web normal au lieu d’une couche d’entrée d’inférence.

Correction : classifiez d’abord les types de trafic, séparez les routes interactives et batch, et traitez le streaming comme sa propre classe.

Essayer de router par nom de modèle sans couche orientée modèle

Symptômes :

  • les clients envoient le modèle dans le corps de la requête
  • les règles Gateway ne peuvent pas sélectionner correctement les backends
  • les équipes commencent à coder en dur des variantes de chemins maladroites

Cause racine : les règles Gateway standard ne parsent pas les corps JSON pour le routage par elles-mêmes.

Correction : gardez la v1 basée sur les chemins ou hostnames, ajoutez un service routeur léger, ou adoptez délibérément une extension orientée inférence plus tard.

ReferenceGrant manquant pour les backends cross-namespace

Symptômes :

  • l’HTTPRoute existe mais ne peut pas résoudre les refs de backend
  • le trafic n’atteint jamais les services de modèles

Cause racine : le namespace de la route peut voir le Gateway partagé, mais le namespace du backend n’a jamais accordé l’accès de référence cross-namespace.

Correction : ajoutez un ReferenceGrant dans le namespace du backend pour le namespace source et le kind spécifiques.

Retries activés sur les routes en streaming

Symptômes :

  • des sorties partielles dupliquées
  • un comportement client étrange pendant les défaillances
  • des taux de succès trompeurs

Cause racine : la logique de retry a été appliquée comme si le trafic en streaming se comportait comme des requêtes idempotentes courtes.

Correction : désactivez ou contraignez fortement les retries sur les routes en streaming, et laissez l’appelant gérer le rejeu quand c’est nécessaire.

Pas de labels de tenant ou de modèle dans les logs et métriques

Symptômes :

  • la latence semble mauvaise, mais personne ne sait pour qui
  • les coûts augmentent, mais il n’y a pas de visibilité au niveau de la route
  • les problèmes de déploiement progressif sont difficiles à localiser

Cause racine : l’observabilité a été ajoutée comme télémétrie HTTP générique uniquement.

Correction : loggez et labellisez par tenant, route, backend, route de modèle et flag streaming dès le premier jour.

Conclusion

Une bonne AI gateway v1 sur Kubernetes n’est pas une énorme plateforme personnalisée. C’est une couche d’entrée Gateway API propre avec une propriété explicite, des routes stables, des contrôles de déploiement progressif sûrs, une isolation solide et suffisamment d’observabilité pour comprendre la latence, les défaillances et les coûts. Gardez la première version simple : séparez les classes de trafic, routez clairement, isolez les tenants, définissez des timeouts explicites et vérifiez le comportement avec du trafic réel.

Passez à une architecture plus avancée quand vous en avez vraiment besoin : routage de modèle basé sur le corps, sélection d’endpoints basée sur les métriques du serveur de modèles, failover de fournisseur externe, limitation orientée tokens ou traitement inline de charge utile. Le Kubernetes AI Gateway Working Group et le projet Gateway API Inference Extension montrent clairement que ces patterns deviennent des préoccupations de plateforme de première classe, mais ils sont encore en évolution. C’est exactement pourquoi une v1 simple et bien structurée est le bon point de départ.