Kubernetes ist ein von Google entwickeltes Open-Source-System zum Ausführen und Verwalten von containerisierten, auf Microservices basierenden Anwendungen in einem Cluster. Benutzer von Kubernetes müssen die in Kubernetes erstellten Dienste häufig von außerhalb ihres Kubernetes-Clusters zugänglich machen.
Obwohl Kubernetes integrierte Lösungen zum Bereitstellen von Diensten bereitstellt (siehe Bereitstellen von Kubernetes-Diensten mit integrierten Lösungen weiter unten), sind Sie bei diesen Lösungen auf Layer-4-Lastausgleich oder Round-Robin-HTTP-Lastausgleich beschränkt.
Dieser Beitrag zeigt, wie Sie NGINX Plus als erweiterte Layer-7-Lastausgleichslösung verwenden, um Kubernetes-Dienste dem Internet zugänglich zu machen, unabhängig davon, ob Sie Kubernetes in der Cloud oder auf Ihrer eigenen Infrastruktur ausführen.
Wir setzen voraus, dass Sie über grundlegende Kenntnisse von Kubernetes (Pods, Dienste, Replikationscontroller und Labels) und einen laufenden Kubernetes-Cluster verfügen. Weitere Informationen zu Kubernetes finden Sie im offiziellen Kubernetes-Benutzerhandbuch .
Kubernetes bietet mehrere Optionen zum Bereitstellen von Diensten . Zwei davon – NodePort und LoadBalancer – entsprechen einem bestimmten Diensttyp. Eine dritte Option, Ingress API, wurde als Beta in Kubernetes Version 1.1 verfügbar.
Wenn Sie den Diensttyp als NodePort angeben, ist der Dienst auf jedem Kubernetes-Knoten auf demselben Port verfügbar. Um den Dienst dem Internet zugänglich zu machen, machen Sie einen oder mehrere Knoten auf diesem Port verfügbar. Um eine hohe Verfügbarkeit zu erreichen, können Sie mehrere Knoten bereitstellen und den Datenverkehr mithilfe eines DNS‑basierten Lastenausgleichs auf diese verteilen oder die Knoten hinter einem Lastenausgleich Ihrer Wahl platzieren.
Wenn eingehender Datenverkehr einen Knoten am Port erreicht, wird die Last zwischen den Pods des Dienstes ausgeglichen. Der Lastausgleich, der durch den auf jedem Knoten ausgeführten Kubernetes-Netzwerkproxy ( Kube-Proxy
) durchgeführt wird, ist auf TCP/UDP-Lastausgleich beschränkt.
Wenn Sie den Diensttyp als LoadBalancer angeben, wird ein Cloud-Load Balancer zugewiesen, der den eingehenden Datenverkehr auf die Pods des Dienstes verteilt.
Die LoadBalancer-Lösung wird nur von bestimmten Cloud-Anbietern und Google Container Engine unterstützt und ist nicht verfügbar, wenn Sie Kubernetes auf Ihrer eigenen Infrastruktur ausführen. Darüber hinaus können Sie mit Kubernetes nur Round-Robin-TCP-Lastausgleich konfigurieren, auch wenn der Cloud-Load Balancer über erweiterte Funktionen wie Sitzungspersistenz oder Anforderungszuordnung verfügt.
Durch das Erstellen einer Ingress- Ressource können Sie Dienste im Internet unter benutzerdefinierten URLs (z. B. Dienst A unter der URL /foo und Dienst B unter der URL /bar ) und mehreren virtuellen Hostnamen (z. B. foo.example.com für eine Gruppe von Diensten und bar.example.com für eine andere Gruppe) verfügbar machen. Ein Ingress-Controller verbraucht eine Ingress-Ressource und richtet einen externen Load Balancer ein.
Ein Ingress-Controller ist kein Teil einer Standardbereitstellung von Kubernetes: Sie müssen den Controller auswählen, der Ihren Anforderungen am besten entspricht, oder selbst einen implementieren und ihn Ihrem Kubernetes-Cluster hinzufügen. Es wird erwartet, dass bald viele Controller-Implementierungen erscheinen, aber derzeit ist die einzige verfügbare Implementierung der Controller für den Google Compute Engine HTTP Load Balancer , der nur funktioniert, wenn Sie Kubernetes auf Google Compute Engine oder Google Container Engine ausführen. Die Ingress-API unterstützt nur Round-Robin-HTTP-Lastausgleich, auch wenn der eigentliche Lastenausgleich erweiterte Funktionen unterstützt.
Zum Zeitpunkt des Schreibens dieses Artikels befinden sich sowohl die Ingress-API als auch der Controller für den HTTP Load Balancer von Google Compute Engine in der Betaphase.
Update – NGINX Ingress Controller für NGINX und NGINX Plus ist jetzt in unserem GitHub-Repository verfügbar. Produktdetails finden Sie unter NGINX Ingress Controller .
Obwohl die oben genannten Lösungen einfach einzurichten sind und sofort einsatzbereit sind, bieten sie keine erweiterten Funktionen, insbesondere keine Funktionen im Zusammenhang mit dem Layer 7-Loadbalancing.
[Editor – Dieser Abschnitt wurde aktualisiert, um auf die NGINX Plus API zu verweisen, die das ursprünglich hier besprochene separate dynamische Konfigurationsmodul ersetzt und veraltet.]
Um NGINX Plus in Kubernetes zu integrieren, müssen wir sicherstellen, dass die NGINX Plus-Konfiguration mit Kubernetes synchronisiert bleibt und Änderungen an Kubernetes-Diensten, wie etwa das Hinzufügen oder Löschen von Pods, widerspiegelt. Mit NGINX Open Source ändern Sie die NGINX-Konfigurationsdatei manuell und führen einen Konfigurationsneuladen durch. Mit NGINX Plus gibt es zwei Möglichkeiten, die Konfiguration dynamisch zu aktualisieren:
Wir gehen davon aus, dass Sie bereits über einen laufenden Kubernetes-Cluster und einen Host mit dem Dienstprogramm „kubectl“
zur Verwaltung des Clusters verfügen. Anweisungen finden Sie in der Kubernetes-Anleitung „Erste Schritte“ für Ihren Clustertyp. Sie müssen außerdem ein NGINX Plus-Docker-Image erstellt haben. Anweisungen dazu finden Sie unter „Bereitstellen von NGINX und NGINX Plus mit Docker“ in unserem Blog.
Hier ist ein Überblick darüber, was wir tun werden:
Hinweise: Wir haben die in diesem Blog beschriebene Lösung mit Kubernetes 1.0.6 getestet, das auf Google Compute Engine und einem lokalen Vagrant -Setup ausgeführt wird, das wir im Folgenden verwenden.
In Befehlen werden Werte, die für Ihr Kubernetes-Setup anders sein können, kursiv angezeigt.
Wir platzieren NGINX Plus in einem Kubernetes-Pod auf einem Knoten, den wir dem Internet zugänglich machen. Unser Pod wird durch einen Replikationscontroller erstellt, den wir ebenfalls einrichten. Unsere Kubernetes-spezifische NGINX Plus-Konfigurationsdatei befindet sich in einem vom NGINX Plus-Pod und dem Knoten gemeinsam genutzten Ordner, was die Wartung vereinfacht.
Um den Knoten zu kennzeichnen, auf dem der NGINX Plus-Pod ausgeführt wird, fügen wir diesem Knoten eine Bezeichnung hinzu. Wir erhalten die Liste aller Knoten, indem wir Folgendes ausführen:
$ kubectl get nodes NAME LABELS STATUS 10.245.1.3 Kubernetes.io/hostname=10.245.1.3 Bereit 10.245.1.4 Kubernetes.io/hostname=10.245.1.4 Bereit 10.245.1.5 Kubernetes.io/hostname=10.245.1.5 Bereit
Wir wählen den ersten Knoten aus und fügen ihm eine Beschriftung hinzu, indem wir Folgendes ausführen:
$ kubectl Label-Knoten10.245.1.3 Rolle=nginxplus
Wir erstellen keinen NGINX Plus-Pod direkt, sondern über einen Replikationscontroller. Wir konfigurieren den Replikationscontroller für das NGINX Plus-Pod in einer Kubernetes-Deklarationsdatei namens nginxplus-rc.yaml .
Replikate
auf eins, was bedeutet, dass Kubernetes sicherstellt, dass immer ein NGINX Plus-Pod ausgeführt wird: Wenn der Pod ausfällt, wird er durch einen neuen Pod ersetzt.„nodeSelector“
geben wir an, dass der NGINX Plus-Pod auf einem Knoten mit der Bezeichnung „Rolle:
nginxplus“
erstellt wird.API-Version: v1
Art: ReplicationController
Metadaten:
Name: nginxplus-rc
Spezifikation:
Replikate: 1
Selektor:
App: nginxplus
Vorlage:
Metadaten:
Labels:
App: nginxplus
Spezifikation:
Knotenselektor:
Rolle: nginxplus
Container:
- Name: nginxplus
ImagePullPolicy: IfNotPresent
Bild: nginxplus
Ports:
- Name: http
ContainerPort: 80
HostPort: 80
- Name: http-alt
ContainerPort: 8080
HostPort: 8080
VolumeMounts:
- MountPath: "/etc/nginx/conf.d"
Name: etc-nginx-confd
Volumes:
- HostPath:
Pfad: "/etc/nginx/conf.d"
Name: etc-nginx-confd
Wie oben erwähnt, haben wir bereits ein NGINX Plus-Docker-Image erstellt. Jetzt machen wir es auf dem Knoten verfügbar. Der Einfachheit halber verwenden wir kein privates Docker-Repository und laden das Image einfach manuell auf den Knoten.
Auf dem Host, auf dem wir das Docker-Image erstellt haben, führen wir den folgenden Befehl aus, um das Image in einer Datei zu speichern:
$ docker save -o nginxplus.tar nginxplus
Wir übertragen nginxplus.tar auf den Knoten und führen den folgenden Befehl auf dem Knoten aus, um das Image aus der Datei zu laden:
$ docker load -i nginxplus.tar
Im Ordner /etc/nginx des NGINX Plus-Containers behalten wir die standardmäßige Hauptkonfigurationsdatei nginx.conf bei, die mit den NGINX Plus-Paketen geliefert wird. Die Include-
Direktive in der Standarddatei liest andere Konfigurationsdateien aus dem Ordner /etc/nginx/conf.d ein . Wie in der Deklarationsdatei für den NGINX Plus-Replikationscontroller ( nginxplus-rc.yaml ) angegeben, geben wir den Ordner /etc/nginx/conf.d auf dem NGINX Plus-Knoten für den Container frei. Durch die Freigabe können wir Änderungen an den im Ordner (auf dem Knoten) gespeicherten Konfigurationsdateien vornehmen, ohne das NGINX Plus Docker-Image neu erstellen zu müssen, was wir tun müssten, wenn wir den Ordner direkt im Container erstellen würden. Wir legen unsere Kubernetes-spezifische Konfigurationsdatei ( backend.conf ) im freigegebenen Ordner ab.
Erstellen wir zunächst den Ordner /etc/nginx/conf.d auf dem Knoten.
$ sudo mkdir -p /etc/nginx/conf.d
Dann erstellen wir dort die Datei backend.conf und fügen diese Anweisungen ein:
Resolver
– Definiert den DNS-Server, den NGINX Plus verwendet, um den Domänennamen, den wir zur Identifizierung unserer Upstream-Server verwenden, regelmäßig neu aufzulösen (in der Server-
Direktive innerhalb des Upstream-
Blocks, siehe nächster Punkt). Wir identifizieren diesen DNS-Server anhand seines Domänennamens kube-dns.kube-system.svc.cluster.local . Der gültige
Parameter weist NGINX Plus an, alle fünf Sekunden eine Neuauflösungsanforderung zu senden.
(Beachten Sie, dass sich der Auflösungsprozess für diese Anweisung von dem für Upstream-Server unterscheidet: Dieser Domänenname wird nur aufgelöst, wenn NGINX gestartet oder neu geladen wird, und NGINX Plus verwendet zur Auflösung den oder die System-DNS-Server, die in der Datei /etc/resolv.conf definiert sind.)
Upstream
– Erstellt eine Upstream-Gruppe namens „Backend“, die die Server enthält, die den von uns verfügbar gemachten Kubernetes-Dienst bereitstellen. Anstatt die Server einzeln aufzulisten, identifizieren wir sie mit einem vollqualifizierten Hostnamen in einer einzigen Serverdirektive
. Der Resolve-
Parameter weist NGINX Plus an, den Hostnamen zur Laufzeit entsprechend den mit der Resolver-
Direktive angegebenen Einstellungen erneut aufzulösen.
Da sowohl Kubernetes DNS als auch NGINX Plus (R10 und höher) DNS Service ( SRV
)-Einträge unterstützen, kann NGINX Plus die Portnummern von Upstream-Servern über DNS abrufen. Wir schließen den Serviceparameter
ein, damit NGINX Plus SRV-
Einträge anfordert, und geben dabei den Namen ( _http
) und das Protokoll ( _tcp
) für die von unserem Service bereitgestellten Ports an. Wir deklarieren diese Werte in der Datei webapp-svc.yaml, die weiter unten im Abschnitt „Erstellen des Replikationscontrollers für den Dienst“ beschrieben wird.
Weitere Informationen zur Diensterkennung mit DNS finden Sie unter „Verwenden von DNS für die Diensterkennung mit NGINX und NGINX Plus“ in unserem Blog.
Server
(zweimal) – Definieren Sie zwei virtuelle Server:
Der erste Server lauscht auf Port 80 und verteilt die Last eingehender Anfragen für /webapp (unseren Dienst) auf die Pods, auf denen Dienstinstanzen ausgeführt werden. Wir richten auch aktive Gesundheitschecks ein.
Der zweite Server lauscht auf Port 8080. Hier richten wir die Live-Aktivitätsüberwachung von NGINX Plus ein. Später werden wir es verwenden, um zu überprüfen, ob NGINX Plus richtig neu konfiguriert wurde.
[Editor – Die Konfiguration für diesen zweiten Server wurde aktualisiert, um die NGINX Plus API zu verwenden, die das ursprünglich verwendete separate Statusmodul ersetzt und veraltet.]
Resolver kube-dns.kube-system.svc.cluster.local gültig=5s;
Upstream-Backend {
Zone Upstream-Backend 64k;
Server webapp-svc.default.svc.cluster.local Service=_http._tcp Resolve;
}
Server {
Listen 80;
Statuszone Backend-Server;
Standort /webapp {
Proxy-Pass http://backend;
Health-Check;
}
}
Server {
Listen 8080;
Root /usr/share/nginx/html;
Standort = /dashboard.html { }
Standort = / {
Return 302 /dashboard.html;
}
Standort /API {
API Write=on;
}
}
Jetzt können wir den Replikationscontroller erstellen, indem wir diesen Befehl ausführen:
$ kubectl erstellen -f nginxplus-rc.yaml
Um zu überprüfen, ob der NGINX Plus-Pod erstellt wurde, führen wir Folgendes aus:
$ kubectl get pods NAME BEREIT STATUS NEUSTART ALTER nginxplus-rc-0ts5t 1/1 Läuft 0 17s
Wir führen Kubernetes auf einem lokalen Vagrant-Setup aus, daher wissen wir, dass die externe IP-Adresse unseres Knotens 10.245.1.3 ist, und wir werden diese Adresse für den Rest dieses Beispiels verwenden. Wenn Sie Kubernetes bei einem Cloud-Anbieter ausführen, können Sie die externe IP-Adresse Ihres Knotens abrufen, indem Sie Folgendes ausführen:
$ kubectl get nodes Knotenname -o json | grep -i externalIP -A 1 "Typ": "ExterneIP", "Adresse": XXX.XXX.XXX.XXX
Wenn Sie eine Cloud verwenden, vergessen Sie nicht, eine Firewall-Regel einzurichten, damit der NGINX Plus-Knoten eingehenden Datenverkehr akzeptieren kann. Weitere Informationen finden Sie in der Dokumentation Ihres Cloud-Anbieters.
Wir können überprüfen, ob unser NGINX Plus-Pod aktiv und betriebsbereit ist, indem wir uns das Dashboard zur Live-Aktivitätsüberwachung von NGINX Plus ansehen, das auf Port 8080 unter der externen IP-Adresse des Knotens verfügbar ist (in unserem Fall also http://10.245.1.3:8080/dashboard.html ). Wenn wir an dieser Stelle allerdings schauen, sehen wir noch keine Server für unseren Dienst, da wir den Dienst noch nicht erstellt haben.
Jetzt ist es an der Zeit, einen Kubernetes-Dienst zu erstellen. Unser Dienst besteht aus zwei Webservern, die jeweils eine Webseite mit Informationen über den Container bereitstellen, in dem sie ausgeführt werden.
Zuerst erstellen wir einen Replikationscontroller, damit Kubernetes sicherstellt, dass immer die angegebene Anzahl von Webserver-Replikaten (Pods) im Cluster ausgeführt wird. Hier ist die Deklarationsdatei ( webapp-rc.yaml ):
API-Version: v1Art: ReplicationController
Metadaten:
Name: webapp-rc
Spezifikation:
Replikate: 2
Selektor:
App: Webanwendung
Vorlage:
Metadaten:
Beschriftungen:
App: Webanwendung
Spezifikation:
Container:
- Name: Hallo
Bild: nginxdemos/hallo
Ports:
- ContainerPort: 80
Unsere Steuerung besteht aus zwei Webservern. Wir deklarieren einen Controller, der aus Pods mit einem einzelnen Container besteht und Port 80 freigibt. Das Image nginxdemos/hello wird vom Docker Hub abgerufen.
Um den Replikationscontroller zu erstellen, führen wir den folgenden Befehl aus:
$ kubectl create -f webapp-rc.yaml
Um zu überprüfen, ob unsere Pods erstellt wurden, können wir den folgenden Befehl ausführen. Wir verwenden den Label-Selektor app=webapp
, um nur die Pods abzurufen, die im vorherigen Schritt vom Replikationscontroller erstellt wurden:
$ kubectl get pods -l app=webapp NAME BEREIT STATUS NEUSTART ALTER webapp-rc-544f1 1/1 Läuft 0 2m webapp-rc-uk6pm 1/1 Läuft 0 2m
Als Nächstes erstellen wir einen Dienst für die von unserem Replikationscontroller erstellten Pods. Wir deklarieren den Dienst mit der folgenden Datei ( webapp-service.yaml ):
API-Version: v1kind: Dienst
Metadaten:
Name: webapp-svc
Spezifikation:
ClusterIP: Keine
Ports:
- Port: 80
ZielPort: 80
Protokoll: TCP
Name: http
Selektor:
App: Webanwendung
Hier deklarieren wir einen speziellen Headless-Dienst , indem wir das Feld ClusterIP
auf None
setzen. Bei diesem Diensttyp wird keine Cluster-IP-Adresse zugewiesen und der Dienst ist nicht über den Kube-Proxy verfügbar. Eine DNS-Abfrage an den Kubernetes-DNS gibt mehrere A-
Einträge zurück (die IP-Adressen unserer Pods).
Wir geben auch den Port an, den NGINX Plus zum Verbinden der Pods verwenden wird. Neben der Angabe der Port- und Zielportnummer geben wir den Namen ( http
) und das Protokoll ( TCP
) an. Wir verwenden diese Werte in der NGINX Plus-Konfigurationsdatei, in der wir NGINX Plus anweisen, die Portnummern der Pods über DNS mithilfe von SRV-
Einträgen abzurufen.
Indem wir das Auswahlfeld
auf app:
webapp
setzen, deklarieren wir, welche Pods zum Dienst gehören, nämlich die von unserem NGINX-Replikationscontroller erstellten Pods (definiert in webapp-rc.yaml ).
Wir führen den folgenden Befehl aus, der den Dienst erstellt:
$ kubectl create -f webapp-service.yaml
Wenn wir jetzt die Dashboard-Seite aktualisieren und oben rechts auf die Registerkarte „Upstreams“ klicken, sehen wir die beiden Server, die wir hinzugefügt haben.
Wir können auch überprüfen, ob NGINX Plus den Datenverkehr zwischen den Pods des Dienstes ausgleicht. Wenn dies der Fall ist und wir in einem Browser auf http://10.245.1.3/webapp/ zugreifen, zeigt uns die Seite Informationen über den Container an, in dem der Webserver ausgeführt wird, beispielsweise den Hostnamen und die IP-Adresse.
Wenn wir diese Seite mehrmals aktualisieren und uns das Status-Dashboard ansehen, sehen wir, wie die Anfragen auf die beiden Upstream-Server verteilt werden.
[Editor – Dieser Abschnitt wurde aktualisiert, um die NGINX Plus API zu verwenden, die das ursprünglich verwendete separate Statusmodul ersetzt und veraltet.]
Fügen wir nun unserem Dienst zwei weitere Pods hinzu und stellen sicher, dass die NGINX Plus-Konfiguration erneut automatisch aktualisiert wird. Wir führen diesen Befehl aus, um die Anzahl der Pods durch Skalierung des Replikationscontrollers auf vier zu ändern:
$ kubectl scale rc webapp-rc --replicas=4 skaliert
Um zu überprüfen, ob NGINX Plus neu konfiguriert wurde, können wir uns erneut das Dashboard ansehen, dieses Mal verwenden wir jedoch stattdessen die NGINX Plus-API . Wir führen den folgenden Befehl aus, mit10.245.1.3
ist die externe IP-Adresse unseres NGINX Plus-Knotens und3
die Version der NGINX Plus API . Um die JSON-Ausgabe ordentlich zu formatieren, leiten wir sie an jq
weiter.
$ locken -s10.245.1.3 :8080/API/3 /http/upstreams/backend/servers | jq { "Peers": [ { "ID": 1, "Server": "10.0.0.1:80", "Backup": false, "Gewicht": 1, „Status“: „ungesund“, „aktiv“: 0, "Anfragen": 1, "Antworten": { "1xx": 0, "2xx": 0, "3xx": 0, "4xx": 0, "5xx": 0, "gesamt": 0 }, "gesendet": 0, "empfangen": 0, „fehlgeschlagen“: 0, „nicht verfügbar“: 0, "Gesundheitschecks": { "Checks": 1, „fehlgeschlagen“: 1, „ungesund“: 1, "last_passed": falsch }, "Ausfallzeit": 33965, "downstart": 1445378182275, "ausgewählt": 1445378131000 }, { "id": 2, "Server": "10.246.1.6:80", ... }, { "id": 3. "Server": "10.246.3.2:80", ... { "id": 4, "Server": "10.0.0.2:80", ... } ], "keepalive": 0 }
Das Peers-
Array in der JSON-Ausgabe hat genau vier Elemente, eines für jeden Webserver.
Reduzieren wir nun die Anzahl der Pods von vier auf eins und überprüfen den NGINX Plus-Status noch einmal:
$ kubectl scale rc webapp-rc --replicas=1 skaliert $ curl -s10.245.1.3 :8080/API/3 /http/Upstreams/Backend/Server | jq
Jetzt enthält das Peer-
Array in der JSON-Ausgabe nur ein Element (die Ausgabe ist dieselbe wie für den Peer mit der ID 1 im vorherigen Beispielbefehl).
Nachdem NGINX Plus nun installiert und ausgeführt wird, können wir dessen erweiterte Funktionen wie Sitzungspersistenz , SSL/TLS-Terminierung , Anforderungsrouting , erweiterte Überwachung und mehr nutzen.
Dank der in NGINX Plus verfügbaren Optionen zur sofortigen Neukonfiguration können Sie es problemlos in Kubernetes integrieren: entweder programmgesteuert über eine API oder vollständig über DNS. Die Verwendung von NGINX Plus zum Bereitstellen von Kubernetes-Diensten im Internet bietet viele Funktionen, die den aktuellen integrierten Kubernetes-Lastausgleichslösungen fehlen.
Um herauszufinden, wie NGINX Plus mit Kubernetes zusammenarbeitet, starten Sie noch heute Ihre kostenlose 30-Tage-Testversion oder kontaktieren Sie uns , um Ihren Anwendungsfall zu besprechen.
„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."