La rédaction – Cet article fait partie d’une série en 10 volets :
- Réduisez la complexité grâce à Kubernetes prêt pour la production
- Comment améliorer la résilience dans Kubernetes grâce à une gestion avancée du trafic
- Comment améliorer la visibilité dans Kubernetes
- Six façons de sécuriser Kubernetes à l’aide d’outils de gestion du trafic
- Guide pour choisir un contrôleur Ingress, 1re partie : identifiez vos besoins
- Guide pour choisir un contrôleur Ingress, 2e partie : risques et pérennisation
- Guide pour choisir un contrôleur Ingress, 3e partie : open source, par défaut ou commercial
- Guide pour choisir un contrôleur Ingress, 4e partie : les différentes options de contrôleur Ingress NGINX
- Comment choisir un maillage de services
- 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 :
- Le contrôleur NGINX Ingress Controller géré par la communauté Kubernetes et basé sur NGINX Open Source. Comme dans nos précédents articles, nous le désignons ici sous le nom de « contrôleur Ingress communautaire ». Nous avons testé la version 0.34.1 à l’aide d’une image extraite de Google Container Registry.
- NGINX Ingress Controller basé sur NGINX Open Source, version 1.8.0 maintenue par NGINX.
- Contrôleur Ingress NGINX basé sur NGINX Plus, version 1.8.0 maintenue par NGINX.
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
doneRé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-secretRemarques :
- 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-protecta é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-admissionConfigMap
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
---À 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
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 ?
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
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
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
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
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.