Gateway API: Remplacer mon Ingress Controller avec Cilium?

Sommaire

Lorsque l'on déploie une application sur Kubernetes, l'étape suivante consiste généralement à l'exposer aux utilisateurs. On utilise habituellement des "Ingress controllers", comme Nginx, Haproxy, Traefik ou encore ceux des différents Clouders afin de diriger le trafic entrant vers l'application, gérer l'équilibrage de charge, la terminaison TLS et j'en passe.

Il faut alors choisir parmi la pléthore d'options disponibles 🤯 la solution qui sera en charge de tous ces aspects et Cilium est, depuis relativement récemment, l'une d'entre elles.

Cilium est une solution Open-Source de connectivité réseau et de sécurité basée sur eBPF dont l'adoption est grandissante. Il s'agit probablement du plugin réseau qui fournit le plus de fonctionnalités. Nous n'allons pas toutes les parcourir mais l'une d'entre elles consiste à gérer le trafic entrant en utilisant le standard Gateway API (GAPI).

🎯 Notre objectif

  • Comprendre ce qu'est exactement Gateway API et en quoi il s'agit d'une évolution par rapport à l'API Ingress.
  • Démonstrations de cas concrets à la sauce GitOps.
  • Les limitations actuelles et les évolutions à venir.
Tip

Toutes les étapes réalisées dans cet article proviennent de ce dépôt git

Je vous invite à le parcourir car, il va bien au delà du contexte de cet article:

  • Installation d'un cluster EKS avec Cilium configuré en mode sans kube-proxy et un Daemonset dédié à Envoy
  • Proposition de structure de configuration Flux avec une gestion des dépendances et une factorisation que je trouve efficaces.
  • Crossplane et composition IRSA qui simplifie la gestion des permissions IAM pour les composants plateforme
  • Gestion des noms de domaine ainsi que des certificats automatisés avec External-DNS et Let's Encrypt

L'idée étant d'avoir l'ensemble configuré au bout de quelques minutes, en une seule ligne de commande 🤩.

☸ Introduction à Gateway API

Comme évoqué précédemment, il y a de nombreuses options qui font office d' Ingress controller et chacune a ses propres spécificités et des fonctionnalités particulières, rendant leur utilisation parfois complexe. Par ailleurs, l'API Ingress, utilisée historiquement dans Kubernetes possède très peu d'options. Certaines solutions ont d'ailleurs créé des CRDs (Ressources personalisées) quand d'autres font usage des annotations pour lever ces limites.

C'est dans ce contexte que Gateway API fait son apparition. Il s'agit d'un standard qui permet de définir des fonctionnalités réseau avancées sans nécessiter d'extensions spécifiques au contrôleur sous-jacent. De plus étant donné que tous les contrôleurs utilisent la même API , il est possible de passer d'une solution à une autre sans changer de configuration (les ressources qui gèrent le trafic entrant restent les mêmes).

Parmi les concepts que nous allons explorer la GAPI introduit un schéma de répartition des responsabilités. Elle définit des roles explicites avec des permissions bien distinctes. (Plus d'informations sur le modèle de sécurité GAPI ici).

Enfin il est important de noter que ce projet est dirigé par le groupe de travail sig-network-kubernetes et un canal slack vous permettra de les solliciter si nécessaire.

Voyons comment cela s'utilise concrètement 🚀!

☑️ Prérequis

Pour le reste de cet article nous considérons qu'un cluster EKS a été déployé. Si vous n'utilisez pas la méthode proposée dans le repo de démo servant de socle à cet article, il y a certains points à valider pour que GAPI puisse être utilisé.

ℹ️ La méthode d'installation decrite ici se base sur Helm, l'ensemble des values peuvent être consultées ici.

  • Installer les CRDs (resources personnalisés) disponibles dans le repository Gateway API

    Note

    Si Cilium est configuré avec le support GAPI (voir ci-dessous) et que les CRDs sont absentes, il ne démarrera pas.

    Dans le repo de demo les CRDs GAPI sont installées une première fois lors de la création du cluster afin que Cilium puisse démarrer puis elles sont ensuite gérées par Flux.

  • Remplacer kube-proxy par les fonctionnalités de transfert réseau apportées par Cilium et eBPF.

1kubeProxyReplacement: true
  • Activer le support de Gateway API
1gatewayAPI:
2  enabled: true
  • Vérifier L'installation Il faut pour cela installer le client en ligne de commande cilium. J'utilise personnellement asdf pour cela:

    1asdf plugin-add cilium-cli
    2asdf install cilium-cli 0.15.7
    3asdf global cilium 0.15.7
    

    La commande suivante permet de s'assurer que tous les composants sont démarrés et opérationnels

     1cilium status --wait
     2   /¯¯\
     3/¯¯\__/¯¯\    Cilium:             OK
     4\__/¯¯\__/    Operator:           OK
     5/¯¯\__/¯¯\    Envoy DaemonSet:    OK
     6\__/¯¯\__/    Hubble Relay:       disabled
     7   \__/       ClusterMesh:        disabled
     8
     9Deployment             cilium-operator    Desired: 2, Ready: 2/2, Available: 2/2
    10DaemonSet              cilium             Desired: 2, Ready: 2/2, Available: 2/2
    11DaemonSet              cilium-envoy       Desired: 2, Ready: 2/2, Available: 2/2
    12Containers:            cilium             Running: 2
    13                      cilium-operator    Running: 2
    14                      cilium-envoy       Running: 2
    15Cluster Pods:          33/33 managed by Cilium
    16Helm chart version:    1.14.2
    17Image versions         cilium             quay.io/cilium/cilium:v1.14.2@sha256:6263f3a3d5d63b267b538298dbeb5ae87da3efacf09a2c620446c873ba807d35: 2
    18                      cilium-operator    quay.io/cilium/operator-aws:v1.14.2@sha256:8d514a9eaa06b7a704d1ccead8c7e663334975e6584a815efe2b8c15244493f1: 2
    19                      cilium-envoy       quay.io/cilium/cilium-envoy:v1.25.9-e198a2824d309024cb91fb6a984445e73033291d@sha256:52541e1726041b050c5d475b3c527ca4b8da487a0bbb0309f72247e8127af0ec: 2
    

    Enfin le support de GAPI peut être vérifié comme suit

    1cilium config view | grep -w "enable-gateway-api"
    2enable-gateway-api                                true
    3enable-gateway-api-secrets-sync                   true
    

    Il est aussi possible de lancer des tests de connectivité pour s'assurer qu'il n'y a pas de problèmes avec la configuration réseau du cluster:

    1cilium connectivity test
    

    ⚠️ Cette commande (connectivity test) provoque actuellement des erreurs lors de l'activation d'Envoy en tant que DaemonSet. (Issue Github).

Info

as DaemonSet

Par défaut l'agent cilium intégre Envoy et lui délegue les opérations réseau de niveau 7. Depuis la version v1.14, il est possible de déployer Envoy séparément ce qui apporte certains avantages:

  • Si l'on modifie/redémarre un composant (que ce soit Cilium ou Envoy), cela n'affecte pas l'autre.
  • Mieux attribuer les ressources à chacun des composants afin d'optimiser les perfs.
  • Limite la surface d'attaque en cas de compromission d'un des pods.
  • Les logs Envoy et de l'agent Cilium ne sont pas mélangés

Il est possible d'utiliser la commande suivante pour vérifier que cette fonctionnalité est bien active:

1cilium status
2    /¯¯\
3 /¯¯\__/¯¯\    Cilium:             OK
4 \__/¯¯\__/    Operator:           OK
5 /¯¯\__/¯¯\    Envoy DaemonSet:    OK
6 \__/¯¯\__/    Hubble Relay:       disabled
7    \__/       ClusterMesh:        disabled

Plus d'information.

🚪 La porte d'entrée: GatewayClass et Gateway

Gateway

Une fois les conditions nécessaires remplies, nous avons accès à plusieurs éléments. Nous pouvons notamment utiliser les ressources de la Gateway API grâce aux CRDs. D'ailleurs, dès l'installation de Cilium, une GatewayClass est directement disponible.

1kubectl get gatewayclasses.gateway.networking.k8s.io
2NAME     CONTROLLER                     ACCEPTED   AGE
3cilium   io.cilium/gateway-controller   True       7m59s

Sur un cluster il est possible de configurer plusieurs GatewayClass et donc d'avoir la possibilité de faire usage de différentes implémentations. Nous pouvons par exemple utiliser Linkerd en référencant la GatewayClass dans la configuration de la Gateway.

La Gateway est la ressource qui permet déclencher la création de composants de répartition de charge chez le Clouder.

Voici un exemple simple: apps/base/echo/gateway.yaml

 1apiVersion: gateway.networking.k8s.io/v1beta1
 2kind: Gateway
 3metadata:
 4  name: echo-gateway
 5  namespace: echo
 6spec:
 7  gatewayClassName: cilium
 8  listeners:
 9    - protocol: HTTP
10      port: 80
11      name: echo-1-echo-server
12      allowedRoutes:
13        namespaces:
14          from: Same

Sur AWS (EKS), quand on configure une Gateway, Cilium crée un Service de type LoadBalancer. Ce service est alors interprété par un autre contrôleur, l'(AWS Load Balancer Controler), qui produit un NLB.

1kubectl get svc -n echo cilium-gateway-echo
2NAME                  TYPE           CLUSTER-IP     EXTERNAL-IP                                                                 PORT(S)        AGE
3cilium-gateway-echo   LoadBalancer   172.20.19.82   k8s-echo-ciliumga-64708ec85c-fcb7661f1ae4e4a4.elb.eu-west-3.amazonaws.com   80:30395/TCP   2m58s

Il est intéressant de noter que l'adresse en question est aussi associée à la resource Gateway.

1kubectl get gateway -n echo echo
2NAME   CLASS    ADDRESS                                                                     PROGRAMMED   AGE
3echo   cilium   k8s-echo-ciliumga-64708ec85c-fcb7661f1ae4e4a4.elb.eu-west-3.amazonaws.com   True         16m

↪️ Les règles de routage: HTTPRoute

Un routage simple

HTTPRoute

Pour résumer le schéma ci-dessus en quelques mots:
Une ressource HTTPRoute permet de configurer le routage vers le service en référencant la gateway et en définissant le les paramètres de routage souhaités.

Note

workaround

À ce jour, il n'est pas possible de configurer les annotations des services générés par les Gateways (Issue Github). Une solution de contournement a été proposé afin de modifier le service généré par la Gateway dès lors qu'il est créé.

Kyverno est un outil qui permet de garantir la conformité des configurations par rapport aux bonnes pratiques et aux exigences de sécurité. Nous utilisons ici uniquement sa capacité à décrire une règle de mutation facilement.

security/mycluster-0/echo-gw-clusterpolicy.yaml

 1spec:
 2  rules:
 3    - name: mutate-svc-annotations
 4      match:
 5        any:
 6          - resources:
 7              kinds:
 8                - Service
 9              namespaces:
10                - echo
11              name: cilium-gateway-echo
12      mutate:
13        patchStrategicMerge:
14          metadata:
15            annotations:
16              external-dns.alpha.kubernetes.io/hostname: echo.${domain_name}
17              service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
18              service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
19          spec:
20            loadBalancerClass: service.k8s.aws/nlb

Le service cilium-gateway-echo se verra donc ajouter les annotations du contrôleur AWS ainsi qu'une annotation permettant de configurer une entrée DNS automatiquement.

apps/base/echo/httproute.yaml

 1apiVersion: gateway.networking.k8s.io/v1beta1
 2kind: HTTPRoute
 3metadata:
 4  name: echo-1
 5  namespace: echo
 6spec:
 7  parentRefs:
 8    - name: echo
 9      namespace: echo
10  rules:
11    - matches:
12        - path:
13            type: PathPrefix
14            value: /
15      backendRefs:
16        - name: echo-1-echo-server
17          port: 80

L'exemple utilisé ci-dessus est simpliste: toutes les requêtes sont transférées au service echo-1-echo-server.
parentRefs permet d'indiquer la Gateway à utiliser puis les règles de routage sont définies dans rules.

Les règles de routages pourraient aussi être basées sur le path.

1...
2spec:
3  hostnames:
4  - foo.bar.com
5  rules:
6  - matches:
7    - path:
8        type: PathPrefix
9        value: /login

Ou une entête HTTP

1...
2spec:
3  rules:
4  - matches:
5      headers:
6      - name: "version"
7        value: "2"
8...

Vérifions que le service est joignable:

1curl -s http://echo.cloud.ogenki.io | jq -rc '.environment.HOSTNAME'
2echo-1-echo-server-fd88497d-w6sgn

Comme vous pouvez le voir le service est exposé en HTTP sans certificat. Essayons de corriger cela 😉

Exposer un service en utilisant un certificat TLS

Il existe plusieurs méthodes pour configurer du TLS avec GAPI. Ici nous allons utiliser le cas le plus commun: protocole HTTPS et terminaison TLS sur la Gateway.

Supposons que nous souhaitons configurer le nom de domaine echo.cloud.ogenki.io utilisé précédemment. La configuration se fait principalement au niveau de la Gateway

apps/base/echo/tls-gateway.yaml

 1apiVersion: gateway.networking.k8s.io/v1beta1
 2kind: Gateway
 3metadata:
 4  name: echo
 5  namespace: echo
 6  annotations:
 7    cert-manager.io/cluster-issuer: letsencrypt-prod
 8spec:
 9  gatewayClassName: cilium
10  listeners:
11    - name: http
12      hostname: "echo.${domain_name}"
13      port: 443
14      protocol: HTTPS
15      allowedRoutes:
16        namespaces:
17          from: Same
18      tls:
19        mode: Terminate
20        certificateRefs:
21          - name: echo-tls

Le point essentiel ici est la référence à un secret contenant le certificat echo-tls. Ce certificat peut être créé manuellement mais j'ai décidé pour cet article d'automatiser cela avec Let's Encrypt et cert-manager.

Info

cert-manager

Avec cert-manager il est très simple d'automatiser la création et la mise à jour des certificats exposés par la Gateway. Pour cela, il faut permettre au contrôlleur d'accéder à route53 afin de résoudre un challenge DNS01 (Mécanisme qui permet de s'assurer que les clients peuvent seulement demander des certificats pour des domaines qu'ils possèdent).

Une ressource ClusterIssuer décrit la configuration nécessaire pour générer des certificats grâce à cert-manager.

Ensuite il suffit d'ajouter une annotation cert-manager.io/cluster-issuer et indiquer le secret Kubernetes où sera stocké le certificat.

ℹ️ Dans le repo de demo les permissions sont attribuées en utilisant Crossplane qui se charge de configurer cela au niveau du Cloud AWS.

Plus d'informations

Pour que le routage se fasse correctement il faut aussi bien entendu référencer la bonne Gateway mais aussi indiquer le nom de domaine dans la ressource HTTPRoute.

 1apiVersion: gateway.networking.k8s.io/v1beta1
 2kind: HTTPRoute
 3metadata:
 4  name: echo-1
 5  namespace: echo
 6spec:
 7  parentRefs:
 8    - name: echo
 9      namespace: echo
10  hostnames:
11    - "echo.${domain_name}"
12...

Il faut patienter quelques minutes le temps que le certificat soit créé.

1kubectl get cert -n echo
2NAME       READY   SECRET     AGE
3echo-tls   True    echo-tls   43m

Nous pouvons enfin vérifier que le certificat est bien issue de Let's Encrypt comme suit:

1curl https://echo.cloud.ogenki.io -v 2>&1 | grep -A 6 'Server certificate'
2* Server certificate:
3*  subject: CN=echo.cloud.ogenki.io
4*  start date: Sep 15 14:43:00 2023 GMT
5*  expire date: Dec 14 14:42:59 2023 GMT
6*  subjectAltName: host "echo.cloud.ogenki.io" matched cert's "echo.cloud.ogenki.io"
7*  issuer: C=US; O=Let's Encrypt; CN=R3
8*  SSL certificate verify ok.
Info

GAPI permet aussi de configurer le TLS de bout en bout, jusqu'au conteneur. Cela se fait en configurant la Gateway en Passthrough et en utilisant une ressource TLSRoute. Il faut aussi que le certificat soit porté par le pod qui fait terminaison TLS.

Une Gateway partagée par plusieurs namespaces

Shared Gateway

Avec GAPI il est possible de router le trafic à travers les Namespaces. Cela est rendu possible grâce à des ressources distinctes pour chaque fonction: Une Gateway qui permet de configurer l'infrastructure et notamment de provisionner une adresse IP, et les *Routes. Ces routes peuvent référencer une Gateway située dans un autre namespace. Il est ainsi possible pour différent(e)s équipes/projets de partager les mêmes éléments d'infrastructure.

Il est cependant requis de spécifier quelle route est autorisée à référencer la Gateway. Ici nous supposons que nous avons une Gateway dédiée aux outils internes qui s'appelle platform. En utilisant le paramètre allowedRoutes, nous spécifions explicitement quelles sont les namespaces autorisés à référencer cette Gateway.

infrastructure/base/gapi/platform-gateway.yaml

 1...
 2      allowedRoutes:
 3        namespaces:
 4          from: Selector
 5          selector:
 6            matchExpressions:
 7              - key: kubernetes.io/metadata.name
 8                operator: In
 9                values:
10                  - observability
11                  - flux-system
12      tls:
13        mode: Terminate
14        certificateRefs:
15          - name: platform-tls

Les HTTPRoutes situées dans les namespaces observability et flux-system réferéncent cette même Gateway.

1...
2spec:
3  parentRefs:
4    - name: platform
5      namespace: infrastructure

Et utilisent le même répartiteur de charge du Clouder

 1NLB_DOMAIN=$(kubectl get svc -n infrastructure cilium-gateway-platform -o jsonpath={.status.loadBalancer.ingress[0].hostname})
 2
 3dig +short ${NLB_DOMAIN}
 413.36.89.108
 5
 6dig +short grafana-mycluster-0.cloud.ogenki.io
 713.36.89.108
 8
 9dig +short gitops-mycluster-0.cloud.ogenki.io
1013.36.89.108
Note

🔒 Ces outils internes ne devraient pas être exposés sur Internet mais vous comprendrez qu'il s'agit là d'une démo 🙏. On pourrait par exemple, utiliser et une Gateway interne (IP privée) en jouant sur les annotations et un moyen de connexion privé (VPN, tunnels ...)

Traffic splitting

Split

Il est souvent utile de tester une application sur une portion du trafic lorsqu'une nouvelle version est disponible (A/B testing ou Canary deployment). GAPI permet cela de façon très simple en utilisant des poids.

Voici un exemple permettant de tester sur 5% du trafic vers le service echo-2-echo-server

apps/base/echo/httproute-split.yaml

 1...
 2  hostnames:
 3    - "split-echo.${domain_name}"
 4  rules:
 5    - matches:
 6        - path:
 7            type: PathPrefix
 8            value: /
 9      backendRefs:
10        - name: echo-1-echo-server
11          port: 80
12          weight: 95
13        - name: echo-2-echo-server
14          port: 80
15          weight: 5

Vérifions que la répartition se fait bien comme attendu:

scripts/check-split.sh

1./scripts/check-split.sh https://split-echo.cloud.ogenki.io
2Number of requests for echo-1: 95
3Number of requests for echo-2: 5

Manipulation des entêtes HTTP (Headers)

Il est aussi possible de jouer avec les entêtes HTTP (Headers): en ajouter, modifier ou supprimer. Ces modifications peuvent se faire sur les Headers de requête ou de réponse par le biais de filtres ajoutés à la ressource HTTPRoute.

Nous allons par exemple ajouter un Header à la requête

 1apiVersion: gateway.networking.k8s.io/v1beta1
 2kind: HTTPRoute
 3metadata:
 4  name: echo-1
 5  namespace: echo
 6spec:
 7...
 8  rules:
 9    - matches:
10        - path:
11            type: PathPrefix
12            value: /req-header-add
13      filters:
14        - type: RequestHeaderModifier
15          requestHeaderModifier:
16            add:
17              - name: foo
18                value: bar
19      backendRefs:
20        - name: echo-1-echo-server
21          port: 80
22...

La commande suivante permet de vérifier que le header est bien présent.

 1curl -s https://echo.cloud.ogenki.io/req-header-add -sk | jq '.request.headers'
 2{
 3  "host": "echo.cloud.ogenki.io",
 4  "user-agent": "curl/8.2.1",
 5  "accept": "*/*",
 6  "x-forwarded-for": "81.220.234.254",
 7  "x-forwarded-proto": "https",
 8  "x-envoy-external-address": "81.220.234.254",
 9  "x-request-id": "320ba4d2-3bd6-4c2f-8a97-74296a9f3f26",
10  "foo": "bar"
11}

🪪 Les roles et permissions

GAPI offre un modèle de partage des permissions claire entre l'infrastructure de routage du trafic (gérée par les administrateurs de cluster) et les applications (gérées par les développeurs).

Le fait de disposer de plusieurs ressources nous permet d'utiliser les ressources RBAC dans Kubernetes pour attribuer les droits de façon déclarative. J'ai ajouté quelques exemples qui n'ont aucun effet dans mon cluster de démo mais qui peuvent vous permettre de vous faire une idée.

La configuration suivante permet aux membres du groupe developers de gérer les HTTPRoutes dans le namespace echo. En revanche ils ne possédent que des droits en lecture sur les Gateways.

 1---
 2apiVersion: rbac.authorization.k8s.io/v1
 3kind: Role
 4metadata:
 5  namespace: echo
 6  name: gapi-developer
 7rules:
 8  - apiGroups: ["gateway.networking.k8s.io"]
 9    resources: ["httproutes"]
10    verbs: ["*"]
11  - apiGroups: ["gateway.networking.k8s.io"]
12    resources: ["gateways"]
13    verbs: ["get", "list"]
14---
15apiVersion: rbac.authorization.k8s.io/v1
16kind: RoleBinding
17metadata:
18  name: gapi-developer
19  namespace: echo
20subjects:
21  - kind: Group
22    name: "developers"
23    apiGroup: rbac.authorization.k8s.io
24roleRef:
25  kind: Role
26  name: gapi-developer
27  apiGroup: rbac.authorization.k8s.io

🤔 Un périmètre pas évident

Il ne faut pas confondre GAPI avec ce que l'on nomme couramment une API Gateway. Une section de la FAQ a d'ailleurs été créé pour éclaircir ce point. Bien que GAPI offre des fonctionnalités typiquement présentes dans une API Gateway, il s'agit avant tout d'une implémentation spécifique pour Kubernetes. Cependant, ce choix de dénomination peut prêter à confusion.

Il est essentiel de mentionner que cet article se concentre uniquement sur le trafic entrant, appelé north-south, traditionnellement géré par les Ingress Controllers. Ce trafic représente le périmètre initial de GAPI. Une initiative récente nommée GAMMA vise à également gérer le routage east-west, ce qui permettra de standardiser certaines fonctionnalités des solutions de Service Mesh à l'avenir. (voir cet article pour plus d'informations).

💭 Dernières remarques

Pour être honnête, j'ai entendu parlé de Gateway API depuis un petit moment. J'ai lu quelques articles mais jusqu'ici je n'avais pas pris le temps d'approfondir le sujet. Je me disais "Pourquoi? J'arrive à faire ce que je veux avec mon Ingress Controller ? et puis il faut apprendre à utiliser de nouvelles ressources".

GAPI gagne en maturité et nous sommes proche d'une version GA. De nombreux projets l'ont déjà adopté, Istio et Linkerd par exemple sont totalement compatibles avec la version 0.8.0 et cette façon de gérer le trafic au sein de Kubernetes deviendra rapidement la norme.

Toujours est-il que j'ai beaucoup aimé la déclaration des différentes configurations que je trouve très intuitive et explicite ❤️. D'autre part le modèle de sécurité permet de donner le pouvoir aux developpeurs sans sacrifier la sécurité. Enfin la gestion de l'infrastructure se fait de façon transparente, nous pouvons rapidement passer d'une implémentation (contrôleur sous-jacent) à une autre sans toucher aux *Routes.

Alors suis-je prêt à changer mon Ingress Controller pour Cilium aujourd'hui? La réponse courte est Non mais bientôt!.

Tout d'abord j'aimerais mettre en évidence sur l'étendue des possiblités offertes par Cilium: De nombreuses personnes se sentent noyées sous les nombreux outils qui gravitent autour de Kubernetes. Cilium permettrait de remplir les fonctionnalités de nombre d'entre eux (metrics, tracing, service-mesh, sécurité et ... Ingress Controller avec GAPI).

Cependant, bien que nous puissions faire du routage HTTP de base, il y à certains points d'attention:

  • Le support de TCP et UDP
  • Le support de GRPC
  • Devoir passer par une règle de mutation pour pouvoir configurer les composants cloud. (Issue Github)
  • De nombreuses fonctionnalités explorées sont toujours au stade expérimental. On peut citer les fonctions étendues qui supportés depuis quelques jours: J'ai par exemple tenté de configurer une redirection HTTP>HTTPS simple mais je suis tombé sur ce problème. Je m'attends donc à ce qu'il y ait des changements dans l'API très prochainement.

Je n'ai pas abordé toutes les fonctionnalités de l'implémentation Cilium de GAPI (Honnêtement, cet article est déjà bien fourni 😜). Néanmoins, je suis vraiment convaincu de son potentiel. J'ai bon espoir qu'on pourra bientôt envisager son utilisation en production. Si vous n'avez pas encore envisagé cette transition, c'est le moment de s'y pencher 😉 ! Toutefois, compte tenu des aspects évoqués précédemment, je conseillerais de patienter un peu.

🔖 References

Traductions: