Heute beschäftigen wir uns mal mit der Härtesten Kategorie in Kubernetes, der Cluster-Erstellung. Da gibt es von der Community schon den Standard kubeadm, aber für die Verwaltung mehrerer Cluster auch den neuen Dienst Cluster API
Cluster API erstell und verwaltet Kubernetes Cluster. Dazu brauchts es selber erstmal einen Cluster, der die Informationen der Downstream Cluster vorhält und die daraus notwendigen Arbeiten in einem Operator durchführt. Die Downstream Cluster können mittels Provider in verschiedenen Umgebungen installiert werden, etwa mit clusterctl init --infrastructure gcp
in der Google Cloud Plattform. Eine vollständige Liste gibt es hier.
Wenn man keine Public Cloud oder VMware benutzt, erscheint mir der K3S Provider am Vielversprechensten. Als klassischer Quickstart wird kind
empfohlen (Kubernetes in Docker), wir wollen uns mit Vcluster Quickstart versuchen.
Wir brauchen einen Rechner mit Ubuntu 22.04 und einige Kommandozeilenwerkzeuge:
apt update
apt install docker-ce
curl -Lo /usr/local/bin/kind https://github.com/kubernetes-sigs/kind/releases/download/v0.23.0/kind-linux-amd64
chmod +x /usr/local/bin/kind
curl -Lo /usr/local/bin/vcluster https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64
chmod +x /usr/local/bin/vcluster
curl -Lo /usr/local/bin/clusterctl https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.7.2/clusterctl-linux-amd64
chmod +x /usr/local/bin/clusterctl
curl -Lo /usr/local/bin/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x /usr/local/bin/kubectl
Zuerst erstellen wir den Upstream-Cluster, oder auch Bootstrap-Cluster/Management-Cluster genannt. Dieser soll als Docker-Container mit kind
erstellt werden:
kind create cluster
Als nächstes initialisieren wir den Management-Cluster mit dem Vcluster Provider:
clusterctl init --infrastructure vcluster
Wenn es dabei keine Fehlermeldung gab, können wir überprüfen, ob der Cluster API Operator mit allen Komponenten läuft:
# kubectl get pod -A| grep capi
capi-kubeadm-bootstrap-system capi-kubeadm-bootstrap-controller-manager-85cd65d6c5-fwjjn 1/1 Running 0 2m39s
capi-kubeadm-control-plane-system capi-kubeadm-control-plane-controller-manager-f8d8578c8-9cqck 1/1 Running 0 2m38s
capi-system capi-controller-manager-7f49f575d4-xxcp9 1/1 Running 0 2m39s
Alsdann können wir den ersten Downstream-Cluster erstellen:
export CLUSTER_NAME=kind
export CLUSTER_NAMESPACE=vcluster
export KUBERNETES_VERSION=1.23.4
export HELM_VALUES="service:\n type: NodePort"
kubectl create namespace ${CLUSTER_NAMESPACE}
clusterctl generate cluster ${CLUSTER_NAME} \
--infrastructure vcluster \
--kubernetes-version ${KUBERNETES_VERSION} \
--target-namespace ${CLUSTER_NAMESPACE} | kubectl apply -f -
Kontrolle:
# vcluster list
NAME | CLUSTER | NAMESPACE | STATUS | VERSION | CONNECTED | CREATED | AGE | DISTRO
-------+-----------+-----------+---------+---------+-----------+-------------------------------+-----+---------
kind | kind-kind | vcluster | Running | 0.11.1 | | 2024-06-09 20:31:21 +0000 UTC | 19s | OSS
Das clusterctl generate
generiert tatsächlich nur die Manifeste, die dann mit kubectl apply -f
zum Management-Cluster geschickt werden. Schauen wir mal in so ein Manifest rein.
vcluster2.yaml:
kind: Cluster
metadata:
name: kind
namespace: vcluster2
spec:
controlPlaneRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
kind: VCluster
name: kind
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
kind: VCluster
name: kind
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1
kind: VCluster
metadata:
name: kind
namespace: vcluster2
spec:
controlPlaneEndpoint:
host: ""
port: 0
helmRelease:
chart:
name: null
repo: null
version: null
values: ""
kubernetesVersion: 1.29.0
Die Sache mit dem NodePort Service haben wir in dieser Instanz mal weggelassen:
kubectl create ns vcluster2
kubectl apply -f vcluster2.yaml
Es wird also jeweils ein Cluster Objekt und ein Vcluster Objekt erstellt:
# kubectl get cluster -A
NAMESPACE NAME CLUSTERCLASS PHASE AGE VERSION
vcluster kind Provisioned 15m
vcluster2 kind Provisioning 6s
# kubectl get vcluster -A
NAMESPACE NAME AGE
vcluster kind 15m
vcluster2 kind 16s
# vcluster list
NAME | CLUSTER | NAMESPACE | STATUS | VERSION | CONNECTED | CREATED | AGE | DISTRO
-------+-----------+-----------+---------+---------+-----------+-------------------------------+--------+---------
kind | kind-kind | vcluster | Running | 0.11.1 | | 2024-06-09 20:31:21 +0000 UTC | 16m54s | OSS
kind | kind-kind | vcluster2 | Running | 0.11.1 | | 2024-06-09 20:46:32 +0000 UTC | 1m43s | OSS
Zugriff bekommt man entweder über vcluster connect
oder
clusterctl -n vcluster get kubeconfig kind
Da wird man dann freilich merken, dass der API-Endpunkt der interne Service Endpunkt im Namespace ist. Im Original Quickstart von Cluster API ist das ein NodePort, damit er von aussen erreichbar ist. Ansonsten bräuchte man einen LoadBalancer Service, was unser Minimalsetup sprengen würde.
Mit Cluster API wurde jetzt auch das Erstellen von Clustern “kubernetisiert”, ist also mittels CRD als Resourcen beschreibbar. Das ganze soll meta-mässig standardisiert sein, also egal welche Infrastruktur darunter liegt. Soweit sogut. Was im ersten Test noch fehlt:
Aber das soll auch erst der Einstieg in Cluster API sein und keine Rancher Migration. Die kommt erst später :-)