BLOG | NGINX

Test des performances des contrôleurs d'entrée NGINX dans un environnement cloud Kubernetes dynamique

NGINX-Partie-de-F5-horiz-black-type-RGB
Miniature d'Amir Rawdat
Amir Rawdat
Publié le 22 septembre 2020

Rédacteur – Ce billet fait partie d’ une série en 10 parties :

  1. Réduisez la complexité avec Kubernetes de niveau production
  2. Comment améliorer la résilience dans Kubernetes grâce à la 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 d'entrée, partie 1 : Identifiez vos besoins
  6. Guide pour choisir un contrôleur d'entrée, partie 2 : Risques et pérennité
  7. Guide pour choisir un contrôleur d'entrée, partie 3 : Open Source contre Par défaut vs. Commercial
  8. Guide pour choisir un contrôleur d'entrée, partie 4 : Options du contrôleur d'entrée NGINX
  9. Comment choisir un maillage de services
  10. Tests de performances des contrôleurs d'entrée NGINX dans un environnement cloud Kubernetes dynamique (ce post)

Vous pouvez également télécharger l’ensemble complet des blogs sous forme d’eBook gratuit – Taking Kubernetes from Test to Production .

Alors que de plus en plus d’entreprises exécutent des applications conteneurisées en production, Kubernetes continue de consolider sa position en tant qu’outil standard pour l’orchestration des conteneurs. Dans le même temps, la demande en matière de cloud computing a été avancée de quelques années, car les initiatives de travail à domicile suscitées par la pandémie de COVID-19 ont accéléré la croissance du trafic Internet. Les entreprises travaillent rapidement pour mettre à niveau leur infrastructure car leurs clients subissent des pannes et des surcharges de réseau majeures.

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 qui exploite 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 les conteneurs dépendent d’un contrôleur Ingress basé sur NGINX pour fournir leurs applications aux utilisateurs.

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

Protocole de test et mesures collectées

Nous avons utilisé le programme de génération de charge wrk2 pour émuler un client, effectuant des requêtes continues 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) transmet les requêtes aux applications back-end déployées dans les pods Kubernetes et renvoie la réponse générée par les applications au client. Nous avons généré un flux constant de trafic client pour tester les contrôleurs Ingress et avons collecté les mesures de performances suivantes :

  • Latence – La durée entre le moment où le client génère une demande et la réception de la réponse. Nous rapportons les latences dans une distribution en percentiles. Par exemple, s’il y a 100 échantillons provenant de tests de latence, la valeur au 99e percentile est la latence de réponse la plus lente sur les 100 exécutions de test.
  • Délais d’expiration de connexion – Connexions TCP qui sont silencieusement abandonnées ou rejetées parce que le contrôleur d’entrée ne répond pas aux demandes dans un certain délai.
  • Erreurs de lecture – Tentatives de lecture sur une connexion qui échouent car 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 pour générer des requêtes. Le client AWS s'est connecté à l'adresse IP externe du contrôleur Ingress, qui a été déployé en tant que DaemonSet Kubernetes sur GKE-node-1 dans un environnement Google Kubernetes Engine (GKE). Le contrôleur Ingress a été configuré pour la terminaison SSL (référençant un secret Kubernetes) et le routage de couche 7, et exposé via un service Kubernetes de type LoadBalancer . L'application backend s'exécutait en tant que déploiement 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 de test

Déploiement du client

Nous avons exécuté le script wrk2 (version 4.0.0) suivant sur la machine cliente AWS. Il génère 2 threads de travail qui établissent ensemble 1 000 connexions au contrôleur Ingress déployé dans GKE. Au cours de chaque exécution de test de 3 minutes, le script génère 30 000 requêtes par seconde (RPS), ce que nous considérons comme une bonne simulation de la charge sur 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 de l’exécution du test en secondes (180 ou 3 minutes)
  • -L – Génère des informations détaillées sur le centile de latence pour l'exportation vers les outils d'analyse
  • -R – Définit le nombre de RPS (30 000)

Pour le chiffrement TLS, nous avons utilisé RSA avec une taille de clé de 2 048 bits et Perfect Forward Secrecy.

Chaque réponse de l'application back-end (accessible à l' adresse https://app.example.com:443 ) se compose d' environ 1 Ko de métadonnées de base du serveur, ainsi que des 200OK Code d'état HTTP.

Déploiement d'applications back-end

Nous avons effectué des tests avec un déploiement statique et dynamique de l’application back-end.

Dans le déploiement statique, il y avait cinq répliques de Pod 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 pour faire évoluer périodiquement le déploiement nginx du backend de cinq répliques de Pod jusqu'à sept, puis revenir à cinq. Cela émule un environnement Kubernetes dynamique et teste l’efficacité avec laquelle le contrôleur Ingress s’adapte aux modifications des points de terminaison.

pendant que [ 1 -eq 1 ]
faire
kubectl scale déploiement nginx --replicas=5
sommeil 12
kubectl scale déploiement nginx --replicas=7
sommeil 10
terminé

Résultats de performance

Résultats de latence pour le déploiement statique

Comme indiqué dans le graphique, les trois contrôleurs Ingress ont obtenu des performances similaires avec un déploiement statique de l’application back-end. Cela a du sens étant donné qu’ils sont tous basés sur NGINX Open Source et que le déploiement statique ne nécessite pas de reconfiguration du contrôleur Ingress.

Résultats de latence pour le déploiement dynamique

Le graphique montre la latence subie par chaque contrôleur d'entrée dans un déploiement dynamique où nous avons périodiquement mis à l'échelle l'application back-end de cinq pods de réplication jusqu'à sept et inversement (voir Déploiement d'applications back-end pour plus de détails).

Il est clair que seul le contrôleur Ingress basé sur NGINX Plus fonctionne bien dans cet environnement, ne subissant pratiquement aucune latence jusqu'au 99,99e percentile. Les contrôleurs Ingress basés sur la communauté et NGINX Open Source connaissent une latence notable à des centiles assez faibles, bien que selon un modèle assez différent. Pour le contrôleur Ingress communautaire, la latence monte doucement mais régulièrement jusqu'au 99e percentile, où elle se stabilise à environ 5 000 ms (5 secondes). Pour le contrôleur Ingress basé sur NGINX Open Source, la latence augmente considérablement jusqu'à environ 32 secondes au 99e percentile, puis à nouveau jusqu'à 60 secondes au 99,99e.

Comme nous l'expliquons plus en détail dans Résultats des erreurs et des délais d'attente pour le déploiement dynamique , la latence rencontrée avec la communauté et les contrôleurs d'entrée basés sur NGINX Open Source est causée par des erreurs et des délais d'attente qui se produisent après la mise à jour et le rechargement de la configuration NGINX en réponse aux points de terminaison changeants de l'application back-end.

Voici une vue plus détaillée des résultats pour le contrôleur Ingress communautaire et le contrôleur Ingress basé sur NGINX Plus dans la même condition de test que le graphique précédent. Le contrôleur Ingress basé sur NGINX Plus n'introduit pratiquement aucune latence jusqu'au 99,99e percentile, où il commence à grimper vers 254 ms au 99,9999e percentile. Le modèle de latence du contrôleur Ingress de la communauté augmente régulièrement jusqu'à atteindre une latence de 5 000 ms au 99e percentile, point auquel la latence se stabilise.

Résultats de dépassement de délai et d'erreur pour le déploiement dynamique

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

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

Avec le contrôleur Ingress basé sur Open Source NGINX, la nécessité de mettre à jour et de recharger la configuration NGINX pour chaque modification des points de terminaison de l'application back-end provoque de nombreuses erreurs de connexion, des délais d'expiration de connexion et des erreurs de lecture. Des erreurs de connexion/socket se produisent pendant le bref laps de temps nécessaire au rechargement de NGINX, lorsque les clients tentent de se connecter à un socket qui n'est plus alloué au processus NGINX. Les délais d'expiration de connexion se produisent lorsque les clients ont établi une connexion au contrôleur Ingress, mais que le point de terminaison principal n'est plus disponible. Les erreurs et les dépassements de délai ont tous deux un impact important sur la latence, avec des pics à 32 secondes au 99e percentile et à nouveau à 60 secondes au 99,99e.

Avec le contrôleur Ingress communautaire, il y a eu 8 809 expirations de connexion dues aux modifications des points de terminaison à mesure que l'application back-end augmentait ou diminuait. Le contrôleur Ingress communautaire utilise le code Lua pour éviter les rechargements de 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 modifications des points de terminaison résout certaines des limitations de performances de la version Open Source de NGINX, qui résultent de son exigence de recharger la configuration après chaque modification des points de terminaison. Néanmoins, des dépassements de délai de connexion se produisent toujours et entraînent une latence importante aux centiles les plus élevés.

Avec le contrôleur Ingress basé sur NGINX Plus, il n’y a eu aucune erreur ni aucun délai d’attente : l’environnement dynamique n’a eu pratiquement aucun effet sur les performances. Cela est dû au fait qu’il utilise l’API NGINX Plus pour mettre à jour dynamiquement la configuration NGINX lorsque les points de terminaison changent. Comme mentionné, la latence la plus élevée était de 254 ms et elle ne se produisait qu'au 99,9999 percentile.

Conclusion

Les résultats de performances montrent que pour éliminer complètement les délais d’attente et les erreurs dans un environnement cloud Kubernetes dynamique, le contrôleur Ingress doit s’adapter de manière dynamique aux modifications des points de terminaison back-end sans gestionnaires d’événements ni rechargements de configuration. Sur la base des résultats, nous pouvons dire que l’ API NGINX Plus est 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 dans les environnements Kubernetes hautement dynamiques dont vous avez besoin pour satisfaire vos utilisateurs.

Appendice

Spécifications de Cloud Machine

Machine Fournisseur de services cloud Type de machine
Client AWS m5a.4xlarge
Nœud GKE-1 BPC norme e2-32
Nœud GKE-2 BPC norme e2-32

Configuration pour les contrôleurs d'entrée NGINX Open Source et NGINX Plus

Configuration de Kubernetes

apiVersion : applications/v1
type : DaemonSet
métadonnées :
nom : nginx-ingress
espace de noms : nginx-ingress
spécification :
sélecteur :
matchLabels :
application : nginx-ingress
modèle :
métadonnées :
étiquettes :
application : 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 
conteneurs :
- image : gcr.io/nginx-demos/nap-ingress:edge
imagePullPolicy : Toujours
nom : nginx-plus-ingress
ports :
- nom : http
containerPort : 80
Port de l'hôte : 80
- nom : https
containerPort : 443
Port de l'hôte : 443
- nom : port de préparation
containerPort : 8081
#- nom : prometheus
#containerPort : 9113
readinessProbe :
httpGet :
chemin : /nginx-ready
port : readiness-port
periodSeconds : 1
securityContext :
allowPrivilegeEscalation : true
runAsUser : 101 #nginx
capacités :
suppression :
- TOUS
ajout :
- NET_BIND_SERVICE
env :
- nom : POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- nom: 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 pour NGINX Plus. Les références à nginx-plus ont été ajusté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'indicateur -enable-app-protect a été omis).

Carte de configuration

gentil: ConfigMap
apiVersion : v1
métadonnées :
nom : nginx-config
espace de noms : nginx-ingress
données :
connexions des travailleurs : "10000"
worker-rlimit-nofile : "10240"
Keepalive : "100"
requêtes keepalive : "100000000"

Configuration du contrôleur d'entrée NGINX de la communauté

Configuration de Kubernetes

apiVersion : applications/v1
type : DaemonSet
métadonnées :
étiquettes :
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: contrôleur
nom: ingress-nginx-controller
espace de noms: ingress-nginx
spécification:
sélecteur:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: contrôleur
modèle:
métadonnées:
étiquettes:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: contrôleur
spécification:
nodeSelector: 
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
hostNetwork: true
conteneurs:
- nom: contrôleur
image: us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1@sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20
Politique d'extraction d'image : IfNotPresent
cycle de vie :
preStop :
exec :
commande :
- /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 :
capacités :
suppression :
- TOUS
ajout :
- NET_BIND_SERVICE
runAsUser : 101
allowPrivilegeEscalation : true
env :
- nom : POD_NAME
valueFrom :
fieldRef :
fieldPath : metadata.name
- nom : POD_NAMESPACE
valueFrom :
fieldRef :
fieldPath : metadata.namespace
readinessProbe :
httpGet :
path : /healthz
port : 10254
schéma : HTTP
périodeSecondes : 1
ports :
- nom : http
containerPort : 80
protocole : TCP
- nom : https
containerPort : 443
protocole : TCP
- nom : webhook
containerPort : 8443
protocole : TCP
volumeMounts :
- nom : webhook-cert
mountPath : /usr/local/certificates/
readOnly : true
serviceAccountName : ingress-nginx
terminaisonGracePeriodSeconds : 300
volumes :
- nom : webhook-cert
secret :
secretName : ingress-nginx-admission

Carte de configuration

apiVersion : v1
type : ConfigMap
métadonnées :
nom : ingress-nginx-controller
espace de noms : ingress-nginx
données :
max-worker-connections : "10000"
nombre maximal de fichiers ouverts par les travailleurs : "10204"
connexions keepalive en amont : "100"
requêtes de maintien en vie : "100000000"

Configuration pour l'application back-end

Configuration de Kubernetes

apiVersion : applications/v1
type : Déploiement
métadonnées :
nom : nginx
spécification :
sélecteur :
matchLabels :
application : nginx 
modèle :
métadonnées :
étiquettes :
application : nginx
spécification :
nodeSelector :
kubernetes.io/hostname : gke-rawdata-cluster-default-pool-3ac53622-t2dz 
conteneurs :
- nom : nginx
image : nginx
ports :
- containerPort : 8080
volumeMounts : 
- nom : main-config-volume
mountPath : /etc/nginx
- nom : app-config-volume
mountPath : /etc/nginx/conf.d
readinessProbe :
httpGet :
chemin : /healthz
port : 8080
périodeSecondes : 3
volumes : 
- nom : volume-config-main
configMap : 
nom : conf-main
- nom : volume-config-app
configMap : 
nom : conf-app
---

Cartes de configuration

apiVersion : v1
type : ConfigMap
métadonnées :
nom : main-conf
espace de noms : par défaut
données :
nginx.conf : |+
utilisateur nginx ;
processus_travailleurs 16 ;
worker_rlimit_nofile 102400 ;
worker_cpu_affinity auto 1111111111111111 ;
journal_erreurs /var/log/nginx/error.log avis ;
pid /var/run/nginx.pid ;

événements {
connexion_travailleurs 100000 ;
}

http {

format_journal principal '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"' ;

sendfile activé ;
tcp_nodelay activé ;

access_log désactivé ;

inclure /etc/nginx/conf.d/*.conf ;
}

---

apiVersion : v1
kind : ConfigMap
métadonnées :
nom : app-conf
espace de noms : par défaut
données :
app.conf : "serveur {listen 8080 ; emplacement / {type_par_défaut text/plain ;expire -1 ; retour 200 'Adresse du serveur : $server_addr : $server_port\nNom du serveur : $hostname\nDate : $time_local\nURI : $request_uri\nID de la requête : $request_id\n' ;}emplacement /healthz {retour 200 'Je suis heureux et en bonne santé :)' ;}}"
---

Service

apiVersion : v1
type : Service
métadonnées :
nom : app-svc
spécification :
ports :
- port : 80
targetPort : 8080
protocole : TCP
nom : http
sélecteur :
application : nginx
---

« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."