Rédacteur – Ce billet fait partie d’ une série en 10 parties :
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 :
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 :
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 .
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 200
OK
Code d'état HTTP.
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é
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.
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.
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.
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.
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 |
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 :
nginx-plus
ont été ajustées si nécessaire dans la configuration de NGINX Open Source.gcr.io/nginx-demos/nap-ingress:edge
), mais il a été désactivé (l'indicateur -enable-app-protect
a été omis).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"
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
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"
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
---
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é :)' ;}}"
---
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."