Redakteur – Dieser Beitrag ist Teil einer 10-teiligen Serie:
Sie können den kompletten Blogsatz auch als kostenloses E-Book herunterladen: Kubernetes vom Test zur Produktion bringen .
Da immer mehr Unternehmen containerisierte Apps in der Produktion ausführen, festigt Kubernetes weiterhin seine Position als Standardtool für die Container-Orchestrierung. Gleichzeitig hat sich die Nachfrage nach Cloud Computing um einige Jahre vorverlagert, da durch die Covid-19-Pandemie angestoßene Homeoffice- Initiativen das Wachstum des Internetverkehrs beschleunigt haben. Unternehmen arbeiten mit Hochdruck an der Modernisierung ihrer Infrastruktur, da ihre Kunden mit massiven Netzwerkausfällen und Überlastungen konfrontiert sind.
Um das erforderliche Leistungsniveau in Cloud-basierten Microservices-Umgebungen zu erreichen, benötigen Sie schnelle, vollständig dynamische Software, die die Skalierbarkeit und Leistung der Hyperscale-Rechenzentren der nächsten Generation nutzt. Viele Organisationen, die Kubernetes zur Verwaltung von Containern verwenden, sind auf einen NGINX-basierten Ingress-Controller angewiesen, um ihre Apps den Benutzern bereitzustellen.
In diesem Blog berichten wir über die Ergebnisse unserer Leistungstests auf drei NGINX Ingress-Controllern in einer realistischen Multi-Cloud-Umgebung, bei denen wir die Latenz von Client-Verbindungen über das Internet gemessen haben:
Wir haben das Lastgenerierungsprogramm wrk2
verwendet, um einen Client zu emulieren, der während eines definierten Zeitraums kontinuierlich Anfragen über HTTPS stellt. Der getestete Ingress-Controller – der Community-Ingress-Controller, der NGINX Ingress Controller basierend auf NGINX Open Source oder der NGINX Ingress Controller basierend auf NGINX Plus – leitete Anfragen an in Kubernetes Pods bereitgestellte Backend-Anwendungen weiter und gab die von den Anwendungen generierte Antwort an den Client zurück. Wir haben einen stetigen Client-Datenverkehr generiert, um die Ingress-Controller einem Stresstest zu unterziehen, und dabei die folgenden Leistungsmesswerte erfasst:
Für alle Tests haben wir das Dienstprogramm wrk2
verwendet, das auf einem Clientcomputer in AWS ausgeführt wird, um Anfragen zu generieren. Der AWS-Client hat eine Verbindung zur externen IP-Adresse des Ingress-Controllers hergestellt, der als Kubernetes- DaemonSet auf GKE-Knoten 1 in einer Google Kubernetes Engine (GKE)-Umgebung bereitgestellt wurde. Der Ingress-Controller wurde für die SSL-Terminierung (unter Bezugnahme auf ein Kubernetes- Geheimnis ) und Layer-7-Routing konfiguriert und über einen Kubernetes -Dienst vom Typ
LoadBalancer
verfügbar gemacht. Die Backend-Anwendung wurde als Kubernetes- Deployment auf GKE-Knoten 2 ausgeführt.
Ausführliche Informationen zu den Cloud-Maschinentypen und den Softwarekonfigurationen finden Sie im Anhang .
Wir haben das folgende wrk2
-Skript (Version 4.0.0) auf dem AWS-Clientcomputer ausgeführt. Es erzeugt zwei Wrk
-Threads, die zusammen 1000 Verbindungen zum in GKE bereitgestellten Ingress-Controller herstellen. Während jedes dreiminütigen Testlaufs generiert das Skript 30.000 Anfragen pro Sekunde (RPS), was wir als gute Simulation der Belastung eines Ingress-Controllers in einer Produktionsumgebung betrachten.
wrk -t2 -c1000 -d180s -L -R30000 https://app.example.com:443/
Wo:
-t
– Legt die Anzahl der Threads fest (2)-c
– Legt die Anzahl der TCP-Verbindungen fest (1000)-d
– Legt die Dauer des Testlaufs in Sekunden fest (180 oder 3 Minuten)-L
– Generiert detaillierte Latenzperzentilinformationen für den Export in Analysetools-R
– Legt die Anzahl der RPS fest (30.000)Für die TLS-Verschlüsselung haben wir RSA mit einer Schlüsselgröße von 2048 Bit und Perfect Forward Secrecy verwendet.
Jede Antwort der Back‑End‑Anwendung (Zugriff unter https://app.example.com:443 ) besteht aus etwa 1 KB grundlegender Server‑Metadaten sowie den 200
OK
HTTP-Statuscode.
Wir haben Testläufe sowohl mit einer statischen als auch einer dynamischen Bereitstellung der Back-End-Anwendung durchgeführt.
In der statischen Bereitstellung gab es fünf Pod-Replikate und es wurden keine Änderungen mithilfe der Kubernetes-API vorgenommen.
Für die dynamische Bereitstellung haben wir das folgende Skript verwendet, um die Back-End -Nginx- Bereitstellung regelmäßig von fünf Pod-Replikaten auf sieben und dann wieder auf fünf zu skalieren. Dies emuliert eine dynamische Kubernetes-Umgebung und testet, wie effektiv sich der Ingress-Controller an Endpunktänderungen anpasst.
während [ 1 -eq 1 ]
machen
kubectl scale deployment nginx --replicas=5
sleep 12
kubectl scale deployment nginx --replicas=7
sleep 10
fertig
Wie in der Grafik dargestellt, erzielten alle drei Ingress-Controller bei einer statischen Bereitstellung der Back-End-Anwendung eine ähnliche Leistung. Dies ist sinnvoll, da sie alle auf NGINX Open Source basieren und für die statische Bereitstellung keine Neukonfiguration vom Ingress-Controller erforderlich ist.
Das Diagramm zeigt die Latenz, die von jedem Ingress-Controller bei einer dynamischen Bereitstellung verursacht wird, bei der wir die Back-End-Anwendung regelmäßig von fünf Replikations-Pods auf sieben und wieder zurück skaliert haben (Einzelheiten finden Sie unter Bereitstellung der Back-End-Anwendung ).
Es ist klar, dass in dieser Umgebung nur der auf NGINX Plus basierende Ingress-Controller eine gute Leistung erbringt und bis zum 99,99. Perzentil praktisch keine Latenz aufweist. Sowohl bei den Community- als auch bei den auf Open Source basierenden Ingress-Controllern von NGINX kommt es bei relativ niedrigen Perzentilen zu merklichen Latenzen, allerdings in einem ziemlich unterschiedlichen Muster. Beim Community-Ingress-Controller steigt die Latenz sanft, aber stetig bis zum 99. Perzentil an, wo sie sich bei etwa 5000 ms (5 Sekunden) einpendelt. Beim auf Open Source basierenden Ingress-Controller NGINX steigt die Latenz beim 99. Perzentil dramatisch auf etwa 32 Sekunden und beim 99,99. Perzentil erneut auf 60 Sekunden .
Wie wir im Abschnitt „Timeout- und Fehlerergebnisse für die dynamische Bereitstellung“ weiter erläutern, wird die bei den Community- und NGINX Open Source-basierten Ingress-Controllern auftretende Latenz durch Fehler und Timeouts verursacht, die auftreten, nachdem die NGINX-Konfiguration als Reaktion auf die sich ändernden Endpunkte für die Back-End-Anwendung aktualisiert und neu geladen wurde.
Hier ist eine detailliertere Ansicht der Ergebnisse für den Community-Ingress-Controller und den NGINX Plus-basierten Ingress-Controller unter denselben Testbedingungen wie im vorherigen Diagramm. Der auf NGINX Plus basierende Ingress-Controller führt bis zum 99,99. Perzentil praktisch keine Latenz ein, wo sie beim 99,9999. Perzentil auf 254 ms anzusteigen beginnt. Das Latenzmuster für den Community-Ingress-Controller wächst stetig an, bis es beim 99. Perzentil eine Latenz von 5000 ms erreicht, bei der sich die Latenz dann stabilisiert.
In dieser Tabelle werden die Ursachen für die Latenzergebnisse genauer dargestellt.
NGINX Open Source | Gemeinschaft | NGINX Plus | |
---|---|---|---|
Verbindungsfehler | 33365 | 0 | 0 |
Verbindungstimeouts | 309 | 8809 | 0 |
Lesefehler | 4650 | 0 | 0 |
Beim Open Source-basierten Ingress-Controller NGINX führt die Notwendigkeit, die NGINX-Konfiguration bei jeder Änderung an den Endpunkten der Back-End-Anwendung zu aktualisieren und neu zu laden, zu vielen Verbindungsfehlern, Verbindungstimeouts und Lesefehlern. Verbindungs-/Socket-Fehler treten während der kurzen Zeit auf, die NGINX zum Neuladen benötigt, wenn Clients versuchen, eine Verbindung zu einem Socket herzustellen, der nicht mehr dem NGINX-Prozess zugewiesen ist. Verbindungstimeouts treten auf, wenn Clients eine Verbindung zum Ingress-Controller hergestellt haben, der Back-End-Endpunkt jedoch nicht mehr verfügbar ist. Sowohl Fehler als auch Timeouts wirken sich erheblich auf die Latenz aus, mit Spitzen auf 32 Sekunden beim 99. Perzentil und erneut auf 60 Sekunden beim 99,99.
Beim Community-Ingress-Controller kam es aufgrund von Endpunktänderungen beim Hoch- und Herunterskalieren der Back-End-Anwendung zu 8.809 Verbindungstimeouts. Der Community-Ingress-Controller verwendet Lua-Code, um ein erneutes Laden der Konfiguration bei Endpunktänderungen zu vermeiden . Die Ergebnisse zeigen, dass das Ausführen eines Lua-Handlers innerhalb von NGINX zum Erkennen von Endpunktänderungen einige der Leistungseinschränkungen der auf Open Source basierenden Version von NGINX behebt, die sich aus der Anforderung ergeben, die Konfiguration nach jeder Änderung an den Endpunkten neu zu laden. Dennoch kommt es weiterhin zu Verbindungstimeouts und führt bei höheren Perzentilen zu erheblichen Latenzen.
Mit dem auf NGINX Plus basierenden Ingress-Controller traten keine Fehler oder Timeouts auf – die dynamische Umgebung hatte praktisch keine Auswirkungen auf die Leistung. Dies liegt daran, dass es die NGINX Plus-API verwendet, um die NGINX-Konfiguration dynamisch zu aktualisieren, wenn sich Endpunkte ändern. Wie erwähnt betrug die höchste Latenz 254 ms und trat nur beim 99,9999. Perzentil auf.
Die Leistungsergebnisse zeigen, dass sich der Ingress-Controller dynamisch an Änderungen an Back-End-Endpunkten anpassen muss, ohne dass Ereignishandler oder Neuladen der Konfiguration erforderlich sind, um Timeouts und Fehler in einer dynamischen Kubernetes-Cloud-Umgebung vollständig zu vermeiden. Basierend auf den Ergebnissen können wir sagen, dass die NGINX Plus API die optimale Lösung für die dynamische Neukonfiguration von NGINX in einer dynamischen Umgebung ist. In unseren Tests erreichte nur der auf NGINX Plus basierende Ingress-Controller die einwandfreie Leistung in hochdynamischen Kubernetes-Umgebungen, die Sie benötigen, um Ihre Benutzer zufrieden zu stellen.
Maschine | Cloud-Anbieter | Maschinentyp |
---|---|---|
Kunde | AWS | m5a.4xlarge |
GKE-Knoten-1 | GCP | e2-standard-32 |
GKE-Knoten-2 | GCP | e2-standard-32 |
API-Version: Apps/v1
Art: DaemonSet
Metadaten:
Name: nginx-ingress
Namespace: nginx-ingress
Spezifikation:
Selektor:
MatchLabels:
App: nginx-ingress
Vorlage:
Metadaten:
Labels:
App: nginx-ingress
#Anmerkungen:
#prometheus.io/scrape: „true“
#prometheus.io/Port: "9113"
Spezifikation:
ServiceAccountName: nginx-ingress
Knotenauswahl:
kubernetes.io/Hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
Hostnetzwerk: true
Container:
-Image: gcr.io/nginx-demos/nap-ingress:edge
ImagePullPolicy: Immer
Name: nginx-plus-ingress
Ports:
- Name: http
ContainerPort: 80
HostPort: 80
- Name: https
ContainerPort: 443
HostPort: 443
- Name: Bereitschaftsport
ContainerPort: 8081
#- Name: prometheus
#ContainerPort: 9113
readinessProbe:
httpGet:
Pfad: /nginx-ready
Port: readiness-port
PeriodeSekunden: 1
Sicherheitskontext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
Fähigkeiten:
löschen:
- ALLE
hinzufügen:
- NET_BIND_SERVICE
Umgebung:
- Name: POD_NAMESPACE
Wert von:
Feldreferenz:
Feldpfad: Metadaten.Namespace
- Name: POD_NAME
Wert von:
Feldreferenz:
Feldpfad: Metadatenname
Argumente:
- -nginx-plus
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
Hinweise:
nginx‑plus
wurden bei Bedarf in der Konfiguration für NGINX Open Source angepasst.gcr.io/nginx-demos/nap-ingress:edge
), wurde aber deaktiviert (das Flag „-enable-app-protect“
wurde weggelassen).Art: ConfigMap
API-Version: v1
Metadaten:
Name: nginx-config
Namespace: nginx-ingress
Daten:
Worker-Verbindungen: "10000"
worker-rlimit-nofile: "10240"
Keepalive: "100"
Keepalive-Anfragen: "100000000"
API-Version: Apps/v1
Art: DaemonSet
Metadaten:
Bezeichnungen:
helm.sh/Chart: ingress-nginx-2.11.1
app.kubernetes.io/Name: ingress-nginx
app.kubernetes.io/Instanz: ingress-nginx
app.kubernetes.io/Version: 0.34.1 app.kubernetes.io/managed-by: Helm
app.kubernetes.io/Komponente: Controller
Name: ingress-nginx-controller
Namespace: ingress-nginx
Spezifikation:
Selektor:
MatchLabels:
app.kubernetes.io/Name: ingress-nginx
app.kubernetes.io/Instanz: ingress-nginx
app.kubernetes.io/Komponente: Controller
Vorlage:
Metadaten:
Labels:
app.kubernetes.io/Name: ingress-nginx
app.kubernetes.io/Instanz: ingress-nginx
app.kubernetes.io/Komponente: Controller
Spezifikation:
Knotenselektor:
kubernetes.io/Hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
Hostnetzwerk: true
Container:
- Name: Controller
Bild: us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1@sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20
imagePullPolicy: IfNotPresent
Lebenszyklus:
preStop:
exec:
Befehl:
- /wait-shutdown
Argumente:
- /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
Sicherheitskontext:
Fähigkeiten:
löschen:
- ALLE
hinzufügen:
- NET_BIND_SERVICE
Als Benutzer ausführen: 101
allowPrivilegeEscalation: true
Umgebung:
- Name: POD_NAME
Wert von:
Feldreferenz:
Feldpfad: Metadatenname
- Name: POD_NAMESPACE
Wert von:
Feldreferenz:
Feldpfad: metadata.namespace
Bereitschaftsprobe:
httpGet:
Pfad: /healthz
Port: 10254
Schema: HTTP
ZeitraumSekunden: 1
Ports:
- Name: http
ContainerPort: 80
Protokoll: TCP
- Name: https
ContainerPort: 443
Protokoll: TCP
- Name: Webhook
ContainerPort: 8443
Protokoll: TCP
VolumeMounts:
- Name: Webhook-Zertifikat
MountPath: /usr/local/certificates/
Nur lesen: true
ServiceAccountName: ingress-nginx
TerminationGracePeriodSeconds: 300
Volumes:
- Name: Webhook-Zertifikat
Geheimnis:
Geheimname: Ingress-Nginx-Zulassung
API-Version: v1
Art: ConfigMap
Metadaten:
Name: ingress-nginx-controller
Namespace: ingress-nginx
Daten:
max-worker-connections: "10000"
max-worker-open-files: "10204"
Upstream-Keepalive-Verbindungen: "100"
Keep-Alive-Anfragen: "100000000"
API-Version: Apps/v1
Art: Bereitstellung
Metadaten:
Name: nginx
Spezifikation:
Selektor:
MatchLabels:
App: nginx
Vorlage:
Metadaten:
Labels:
App: nginx
Spezifikation:
Knotenselektor:
kubernetes.io/Hostname: gke-rawdata-cluster-default-pool-3ac53622-t2dz
Container:
- 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:
Pfad: /healthz
Port: 8080
PeriodeSekunden: 3
Volumes:
- Name: Hauptkonfigurationsvolume
configMap:
Name: Hauptconf
- Name: App-Konfigurationsvolume
configMap:
Name: App-conf
---
API-Version: v1
Art: ConfigMap
Metadaten:
Name: main-conf
Namespace: default
Daten:
nginx.conf: |+
Benutzer nginx;
worker_processes 16;
worker_rlimit_nofile 102400;
worker_cpu_affinity auto 1111111111111111;
error_log /var/log/nginx/error.log Hinweis;
pid /var/run/nginx.pid;
Ereignisse {
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 ein;
access_log aus;
include /etc/nginx/conf.d/*.conf;
}
---
apiVersion: v1
kind: ConfigMap
Metadaten:
Name: app-conf
Namespace: Standard
Daten:
app.conf: „Server {listen 8080;Standort / {Standardtyp Text/Plain;expires -1;return 200 ‚Serveradresse: $server_addr:$server_port\nServername:$hostname\nDatum: $time_local\nURI: $request_uri\nAnforderungs-ID: $request_id\n‘;}Standort /healthz {return 200 ‚Ich bin glücklich und gesund :)‘;}}“
---
API-Version: v1
Art: Dienst
Metadaten:
Name: app-svc
Spezifikation:
Ports:
- Port: 80
ZielPort: 8080
Protokoll: TCP
Name: http
Selektor:
App: nginx
---
„Dieser Blogbeitrag kann auf Produkte verweisen, die nicht mehr verfügbar und/oder nicht mehr unterstützt werden. Die aktuellsten Informationen zu verfügbaren F5 NGINX-Produkten und -Lösungen finden Sie in unserer NGINX-Produktfamilie . NGINX ist jetzt Teil von F5. Alle vorherigen NGINX.com-Links werden auf ähnliche NGINX-Inhalte auf F5.com umgeleitet."