Dieser Beitrag ist aus einer Notiz entstanden, die die ersten Schritte mit VKS (VMware vSphere Kubernetes Service) erklärt, insbesondere die Erstellung eines eigenen Guest-Clusters in einem eigenen Namespace.
Die Begrifflichkeiten
Falls Sie sich hauptsächlich mit Vanilla Kubernetes beschäftigen, lohnt es sich, die VKS in wenigen Worten zu erklären. Die Kubernetes-Cluster werden ganz grob in vSphere nach dem Prinzip der Matrjoschka-Schachtelpuppen angelegt:
Supervisor > Namespaces (mehrere) > einzelne VKS Cluster (Guest Cluster)
Supervisor
Die höchste Ebene ist ein Objekt namens „Supervisor”. Im VKS gibt es immer genau drei Supervisor-Control-Plane-VMs. Die Worker-Nodes sind die ESXi-Hosts selbst. Jeder Host wird über den Spherelet (ein kubelet-Äquivalent auf dem Host) zum Worker-Node. Separate Worker-VMs gibt es nicht. Die Zahl der Worker entspricht damit der Zahl der ESXi-Hosts im vSphere Cluster.
Auf dem Supervisor ist VKS selbst als Kubernetes Service installiert (Workload Management > Services > Kubernetes Service). z. B. v1.32.7+vmware.5-fips-vsc…. Seit vSphere 8.0 U3 ist dieser Service von der Supervisor-Version entkoppelt und lässt sich getrennt aktualisieren.
Namespace
Ein Namespace ist eine logische Gliederung innerhalb des Supervisors. Die Kernaufgabe eines Namespaces ist, eine logische Grenze für die Vergabe von Permissions (RBAC), Storage-Policies, VM-Classes und Compute-Ressourcen zu bilden.
Guest Cluster
Ein Guest Cluster ist im Grunde ein vollwertiger CNCF-konformer Kubernetes-Cluster, der innerhalb eines Namespace angelegt wird.
Die drei Bausteine: ClusterClass, VKr und OS-Image
Um den Guest Cluster in der YAML-Datei korrekt beschreiben zu können, sind weitere Angaben erforderlich. Zwei davon sind echte Felder in der YAML-Datei: die ClusterClass (classRef) und die Version (version).
ClusterClass
ClusterClass beschreibt die VKS-Topologie als eine Vorlage, die den Aufbau des Clusters definiert (Control-Plane, Worker-Pools, verfügbare Variablen). VKS liefert fertige, versionierte Klassen mit.
Wie prüft man verfügbare ClusterClasses?
kubectl get clusterclass -A | grep vmware-system-vks-public
Erwartbare Ergebnisse:
NAMESPACE NAME READY AGE vmware-system-vks-public builtin-generic-v3.1.0 True 8d vmware-system-vks-public builtin-generic-v3.2.0 True 8d vmware-system-vks-public builtin-generic-v3.3.0 True 8d vmware-system-vks-public builtin-generic-v3.4.0 True 8d vmware-system-vks-public builtin-generic-v3.5.0 True 7d6h vmware-system-vks-public builtin-generic-v3.6.0 True 7d6h vmware-system-vks-public builtin-generic-v3.7.0 True 7d6h
Der Name builtin-generic-vX.Y.0 wird in classRef.name verwendet, der Namespace vmware-system-vks-public in classRef.namespace. Die älteren (3.1.x > v3.7.0), kompatiblen Klassen sind weiterhin vorhanden und können genutzt werden.
Es ist ganz üblich, dass mehrere builtin-generic-Versionen nebeneinander existieren. Jede VKS-Version bringt ihre eigene ClusterClass mit, ältere bleiben für bestehende Cluster erhalten. Die jüngeren Versionen(hier v3.5.0–v3.7.0, erkennbar am kleineren AGE) sind mit der Aktualisierung des Kubernetes Service auf die Version 3.7.1+v1.36 dazugekommen.
Diese offizielle Broadcom-Seite „ClusterClass Variable Reference” ist Ihre absolute Single Source of Truth für die Variablen der VKS-ClusterClass.
KubernetesRelease
KubernetesRelease (VKr) beschreibt die jeweilige Kubernetes-Version. Es handelt sich um eine von VMware signierte Kubernetes-Distribution, die eine bestimmte Kubernetes-Version zusammen mit einem passenden OS-Image, Bootstrap-Artefakte sowie den Kernpaketen (CNI, CSI) enthält (oder darauf verweist).
Wie prüft man verfügbare KubernetesReleases? Der Befehl kubectl get kubernetesreleases lässt sich auch als kubectl get kr abkürzen.
kubectl get kubernetesreleases | grep -E 'NAME|1\.35|1\.36'
Erwartbare Ergebnisse:
NAME VERSION READY COMPATIBLE UPDATES AVAILABLE AGE v1.35.0---vmware.2-vkr.4 v1.35.0+vmware.2-vkr.4 False False v1.35.2---vmware.1-vkr.3 8d v1.35.2---vmware.1-vkr.3 v1.35.2+vmware.1-vkr.3 True True 8d v1.35.5---vmware.1-vkr.1 v1.35.5+vmware.1-vkr.1 True True 8d v1.35.6---vmware.2-vkr.3 v1.35.6+vmware.2-vkr.3 True True 8d v1.36.1---vmware.4-vkr.5 v1.36.1+vmware.4-vkr.5 True True 8d v1.36.2---vmware.2-vkr.3 v1.36.2+vmware.2-vkr.3 True True 8d
Eine Zeile mit READY=True und COMPATIBLE=True bedeutet, dass diese Versionen wählbar sind. Der Wert aus der Spalte NAME (mit – – -) wird in version eingetragen.
OSImage
OSImage legt fest, welche Image-Datei mit welcher Version als OS-Basis (Photon, Ubuntu) für die Node-VM verwendet wird.
Wie prüft man verfügbare OSImages?
kubectl get osimages | grep -E 'NAME|1\.35|1\.36'
Erwartbare Ergebnisse:
NAME VERSION OS-NAME OS-VERSION ARCH TYPE AGE vmi-062b7e890f2e09522 v1.35.6+vmware.2 ubuntu 22.04 amd64 cvmi 8d vmi-09e08419c49071c82 v1.35.2+vmware.1 photon 5 amd64 cvmi 8d vmi-0ca12bf184479de9a v1.36.1+vmware.4 ubuntu 24.04 amd64 cvmi 8d vmi-15cdf41add09f3439 v1.35.0+vmware.2 photon 5 amd64 cvmi 8d vmi-1e3549495aafdad02 v1.36.1+vmware.4 photon 5 amd64 cvmi 8d vmi-27b4cf8faef707f6b v1.35.2+vmware.1 ubuntu 24.04 amd64 cvmi 8d vmi-2c43b2570fdffa599 v1.35.5+vmware.1 ubuntu 24.04 amd64 cvmi 8d vmi-3a3c5cef08debea3d v1.36.1+vmware.4 ubuntu 22.04 amd64 cvmi 8d vmi-751c19d8094c5222f v1.35.2+vmware.1 ubuntu 22.04 amd64 cvmi 8d vmi-7c87cd337fbd49951 v1.35.0+vmware.2 ubuntu 22.04 amd64 cvmi 8d vmi-7e83543eef5f58d65 v1.35.6+vmware.2 photon 5 amd64 cvmi 8d vmi-7f82c96298ecc4630 v1.35.5+vmware.1 photon 5 amd64 cvmi 8d vmi-902c05d4fd4b92fd2 v1.35.5+vmware.1 ubuntu 22.04 amd64 cvmi 8d vmi-b032c228b746e2b56 v1.36.2+vmware.2 ubuntu 24.04 amd64 cvmi 8d vmi-b7ca083ec018c5470 v1.36.2+vmware.2 ubuntu 24.04 amd64 cvmi 8d vmi-b9fd53a6e5ab721df v1.36.2+vmware.2 photon 5 amd64 cvmi 8d vmi-c476f321ab526101c v1.35.6+vmware.2 ubuntu 24.04 amd64 cvmi 8d vmi-da7c501408e59230f v1.36.2+vmware.2 ubuntu 22.04 amd64 cvmi 8d
Standardmäßig wird Photon ausgewählt. Soll eine bestimmte Version von Ubuntu verwendet werden, müssen folgende Parameter in die YAML-Datei eingefügt werden:
controlPlane:
metadata:
annotations:
run.tanzu.vmware.com/resolve-os-image: os-name=ubuntu,os-version=24.04
replicas: 1
workers:
machineDeployments:
- class: node-pool
name: worker-pool-01
replicas: 1
metadata:
annotations:
run.tanzu.vmware.com/resolve-os-image: os-name=ubuntu,os-version=24.04
und zwar nicht als eigenes Feld, sondern als Annotation run.tanzu.vmware.com/resolve-os-image an zwei Stellen. Zuerst für die Control-Plane und dann für den Worker-Pool. Mehr dazu in der offiziellen Dokumentation.
Namespace – Erstellung
Dieser Beitrag ist für die VKS-Nutzer vorgesehen, die bereits einen eigenen Namespace vom zuständigen Team, welches VKS-Infrastruktur verwaltet, zugewiesen bekommen. Dabei gehe ich von der folgenden Annahme aus: Wenn Sie VKS in Ihrem Unternehmen verwenden, haben Sie keine unbegrenzte Anzahl von Resources, deswegen findet die Erstellung von Namespace nicht automatisiert, sondern in vorheriger Absprache statt.

Bei der Erstellung von Namespace wird nämlich Folgendes definiert:
Permissions: Wer und mit welchen Rechten (Rolle wie Can view / Can edit / Owner) auf den Namespace über den Cluster-API-Endpunkt zugreifen darf.
Storage: Hier werden Storage-Policies hinzugefügt, die im Namespace zu nutzbaren StorageClasses übersetzt werden. storageClass-Wert im YAML.
Capacity and Usage: Es besteht auch die Möglichkeit die zur Verfügung stehenden Hardware-Ressourcen, wie CPU-, Arbeitsspeicher- und/oder Disk-Speicher zu begrenzen.
VM Service: Hier wird ausgewählt, welche VMs gemäß den T-Shirt-Größen bei der Clustererstellung verwendet werden können. vmClass-Wert im YAML. Ebenfalls hier wird die Content Library hinzugefügt. Die OS- und VKr-Images stammen aus einer Content Library.
Login am Supervisor
Um den Guest Cluster im zugewiesenen Namespace zu erstellen, muss man sich entsprechend anmelden, da er nur aus dem Namespace-Kontext des Supervisors heraus erstellt werden kann.
kubectl vsphere login \
--server=<IP-oder-FQDN-Supervisor> \
--insecure-skip-tls-verify \
--vsphere-username=<benutzername> \
--tanzu-kubernetes-cluster-namespace=<Namespace-Name>
kubectl config current-context # Dient zur Kontrolle, zeigt "namespace-name"
–insecure-skip-tls-verify – Dieser Parameter deaktiviert die Zertifikatsprüfung. Nur verwenden, wenn das Supervisor-Zertifikat auf dem Client nicht vertrauenswürdig ist.
Durch die Verwendung des Parameters tanzu-kubernetes-cluster-namespace wird die Ausführung des Befehls kubectl config use-context namespace-name überflüssig.
YAML-Datei für den Guest Cluster
Diese YAML-Datei dient ausschließlich Lernzwecken und kann nicht für das Cluster-Deployment verwendet werden. In dieser Datei steht jedes · für genau ein Leerzeichen. Die Punkte dürfen nicht in die echte YAML-Datei übernommen werden. Die gültige YAML-Datei befindet sich unter dieser Erklärung.
# apiVersion legt die verwendete Kubernetes-API für das Cluster-Objekt fest. apiVersion: cluster.x-k8s.io/v1beta2 # Es wird ein Cluster-API-Clusterobjekt angelegt. kind: Cluster # Metadaten des neuen Guest Clusters. metadata: ··# Frei wählbarer Name des Guest Clusters. ··name: akr-test01 ··# Supervisor-Namespace, in dem der Guest Cluster erstellt wird. ··namespace: akr-001 # Gewünschte Konfiguration des Clusters. spec: ··# Netzwerkbereiche des Kubernetes-Clusters. ··clusterNetwork: ····# CIDR für Kubernetes Services (ClusterIP-Adressen). ····services: ······cidrBlocks: ········- 10.96.0.0/12 ····# CIDR für die Pod-Adressen im Guest Cluster. ····pods: ······cidrBlocks: ········- 192.168.0.0/16 ····# Interne Kubernetes-DNS-Domain. ····serviceDomain: cluster.local ··# Topologie und VKS-spezifische Cluster-Konfiguration. ··topology: ····# Verwendete VKS ClusterClass. ····classRef: ······# Name der ClusterClass. ······name: builtin-generic-v3.7.0 ······# Namespace, in dem VMware die öffentliche ClusterClass bereitstellt. ······namespace: vmware-system-vks-public ····# Gewünschter KubernetesRelease. ····# Vorher mit "kubectl get kubernetesreleases" prüfen. ····# Der Release sollte READY=True und COMPATIBLE=True sein. ····version: v1.35.6---vmware.2-vkr.3 ····# Anzahl der Control-Plane-Nodes. ····# Für einen Testcluster genügt ein Node; produktiv wird typischerweise HA geplant. ····controlPlane: ······replicas: 1 ····# Definition der Worker-Nodes. ····workers: ······machineDeployments: ········# VKS-Worker-Klasse innerhalb der ClusterClass. ········- class: node-pool ··········# Name des Worker-Pools. ··········name: worker-pool-01 ··········# Anzahl der Worker-Nodes. ··········replicas: 1 ····# Parameter, die an die ClusterClass übergeben werden. ····variables: ······# VM Class bestimmt die virtuelle Hardwaregröße der Nodes. ······- name: vmClass ········value: best-effort-medium ······# StorageClass für die Root-Volumes der Kubernetes-Nodes. ······# Die virtuellen Systemplatten der Control-Plane- ······# und Worker-VMs werden also darüber angelegt. ······- name: storageClass ········value: vsan-default-storage-policy ······# Zusätzliche vSphere-spezifische Optionen. ······- name: vsphereOptions ········value: ··········# Konfiguration für Persistent Volumes. ··········persistentVolumes: ············# Default StorageClass INNERHALB des Guest Clusters. ············# Sie wird verwendet, wenn ein PersistentVolumeClaims (PVC) ············# keine eigene storageClassName angibt. ············defaultStorageClass: vsan-default-storage-policy
Die Werte 10.96.0.0/12 und 192.168.0.0/16 sind nur Beispiele, wobei 10.96.0.0/12 standardmäßige internal IP Address Range (CIDR) ist. Die Service- und Pod-Netze dürfen untereinander sowie mit relevanten Infrastruktur-/Routing-Netzen nicht kollidieren.
Unter diesem LINK lässt sich eine gültige YAML-Datei mit identischer Konfiguration wie oben herunterladen. Passen Sie die Datei entsprechend an. Es lohnt sich, die Datei serverseitig zu validieren, bevor Sie den Cluster erstellen.
kubectl apply --dry-run=server -f guest-cluster-vorlage.yaml
Danach:
kubectl apply -f guest-cluster-vorlage.yaml
Nach wenigen Minuten sollte der Cluster vollständig provisioniert sein. Dies lässt sich mit der folgenden Befehlskette verifizieren:
kubectl get cluster,machines,machinedeployments,virtualmachines
Erwartbare Ergebnisse:
NAME CLUSTERCLASS AVAILABLE CP DESIRED CP AVAILABLE CP UP-TO-DATE W DESIRED W AVAILABLE W UP-TO-DATE PHASE AGE VERSION cluster.cluster.x-k8s.io/akr-test01 builtin-generic-v3.7.0 True 1 1 1 1 1 1 Provisioned 3d19h v1.35.6+vmware.2 NAME CLUSTER NODE NAME FAILURE DOMAIN READY AVAILABLE UP-TO-DATE PHASE AGE VERSION machine.cluster.x-k8s.io/akr-test01-cnbpf-wcqjr akr-test01 akr-test01-cnbpf-wcqjr domain-c11 True True True Running 3d19h v1.35.6+vmware.2 machine.cluster.x-k8s.io/akr-test01-worker-pool-01-smcpz-k6n9h-prnj6 akr-test01 akr-test01-worker-pool-01-smcpz-k6n9h-prnj6 domain-c11 True True True Running 3d19h v1.35.6+vmware.2 NAME CLUSTER AVAILABLE DESIRED CURRENT READY UP-TO-DATE PHASE AGE VERSION machinedeployment.cluster.x-k8s.io/akr-test01-worker-pool-01-smcpz akr-test01 True 1 1 1 1 Running 3d19h v1.35.6+vmware.2 NAME POWER-STATE AGE virtualmachine.vmoperator.vmware.com/akr-test01-cnbpf-wcqjr PoweredOn 3d19h virtualmachine.vmoperator.vmware.com/akr-test01-worker-pool-01-smcpz-k6n9h-prnj6 PoweredOn 3d19h
Login in den neuen Guest Cluster

Die folgende Befehlskette sorgt für eine direkte Anmeldung auf der Ebene des Guest Clusters.
kubectl vsphere login \ --server=<IP-oder-FQDN-Supervisor> \ --insecure-skip-tls-verify \ --vsphere-username=<Benutzername> \ --tanzu-kubernetes-cluster-namespace=<Namespace-Name> --tanzu-kubernetes-cluster-name=<Guest-Cluster-Name>
.