Kubernetes sucht beim Skalieren von Anwendungen freie Knoten, die die Anforderungen eines Containers an CPU und Hauptspeicher erfüllen. Ist die vorhandene Hardware jedoch ausgelastet, lassen sich mit KubeFed einfach zusätzlich weitere K8s-Cluster anbauen.
In der klassischen IT bedeutete dynamisches Skalieren für den Admin meist, dass er händisch neue virtuelle Maschinen starten musste, die manchmal ein manuelles Nacharbeiten benötigten. Anschließend musste er die Anwendung in einen bestehenden Cluster integrieren und gegebenenfalls auch noch Load Balancer umkonfigurieren. Kubernetes nimmt dem Admin all diese Arbeiten ab. Mit dem Kommando »kubectl scale deployment/webserver –replicas=5« startet Kubernetes fünf Instanzen des Webserver-Containers und sorgt dafür, dass sie laufen und sich erreichen lassen. Die Lastverteilung ist sichergestellt.
Das funktioniert allerdings nur, solange es im Cluster noch genügend Ressourcen gibt. Sind sie ausgeschöpft, gilt es, den Cluster um neue Knoten zu erweitern. Das ist zwar einfach zu konfigurieren, aber wenn es die Anschaffung neuer Hardware bedingt, bedeutet es zumindest eine Wartezeit, während der der Dienst nicht in der notwendigen Leistungsfähigkeit bereitsteht. Kommt Autoscaling zum Einsatz, stößt Kubernetes gegebenenfalls sogar unbemerkt an die Hardwaregrenzen.
Eine Möglichkeit, die Ressourcenknappheit zu überbrücken, stellt ein Ausweichen in die Public Cloud dar. Im einfachsten Fall mietet der Admin die benötigten Ressourcen in Form von VMs und koppelt sie an den Cluster an. Dazu müssen sich der bestehende Cluster und die Knoten in der Cloud direkt erreichen können, entweder über öffentliche Adressen oder eine VPN-Verbindung. Eine weitere Möglichkeit bietet das Föderieren von Kubernetes-Clustern. Das ermöglicht es dem Admin, Ressourcen eines zweiten, eigenständigen Clusters an den eigenen anzudocken und die Anwendungen auf beiden laufen zu lassen. Die Software dazu findet sich beim Projekt Kubernetes Cluster Federation (KubeFed [1]).
Installation
Im Folgenden gehen wir davon aus, dass Sie bereits einen Kubernetes-Cluster betreiben. Als Anbau dient im Beispiel ein gemanagter K8s-Cluster in der AWS Cloud, aber abgesehen von den Details des Zugriffs darauf funktioniert die beschriebene Installation mit jedem anderen Kubernetes-Cluster.
Die KubeFed-Dokumentation beschreibt die Installation per Helm-Chart. Im ersten Arbeitsschritt fügen Sie den lokal installierten Helm Charts das KubeFed-Repository hinzu (Listing 1, erste Zeile) und prüfen das Resultat (Zeile 2 und 3). Hat alles geklappt, stehen Helm nun mehrere Versionen des Charts zur Verfügung. Das Kommando aus Zeile 4 lieferte im Test die Version 0.9.0, die beim Einspielen des Charts (Zeile 5) als Parameter zum Einsatz kommt.
Listing 1
Installation
# helm repo add kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts # helm repo list kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts<C> # helm search repo kubefed # helm --namespace kube-federation-system upgrade -i kubefed kubefed-charts/kubefed --version=0.9.0 --create-namespace
Als nächster Arbeitsschritt steht nun die Aufnahme des ersten Clusters in die Föderation an. Zum Verwalten der Föderation laden Sie das Werkzeug Kubefedctl [2] herunter und kopieren es zur einfachen Verwendung am besten nach »/usr/local/bin/«.
Kubeconfig für mehrere Cluster
Den Zugriff auf den oder die Kubernetes-Cluster steuert die Datei »~/.kube/config«. Diese YAML-Datei enthält für jeden verwalteten Cluster eine ganze Reihe an Informationen. Diese umfassen den Cluster mit je einem CA-Zertifikat, einem Namen und einem Endpunkt für den Zugriff. Hinzu kommen die Benutzerdaten, die entweder Zertifikat und Private Key, das Token eines Service-Accounts, ein Skript oder Benutzernamen und Passwort enthalten. Solch ein Eintrag hat einen Namen.
Zu guter Letzt gibt es einen Kontext, der je einen Benutzer- und einen Cluster-Eintrag zusammenbindet. Außerdem enthält die Datei den Eintrag »current-context« der beschreibt, welcher der Kontexte greifen soll, wenn der Admin beim Aufruf von Kubectl keinen angibt. Die Datei bearbeiten Sie einfach mit einem Texteditor oder manipulieren sie mit Kubectl. Die in der Datei verwendeten Namen dienen lediglich der gegenseitigen Zuordnung.
Mit einem Kommando wie dem aus der ersten Zeile von Listing 2 fügen Sie der Föderation einen ersten Cluster hinzu. Im Beispiel ist »earth« der Name eines Cluster-Kontexts aus der Datei »~/.kube/config«. Anschließend prüfen Sie den Status des Clusters (zweite Zeile).
Listing 2
Cluster einfügen
# kubefedctl join earth --host-cluster-context=earth # kubectl -n kube-federation-system get kubefedclusters NAME AGE READY earth 41h True
Während der Recherche zu diesem Artikel stieß der Autor dabei in der Testumgebung allerdings auf ein kleines Problem: Weil der Benutzer kubeadm und der Cluster »kubernetes« hießen, nannte sich der Cluster-Kontext »kubeadm@kubernetes«. Der Klammeraffe störte allerdings Kubefedctl, der Join funktionierte erst nach einer manuellen Änderung des Namens.
Der zweite Cluster
Bei den großen Public-Cloud-Anbietern wie Amazon (AWS) oder Google (GCE) stehen Ihnen in der Regel zwei Möglichkeiten zur Verfügung, um Kubernetes zu betreiben: Entweder kommen normale virtuelle Maschinen zum Einsatz, auf denen Sie K8s selbst installieren, oder der Provider hält im Rahmen eines Platform-as-a-Service-Angebots fertige K8s-Cluster bereit. Bei denen starten zwar im Hintergrund auch virtuelle Maschinen, Sie erhalten als Übergabepunkt aber den Cluster.
Für diesen Artikel kommt das gemanagte Angebot von AWS namens Elastic Kubernetes Service (EKS) zum Einsatz. Das Anlegen dieses Clusters funktioniert zwar im Prinzip auf Knopfdruck, setzt aber einige Umgebungsparameter voraus, die Sie vorher anlegen müssen. Das umfasst:
- die Subnetze in den Availability-Zonen, in denen die Arbeitsknoten des Clusters laufen (mindestens zwei Netze in zwei Zonen),
- eine Berechtigungsrolle in AWS. unter der die Knoten laufen. Das steuert innerhalb der AWS-Infrastruktur, welche anderen Ressourcen die Kubernetes-Knoten auf welche Weise nutzen können.
- eine Security-Gruppe mit Firewall-Regeln, die den eingehenden Traffic zum Kubernetes-Cluster steuern.
Der eigentliche Kubernetes-Cluster besteht aus zwei Komponenten: der Control Plane, also dem eigentlichen Cluster, und der Node Group, auf die sich dann die in Kubernetes laufenden Container verteilen. Dazu kommt die Anbindung zwischen dem lokalen Rechenzentrum und der AWS Cloud. Prinzipiell ließe sich der komplette Cluster direkt über das Internet ansprechen, das erhöht aber die Angriffsfläche.
In einem ernst zu nehmenden Setup schalten Sie eine Site-to-Site-VPN-Verbindung zwischen dem eigenen Rechenzentrum und der Umgebung in AWS. Dementsprechend besitzen dann der Kubernetes-Cluster und alle darin laufenden Anwendungen nur private IP-Adressen und lassen sich nur innerhalb der AWS-Umgebung oder über das VPN erreichen. Die Security-Gruppen zum Netzwerkzugriff beinhalten als Quellen ebenfalls nur die privaten IP-Adressen der AWS-Umgebung und des lokalen RZs.
Der Autor hält den Kubernetes-Cluster in AWS nicht vor, sondern aktiviert ihn nur bei Bedarf. Dabei kommt das AWS-Orchestrierungswerkzeug CloudFormation zusammen mit Ansible zum Einsatz, um alle Komponenten als Stack in AWS zu erzeugen, die lokale Firewall mit einem VPN-Tunnel in diese Umgebung zu versorgen und das Routing auf den lokalen Kubernetes-Knoten anzupassen, damit sie den Cluster in AWS erreichen können. Abbildung 1 zeigt die so aufgebaute Infrastruktur. Auf AWS-Seite sind IP-Adressen aus dem Subnet 10.11.0.0/16 vergeben. Der Kubernetes-Cluster selbst benötigt noch Service-Adressen aus einem davon disjunkten Netz, im konkreten Fall 10.5.0.0/24. Die dicke schwarze Linie in der Abbildung symbolisiert den VPN-Tunnel über das Internet.
Damit Sie in einer solchen Konfiguration mit Kubectl beziehungsweise über die API auf den Cluster bei AWS zugreifen können, müssen Sie dafür Einträge in der Datei ».kube/config« hinzufügen. Das AWS-CLI stellt dazu ein eigenes Kommando bereit: Der Befehl »aws eks update-kubeconfig Cluster-Name« fügt die notwendigen Einträge hinzu. Auf dem Verwaltungsrechner muss neben den Kubernetes-Tools auch das AWS-Kommandozeilen-Interface installiert und so konfiguriert sein, dass es Zugriff auf das AWS-Konto hat.
Der Einträge in der Datei ».kube/config« für den EKS-Cluster sehen ähnlich aus. Allerdings melden Sie sich nicht über ein Token an, sondern mit dem Output eines Kommandos. Im Hintergrund führt Kubectl das Kommando »aws eks get-token –cluster-name vulkan« aus. Dabei ist vulkan der Name des Kubernetes-Clusters in AWS. In der Syntax der Kubernetes-Config-Datei sieht das Ganze als Benutzereintrag dann so aus wie in Listing 6.
Listing 3
Benutzereintrag
- name: kubernetes-eks-user
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
command: aws
args:
- eks
- get-token
- --cluster-name
- vulcan
Da die Argumente des Kommandos ein Feld bilden, schreibt man sie in YAML entsprechend als Liste untereinander. Der Cluster-Kontext heißt ebenfalls »vulcan«. Geht etwas schief, scrollen Sie am besten an den Anfang der Ausgabe des Kommandos: Hier befindet sich meist der relevanteste Teil der Informationen. Bei Rest handelt es sich um einen zum Teil sehr langen Stacktrace. Klappt alles, besteht die Föderation nun aus zwei Clustern, wie ein Aufruf von Kubectl bestätigt (Listing 4).
Listing 4
Federation prüfen
# kubectl -n kube-federation-system get kubefedclusters
NAME AGE READY
earth 2h True
vulcan 5m True
Benutzung
Bevor die Verteilung losgehen kann, müssen Sie die Ressourcentypen föderieren, die Sie verteilen wollen. Das können Pods, Services, Namespaces und so weiter sein. Hierzu dient wieder das Werkzeug Kubefedctl. Das Kommando »kubecfedctl enable pods« erlaubt es zum Beispiel, Ressourcen vom Typ Pod zu verteilen. Existiert ein Kubernetes-Namespace, den Sie im Ganzen föderieren möchten, erledigen Sie das mit folgendem Kommando:
# kubefedctl federate namespace demo --contents --enable-type
Die Option »–enable-type« sorgt dafür, dass die fehlenden Typen auch gleich föderiert werden. Zusätzlich können Sie noch eine Ressource vom Typ »FederatedNamespace« anlegen, mit der sich auf Namespace-Ebene steuern lässt, auf welchen Clustern K8s Ressourcen anlegt. Das klappt selbst auf der Ebene eines einzelnen Deployments, verursacht jedoch mehr Administrationsaufwand. Gerade bei der Verwendung von Cloud-Anbietern, bei denen Datenschutzbedenken bestehen, haben sie damit jedoch klar im Griff, wo welche Container laufen.
Zum geordneten Aufsetzen eines Namespaces für die Verwendung in der Föderation setzen Sie eine YAML-Datei wie die aus Listing 5 ein. Der Namespace »fedtestns« muss vor dem Erzeugen existieren. Über den Parameter »placement« steuern Sie, auf welche Cluster K8s die Ressourcen ausrollt. Um die Pods nun auf beiden Seiten des Clusters zu verteilen, müssen Sie sie anders einspeisen.
Listing 5
Federated Namespace
---
apiVersion: types.kubefed.io/v1beta1
kind: FederatedNamespace
metadata:
name: fedns
namespace: fedtestns
spec:
placement:
clusters:
- name: earth
- name: vulcan
Als Testfall kommt ein einfacher Webserver zum Einsatz. Das normale, unföderierte Deployment führt dazu, dass die Pods nur im lokalen Cluster laufen. Das Kommando zur Föderierung des Namespaces samt Inhalt verteilt alle bestehenden Ressourcen, sorgt aber nicht dafür, dass neu angelegte auch gleich verteilt werden. Hier haben Sie nun stattdessen die Möglichkeit, die Deployments direkt als »FederatedDeployment« anzulegen. Die YAML-Datei dazu zeigt Listing 6. Sie sieht der für ein einfaches Deployment sehr ähnlich, aber der Parameter »placement« sorgt dafür, dass die angegebenen Cluster auch das Deployment erben.
Listing 6
Federated Deployment
apiVersion: types.kubefed.io/v1beta1
kind: FederatedDeployment
metadata:
name: fedhttp
namespace: fedtestns
spec:
template:
metadata:
name: http
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
placement:
clusters:
- name: earth
- name: vulcan
Nach kurzer Zeit findet sich nun auf beiden Clustern je ein Pod und ein Deployment mit dem Webservice. Die Pods auf beiden Clustern lassen sich auch auf Port 80 ansprechen. Im Fall von AWS müssen Sie allerdings in der richtigen Security Group der AWS-Konfiguration diesen Port auch freischalten.
Für das Zusammenspiel der Pods in den Clustern ist es entscheidend, das Routing zwischen beiden Clustern so aufzusetzen, dass sie sich gegenseitig erreichen. Auch Firewall-Regeln und Security Groups müssen Sie passend konfigurieren. Hier empfiehlt es sich, auf ein Automatisierungswerkzeug wie Ansible zu setzen, wenn der Cluster beim Cloud-Anbieter nur bei Bedarf aktiviert werden soll.
Wie das Deployment müssen Sie auch den Service, so Sie einen verwenden, als »FederatedService« ausrollen. Listing 7 zeigt den Service zum Deployment aus Listing 6. Die Namensauflösung der Services läuft dabei lokal. Das heißt, dass »fed-service« jeweils zur Cluster-IP im lokalen Cluster auflöst. Das gilt es beim Service-Design zu bedenken.
Listing 7
Federated Service
apiVersion: types.kubefed.io/v1beta1
kind: FederatedService
metadata:
name: fed-service
namespace: fedtestns
spec:
template:
spec:
selector:
app: httpbin
type: NodePort
ports:
- name: http
port: 80
placement:
clusters:
- name: earth
- name: vulcan
Auch Komponenten wie Persistent Volumes werden auf den Clustern lokal angelegt und müssen dort befüllt werden. Greifen Pods auf entfernte Ressourcen zu, müssen Sie auf beiden Clustern sicherstellen, dass sich diese erreichen lassen. Dabei gilt es, sowohl die IP-Erreichbarkeit als auch die Namensauflösung zu beachten.
Indem Sie die föderierten Ressourcen löschen, bauen Sie auch die Ressourcen wieder ab. Um nur einen Cluster aus der Verteilung zu nehmen, entfernen Sie den Cluster unter »placement«. Den zweiten Cluster konfigurieren Sie mit folgendem Kommando wieder heraus:
# kubefedctl unjoin vulcan --host-cluster-context earth --v=2
Im Test musste der Autor anschließend allerdings die im zweiten Cluster ausgerollten Ressourcen manuell aufräumen. Diesen Arbeitsschritt sparen Sie sich, indem Sie den Cluster beim kostenpflichtigen Public Cloud Provider danach vollständig löschen.
Fazit
Kubernetes Cluster Federation macht das Anbinden eines oder mehrerer Cluster als Ressourcenerweiterung denkbar einfach. Das entbindet Sie nicht davon, sich Gedanken darüber zu machen, was wo läuft. Zudem gilt es, die Erweiterung so anzulegen, dass die Verbraucher des Diensts sie auch nutzen können. Im Fall einer Sonderaktion in einem Webshop etwa müssen die Anfragen der Kunden bei den Containern im neuen Cluster genauso ankommen wie bei den bisher vorhandenen, sonst bringt Föderation keine Leistungssteigerung. Rechnen Sie damit, dass solche Situationen öfter vorkommen, empfiehlt es sich, den eigenen Cluster gleich als Föderation mit einem Mitglied laufen zu lassen. Dann fallen bei der Erweiterung nur noch die dazu gehörenden Arbeitsschritte an. (jcb/jlu)
Der Autor
Konstantin Agouros arbeitet als Head of Networks & New Technologies bei der Matrix Technology GmbH und berät dort mit seinem Team Kunden in Sachen Open Source, Sicherheit und Cloud. Sein Buch “Software Defined Networking” ist bei de Gruyter erschienen.
Infos
- Projektseite auf Github: https://github.com/kubernetes-sigs/kubefed
- Kubefedctl: https://github.com/kubernetes-sigs/kubefed/releases






