Tests de performance des contrôleurs Ingress NGINX dans un environnement cloud Kubernetes dynamique

NGINX | 22 septembre 2020

La rédaction – Cet article fait partie d’une série en 10 volets :

  1. Réduisez la complexité grâce à Kubernetes prêt pour la production
  2. Comment améliorer la résilience dans Kubernetes grâce à une gestion avancée du trafic
  3. Comment améliorer la visibilité dans Kubernetes
  4. Six façons de sécuriser Kubernetes à l’aide d’outils de gestion du trafic
  5. Guide pour choisir un contrôleur Ingress, 1re partie : identifiez vos besoins
  6. Guide pour choisir un contrôleur Ingress, 2e partie : risques et pérennisation
  7. Guide pour choisir un contrôleur Ingress, 3e partie : open source, par défaut ou commercial
  8. Guide pour choisir un contrôleur Ingress, 4e partie : les différentes options de contrôleur Ingress NGINX
  9. Comment choisir un maillage de services
  10. Tests de performances des contrôleurs Ingress NGINX dans un environnement cloud Kubernetes dynamique (cet article)

Vous pouvez également télécharger l’intégralité de cette série d’articles sous la forme d’un e-book gratuit : « Faire passer Kubernetes de l’environnement de test à la production ».

À mesure que de plus en plus d’entreprises exécutent des applications conteneurisées en production, Kubernetes continue de conforter sa position d’outil de référence pour l’orchestration des conteneurs. Dans le même temps, la demande en matière de cloud computing a progressé de quelques années par rapport aux prévisions, car les initiatives de télétravail suscitées par la pandémie de COVID‑19 ont accéléré la croissance du trafic Internet. Les entreprises s’efforcent de moderniser rapidement leur infrastructure, car leurs clients subissent d’importantes pannes et surcharges réseau.

Pour atteindre le niveau de performances requis dans les environnements de microservices basés sur le cloud, vous avez besoin d’un logiciel rapide et entièrement dynamique, capable d’exploiter l’évolutivité et les performances des centres de données hyperscale de nouvelle génération. De nombreuses organisations qui utilisent Kubernetes pour gérer leurs conteneurs s’appuient sur un contrôleur Ingress basé sur NGINX pour mettre leurs applications à la disposition des utilisateurs.

Dans cet article de blog, nous présentons les résultats de nos tests de performances menés sur trois contrôleurs Ingress NGINX dans un environnement multicloud réaliste, en mesurant la latence des connexions clientes sur Internet :

Protocole de test et métriques collectées

Nous avons utilisé le programme de génération de charge wrk2 pour simuler un client envoyant en continu des requêtes via HTTPS pendant une période définie. Le contrôleur Ingress testé – le contrôleur Ingress communautaire, NGINX Ingress Controller basé sur NGINX Open Source ou NGINX Ingress Controller basé sur NGINX Plus – transmettait les requêtes aux applications backend déployées dans des pods Kubernetes, puis renvoyait au client la réponse générée par ces applications. Nous avons généré un flux constant de trafic client afin de soumettre les contrôleurs Ingress à des tests de charge et avons recueilli les métriques de performances suivantes :

  • Latence – Temps écoulé entre l’envoi d’une requête par le client et la réception de la réponse. Nous présentons les latences sous forme de distribution en percentiles. Par exemple, s’il existe 100 échantillons issus de tests de latence, la valeur au 99e percentile correspond à l’avant-dernière latence de réponse la plus élevée parmi les 100 exécutions du test.
  • Délais d’expiration de connexion – Connexions TCP interrompues ou rejetées silencieusement parce que le contrôleur Ingress ne répond pas aux requêtes dans un délai donné.
  • Erreurs de lecture – Tentatives de lecture sur une connexion qui échouent parce qu’un socket du contrôleur Ingress est fermé.
  • Erreurs de connexion – Connexions TCP entre le client et le contrôleur Ingress qui ne sont pas établies.

Topologie

Pour tous les tests, nous avons utilisé l’utilitaire wrk2 exécuté sur une machine cliente dans AWS afin de générer des requêtes. Le client AWS s’est connecté à l’adresse IP externe du contrôleur Ingress, déployé en tant que DaemonSet Kubernetes sur GKE-node-1 dans un environnement Google Kubernetes Engine (GKE). Le contrôleur Ingress était configuré pour la terminaison SSL (en référençant un Secret Kubernetes) et le routage de couche 7, et était exposé via un Service Kubernetes de Type LoadBalancer. L’application backend s’exécutait en tant que Deployment Kubernetes sur GKE-node-2.

Pour plus de détails sur les types de machines cloud et les configurations logicielles, consultez l’annexe.

Méthodologie des tests

Déploiement du client

Nous avons exécuté le script wrk2 suivant (version 4.0.0) sur la machine cliente AWS. Il lance 2 threads wrk qui établissent ensemble 1 000 connexions au contrôleur Ingress déployé dans GKE. Lors de chaque test de 3 minutes, le script génère 30 000 requêtes par seconde (RPS), ce qui constitue selon nous une bonne simulation de la charge supportée par un contrôleur Ingress dans un environnement de production.

wrk -t2 -c1000 -d180s -L -R30000 https://app.example.com:443/

où :

  • -t – Définit le nombre de threads (2)
  • -c – Définit le nombre de connexions TCP (1000)
  • -d – Définit la durée d’exécution du test en secondes (180, soit 3 minutes)
  • -L – Génère des informations détaillées sur les percentiles de latence en vue de leur exportation vers des outils d’analyse
  • -R – Définit le nombre de requêtes par seconde (30 000)

Pour le chiffrement TLS, nous avons utilisé RSA avec une clé de 2 048 bits et la confidentialité persistante (Perfect Forward Secrecy).

Chaque réponse de l’application back-end (accessible à l’adresse https://app.example.com:443) contient environ 1 Ko de métadonnées serveur de base, ainsi que le code d’état HTTP 200 OK.

Déploiement de l’application back-end

Nous avons effectué des essais avec des déploiements statique et dynamique de l’application back-end.

Dans le déploiement statique, il y avait cinq réplicas de pods, et aucune modification n’a été appliquée à l’aide de l’API Kubernetes.

Pour le déploiement dynamique, nous avons utilisé le script suivant afin de faire passer périodiquement le nombre de réplicas de pods du déploiement backend nginx de cinq à sept, puis de le ramener à cinq. Cela simule un environnement Kubernetes dynamique et permet de tester l’efficacité avec laquelle le contrôleur Ingress s’adapte aux changements de points de terminaison.

while [ 1 -eq 1 ]
do
  kubectl scale deployment nginx --replicas=5
  sleep 12
  kubectl scale deployment nginx --replicas=7
  sleep 10
done

Résultats des performances

Résultats de latence pour le déploiement statique

Comme l’indique le graphique, les trois contrôleurs Ingress ont obtenu des performances similaires avec un déploiement statique de l’application back-end. Cela s’explique par le fait qu’ils reposent tous sur NGINX Open Source et que le déploiement statique ne nécessite aucune reconfiguration de la part du contrôleur Ingress.

Résultats de latence pour le déploiement dynamique

Le graphique montre la latence induite par chaque contrôleur Ingress dans le cadre d’un déploiement dynamique où nous avons périodiquement fait passer l’application back-end de cinq pods répliqués à sept, puis de nouveau à cinq (voir « Déploiement de l’application back-end » pour plus de détails).

Il est clair que seul le contrôleur Ingress basé sur NGINX Plus offre de bonnes performances dans cet environnement, avec une latence pratiquement nulle jusqu’au 99,99e centile. Les contrôleurs Ingress de la communauté et celui basé sur NGINX Open Source présentent tous deux une latence notable dès des centiles relativement bas, mais selon des profils assez différents. Pour le contrôleur Ingress de la communauté, la latence augmente lentement mais régulièrement jusqu’au 99e centile, où elle se stabilise à environ 5 000 ms (5 secondes). Pour le contrôleur Ingress basé sur NGINX Open Source, la latence grimpe brutalement à environ 32 secondes au 99e centile, puis à 60 secondes au 99,99e centile.

Comme nous l’expliquons plus en détail dans la section « Résultats relatifs aux délais d’expiration et aux erreurs pour le déploiement dynamique », la latence observée avec les contrôleurs Ingress de la communauté et ceux basés sur NGINX Open Source est due aux erreurs et aux délais d’expiration qui surviennent après la mise à jour et le rechargement de la configuration NGINX en réponse aux changements de points de terminaison de l’application back-end.

Voici une vue plus détaillée des résultats obtenus par le contrôleur Ingress communautaire et le contrôleur Ingress basé sur NGINX Plus, dans les mêmes conditions de test que pour le graphique précédent. Le contrôleur Ingress basé sur NGINX Plus n’introduit pratiquement aucune latence jusqu’au 99,99e percentile, à partir duquel elle commence à augmenter pour atteindre 254 ms au 99,9999e percentile. La latence du contrôleur Ingress communautaire augmente progressivement jusqu’à atteindre 5 000 ms au 99e percentile, puis se stabilise.

Résultats des délais d’expiration et des erreurs pour le déploiement dynamique

Ce tableau présente plus en détail la cause des résultats de latence.

NGINX Open Source Communauté NGINX PlusErreurs de connexion 33365 0 0Délais d’expiration de connexion 309 8809 0Erreurs de lecture 4650 0 0

Avec le contrôleur Ingress basé sur NGINX Open Source, la nécessité de mettre à jour et de recharger la configuration NGINX à chaque modification des points de terminaison de l’application back-end entraîne de nombreuses erreurs de connexion, expirations de délai de connexion et erreurs de lecture. Des erreurs de connexion/socket se produisent pendant le bref laps de temps nécessaire au rechargement de NGINX, lorsque des clients tentent de se connecter à un socket qui n’est plus alloué au processus NGINX. Des expirations de délai de connexion se produisent lorsque des clients ont établi une connexion avec le contrôleur Ingress, mais que le point de terminaison back-end n’est plus disponible. Les erreurs comme les expirations de délai ont de graves répercussions sur la latence, avec des pics à 32 secondes au 99e centile, puis à 60 secondes au 99,99e centile.

Avec le contrôleur Ingress communautaire, 8 809 délais d’attente de connexion ont été enregistrés en raison des changements de points de terminaison lors de l’augmentation et de la réduction de la capacité de l’application back-end. Le contrôleur Ingress communautaire utilise du code Lua pour éviter de recharger la configuration lorsque les points de terminaison changent. Les résultats montrent que l’exécution d’un gestionnaire Lua dans NGINX pour détecter les changements de points de terminaison permet de remédier à certaines limitations de performances de la version basée sur NGINX Open Source, qui découlent de la nécessité de recharger la configuration après chaque changement de point de terminaison. Néanmoins, des délais d’attente de connexion se produisent encore et entraînent une latence importante aux percentiles supérieurs.

Avec le contrôleur Ingress basé sur NGINX Plus, aucune erreur ni expiration de délai ne s’est produite : l’environnement dynamique n’a eu pratiquement aucun effet sur les performances. Cela s’explique par le fait qu’il utilise l’API NGINX Plus pour mettre à jour dynamiquement la configuration de NGINX lorsque les points de terminaison changent. Comme indiqué précédemment, la latence maximale était de 254 ms et n’a été observée qu’au 99,9999e centile.

Conclusion

Les résultats des tests de performance montrent que, pour éliminer complètement les expirations de délai et les erreurs dans un environnement cloud Kubernetes dynamique, le contrôleur Ingress doit s’adapter de manière dynamique aux changements des points de terminaison back-end, sans gestionnaires d’événements ni rechargements de configuration. Au vu des résultats, nous pouvons affirmer que l’API NGINX Plus constitue la solution optimale pour reconfigurer dynamiquement NGINX dans un environnement dynamique. Lors de nos tests, seul le contrôleur Ingress basé sur NGINX Plus a atteint les performances irréprochables dont vous avez besoin dans des environnements Kubernetes hautement dynamiques pour garantir la satisfaction de vos utilisateurs.

Annexe

Caractéristiques de la machine cloud

Machine Fournisseur cloud Type de machineClient AWS m5a.4xlargeGKE-node-1 GCP e2-standard-32GKE-node-2 GCP e2-standard-32

Configuration des contrôleurs Ingress NGINX Open Source et NGINX Plus

Configuration de Kubernetes

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ingress
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: nginx-ingress
  template:
    metadata:
      labels:
        app: nginx-ingress
     #annotations:
       #prometheus.io/scrape: "true"
       #prometheus.io/port: "9113"
    spec:
      serviceAccountName: nginx-ingress
      nodeSelector:
        kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
      hostNetwork: true    
      containers:
      - image: gcr.io/nginx-demos/nap-ingress:edge
        imagePullPolicy: Always
        name: nginx-plus-ingress
        ports:
        - name: http
          containerPort: 80
          hostPort: 80
        - name: https
          containerPort: 443
          hostPort: 443
        - name: readiness-port
          containerPort: 8081
       #- name: prometheus
         #containerPort: 9113
        readinessProbe:
          httpGet:
            path: /nginx-ready
            port: readiness-port
          periodSeconds: 1
        securityContext:
          allowPrivilegeEscalation: true
          runAsUser: 101 #nginx
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        args:
          - -nginx-plus
          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret

Remarques :

  • Cette configuration est destinée à NGINX Plus. Les références à « nginx‑plus » ont été adaptées si nécessaire dans la configuration de NGINX Open Source.
  • NGINX App Protect est inclus dans l’image (gcr.io/nginx-demos/nap-ingress:edge), mais il a été désactivé (l’option -enable-app-protect a été omise).

ConfigMap

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
  namespace: nginx-ingress
data:
  worker-connections: "10000"
  worker-rlimit-nofile: "10240"
  keepalive: "100"
  keepalive-requests: "100000000"

Configuration du contrôleur Ingress NGINX communautaire

Configuration de Kubernetes

apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    helm.sh/chart: ingress-nginx-2.11.1
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 0.34.1
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/component: controller
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/component: controller
    spec:
      nodeSelector: 
        kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
      hostNetwork: true
      containers:
        - name: controller
          image: us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1@sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20
          imagePullPolicy: IfNotPresent
          lifecycle:
            preStop:
              exec:
                command:
                  - /wait-shutdown
          args:
            - /nginx-ingress-controller
            - --election-id=ingress-controller-leader
            - --ingress-class=nginx
            - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
            - --validating-webhook=:8443
            - --validating-webhook-certificate=/usr/local/certificates/cert
            - --validating-webhook-key=/usr/local/certificates/key
          securityContext:
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            runAsUser: 101
            allowPrivilegeEscalation: true
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          readinessProbe:
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 1
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
            - name: webhook
              containerPort: 8443
              protocol: TCP
          volumeMounts:
            - name: webhook-cert
              mountPath: /usr/local/certificates/
              readOnly: true
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 300
      volumes:
        - name: webhook-cert
          secret:
            secretName: ingress-nginx-admission

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  max-worker-connections: "10000"
  max-worker-open-files: "10204"
  upstream-keepalive-connections: "100"
  keep-alive-requests: "100000000"

Configuration de l’application back-end

Configuration de Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx 
  template:
    metadata:
      labels:
        app: nginx
    spec:
      nodeSelector:
        kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-t2dz 
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 8080
        volumeMounts: 
        - name: main-config-volume
          mountPath: /etc/nginx
        - name: app-config-volume
          mountPath: /etc/nginx/conf.d
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8080
          periodSeconds: 3
      volumes: 
      - name: main-config-volume
        configMap:
          name: main-conf
      - name: app-config-volume
        configMap: 
          name: app-conf
---

ConfigMaps

apiVersion: v1
kind: ConfigMap
metadata:
  name: main-conf
  namespace: default
data:
  nginx.conf: |+
    user nginx;
    worker_processes 16;
    worker_rlimit_nofile 102400;
    worker_cpu_affinity auto 1111111111111111;
    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;
 
    events {
        worker_connections  100000;
    }
 
    http {
 
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
 
        sendfile        on;
        tcp_nodelay on;
 
        access_log off;
 
        include /etc/nginx/conf.d/*.conf;
    }
 
---
 
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-conf
  namespace: default
data:
  app.conf: "server {listen 8080;location / {default_type text/plain;expires -1;return 200 'Server address: $server_addr:$server_portnServer name:$hostnamenDate: $time_localnURI: $request_urinRequest ID: $request_idn';}location /healthz {return 200 'I am happy and healthy :)';}}"
---

Service

apiVersion: v1
kind: Service
metadata:
  name: app-svc
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: nginx
---


Partager

À propos de l’auteur

Articles de blog associés

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA
NGINX | 13/10/2025

Tendances actuelles des technologies cloud natives, de l’ingénierie de plateforme et de l’IA

Découvrez les principaux enseignements tirés des réponses à l’enquête annuelle F5 NGINX sur les dernières tendances en matière de technologies cloud natives, de sécurité, d’ingénierie de plateforme et d’IA.

Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?
NGINX | 03/11/2023

Quels contrôleurs Ingress NGINX sont affectés par les vulnérabilités CVE-2022-4886, CVE-2023-5043 et CVE-2023-5044 ?

Lorsque de nouvelles CVE sont signalées, il est facile de ne plus savoir si elles concernent un outil de contrôleur Ingress NGINX particulier, car il existe plusieurs projets. Cet article présente les CVE et explique comment distinguer les différents projets de contrôleurs Ingress afin de dissiper toute confusion.

Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX
NGINX | 11/03/2020

Votre API est-elle en temps réel ? Testez sa latence avec l’outil rtapi de NGINX

Votre API répond-elle aux requêtes en moins de 30 ms ? Si ce n’est pas le cas, il ne s’agit pas d’une API en temps réel offrant la faible latence exigée par la grande majorité des organisations. Mesurez la latence de votre API avec l’outil rtapi de NGINX et découvrez comment NGINX peut l’aider à offrir une réactivité en temps réel.

Un testeur d’expressions régulières pour NGINX et NGINX Plus
NGINX | 11/06/2019

Un testeur d’expressions régulières pour NGINX et NGINX Plus

Le testeur d’expressions régulières (regex) pour NGINX et NGINX Plus vous évite de tâtonner en vous indiquant si une expression régulière utilisée dans un bloc location ou map correspond aux valeurs comme prévu. Il génère la configuration appropriée et affiche les valeurs des groupes de capture.

Caches partagés avec les clusters de cache NGINX Plus, partie 1
NGINX | 24/01/2017

Caches partagés avec les clusters de cache NGINX Plus, partie 1

Optimisez la capacité de votre cache web en le répartissant entre plusieurs serveurs de cache web NGINX ou NGINX Plus. Découvrez comment procéder dans cet article.

Introduction aux microservices
NGINX | 19/05/2015

Introduction aux microservices

Les microservices suscitent actuellement beaucoup d’intérêt. Cet article de blog est le premier d’une série de sept consacrée à la conception, au développement et au déploiement de microservices.