Crossplane Tutorial
Im DevOps Kontext haben sich über die Zeit verschiedene Werkzeuge entwickelt:
Waren Puppet und Chef noch frühe Vertreter mit unterschiedlichen Paradigmen (deklarativ vs. imperativ) verwendeten doch beide einen Agent.
Ansible setzte sich weitgehend als imperative Lösung ohne Agent für die Provisionierung von Systemen durch, während Terraform als Infrastruktur- und Cloudwerkzeug de-factor Standard wurde.
Sowohl Ansible als auch Puppet setzen auf eine Konfiguration, die nahe an typischen Datenformaten von APIs sind (YAML bzw. JSON).
In diesem Beitrag soll es um ein neuartiges Werkzeug gehen, dass den deklarativen Ansatz verfolgt, jedoch die Kubernetes API als Schnittstelle verwendet. Crossplane geht damit einen spannenden Weg und erlaubt es, bestehende Verfahren zur Authentifizierung und Autorisierung weiter zu nutzen und sich dank zahlreicher Kubernetes Libraries auch einfach an eigene oder bestehende Anwendungen zu integrieren. Dies ermöglicht eine konsistente Verwaltung von (Cloud-)Ressourcen und Kubernetes-Workloads. Crossplane bietet somit eine engere Integration zwischen Anwendungen und Infrastruktur, was die Automatisierung und das Management vereinfacht.
Dies wird dank der erweiterbaren API von Kubernetes möglch: Alle Crossplane Ressourcen sind Custom Resource Definitions (CRDs) in Kubernetes. Die Erweiterung von Crossplane ist durch die erweiterbare API von Kubernetes ebenfalls gegeben, so können sogenannte Provider nachgerüstet werden. Dazu können vorhandene Kubernetes Konzepte wie ConfigMaps oder Secrets verwendet werden.
Aus diesem Ansatz ergeben sich folgende Vorteile von Crossplane:
-
Infrastrukturverwaltung kann durch
kubectl
erfolgen -
Auf der Kubernetes API aufsetzende Werkzeuge, wie ArgoCD oder Flux, können nahtlos eingesetzt werden
-
Durch die grundsätzlich Abstraktion wird die Unterstützung unterschiedlichster Zielinfrastruktur vereinfacht
-
Eigene Anbindungen - sogenannte Provider - können auf einfache Weise entwickelt werden
-
Durch die Verwendung von Kubernetes Standards kann Crossplane auf beliebigen Kubernetes basierten Clustern betrieben werden
-
Durch den deklarativen Ansatz kann Crossplane die von Kubernetes bekannten Self-Healing-Eigenschaften bieten
Crossplane benötigt jedoch einen Kubernetes API Server als Basisinfrastruktur. Im folgenden schauen wir uns die Installation und Verwendung von Crossplane genauer an.
Für einen einfachen und schnellen Start bietet sich ein lokales Kubernetes an. Das kann ein Docker Desktop, kind (Kubernetes-in-Docker) oder auch Minikube sein. Minikube hat dabei den Vorteil, dass es verschiedene Isolationsmechanismen unterstützt. Speziell unter Linux sind kind und Minikube mit dem Docker Driver besonders leichtgewichtig aufzusetzen.
Crossplane auf Minikube
Um Crossplane auf Minikube zu testen, sind einige Werkzeuge erforderlich:
-
Das
kubectl
Werkzeug zur Steuerung von Kubernetes -
Minikube um den Kubernetes Cluster aufzusetzen
-
Helm als Paketmanager zur Installation von Crossplane
-
Optional das Crossplane CLI mit dem Crossplane komfortabel gesteuert werden kann
Das Setup eines Minikube Kubernetes Clusters für Crossplane ist im Prinzip ein ganz gewöhnlicher Cluster, hier reicht auch eine einzelne Node.
$ minikube start --driver docker --memory 8192 --cpus 4
Zur Sicherheit sollte verifiziert werden, dass auf dem richtigen Cluster gearbeitet wird. Dies ist eine Routineabfrage, die sich vor dem Start von Arbeiten mit Kubernetes bewährt hat, um zu vermeiden, dass irrtümlich auf dem falschen Cluster gearbeitet wird.
$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* minikube minikube minikube default
Wenn der Cluster bereit steht, kann die Installation von Crossplane im Minikube Cluster vorgenommen werden.
Zur Installation wird Helm verwendet, das Crossplane Helm Repository ist unter https://charts.crossplane.io/stable zu finden.
Crossplane sollte standardmäßig im Namespace crossplane-system
installiert werden, entsprechend ist der Helm Aufruf mit diesem Namespace konfiguriert.
$ helm repo add crossplane-stable https://charts.crossplane.io/stable
$ helm repo update
$ helm install crossplane \
--create-namespace --namespace crossplane-system \
crossplane-stable/crossplane
Die Installation von Crossplane selbst ist eine Anwendung, die ganz normal in Kubernetes läuft.
Entsprechend können die Helm und kubectl
-Mittel verwendet werden, um den Status der Installation abzufragen.
Gerade bei der ersten Installation von Crossplane lohnt ein Blick darauf, dass die Crossplane Pods korrekt starten.
$ helm list -n crossplane-system
$ kubectl get all -n crossplane-system
$ kubectl -n crossplane-system get pods --watch
Das optionale Crossplane CLI liegt als Binary für verschiedene Plattformen vor.
Zur komfortablen Installation wird durch Crossplane ein Shellscript ausgeliefert, das die Plattform ermittelt und den richtigen Download startet.
Angenehm daran ist, dass keine administrativen Rechte vorausgesetzt werden, sondern der Download von der globalen Einrichtung im $PATH
getrennt sind.
Wer ein zusätzliches Verzeichnis im $PATH
zur lokalen Installation von Software aufgenommen hat, kommt gänzlich ohne administrative Rechte bei der Installation des Crossplane CLI aus.
Alternativ kann das Crossplane CLI unter /usr/local/bin
global installiert werden.
$ curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
$ mv kubectl-crossplane ~/bin
$ kubectl crossplane --help
Die Installation von Crossplane ist damit soweit abgeschlossen und Crossplane ist im Prinzip einsatzbereit.
Zur Unterstützung spezifischer Infrastruktur werden noch sogenannte Crossplane Provider benötigt.
Eine Liste verschiedener Provider ist im Crossplane Marketspace unter https://marketplace.upbound.io/providers/ zu finden.
Um die Funktionsweise von Crossplane genauer kennenzulernen, ohne jedoch eine zusätzliche Abhängigkeit auf eine Cloud wie Amazon AWS, Azure oder Google zu haben, bietet sich an mit dem ohnehin für Crossplane erforderlichen Kubernetes Cluster zu arbeiten.
Crossplane Kubernetes Provider
Crossplane kann mit dem Crossplane Kubernetes Provider Objekte in Kubernetes verwalten. Nun kann argumentiert werden, dass dazu bereits Werkzeuge, wie ArgoCD, existieren. Das ist natürlich auch korrekt, doch geht es hier zunächst darum, die Funktionsweise von Crossplane und Providern vorzustellen. Zum anderen kann es durchaus sinnvoll sein, Crossplane als einheitliche Basis zur Verwaltung unterschiedlicher Arten von Infrastruktur zu nutzen, und dazu können dann auch Kubernetes Objekte gehören.
Der Crossplane Kubernetes Provider ist im Marketplace unter https://marketplace.upbound.io/providers/crossplane-contrib/provider-kubernetes/ zu finden.
Das zugehörige GitHub Repository findet sich unter https://github.com/crossplane-contrib/provider-kubernetes/tree/main .
Zur Installation des Providers gibt es drei Optionen, die alle darauf hinauslaufen, dass ein entsprechendes Provider Objekt, eine Crossplane Custom Resource in Kubernetes, angelegt wird:
-
Direkte Verwendung der Crossplane Provider CRD Objekte in Kubernetes
-
Konfiguration über Helm direkt bei der Installation von Crossplane oder als nachträgliches Upgrade
-
Verwendung des Crossplane CLI
Crossplane reagiert auf diese Objekte mit der Installation des jeweiligen Providers, ebenfalls in Kubernetes.
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-kubernetes
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-kubernetes:v0.9.0
Das Crossplane Helm Chart unterstützt sowohl bei der initialen Installation von Crossplane, als auch als nachträgliches Upgrade den Wert provider.packages
, um darüber zu installierende Provider zu konfigurieren.
Als Werte werden darin die Paketnamen und Versionen zu installierender Provider angegeben.
$ helm upgrade crossplane --reuse-values \
--namespace crossplane-system \
--set provider.packages='{xpkg.upbound.io/crossplane-contrib/provider-kubernetes:v0.9.0}' \
crossplane-stable/crossplane
Das Crossplane CLI bietet dazu ebenfalls ein Kommando: xpkg install provider
.
Im Vergleich zu Helm ist hier weniger zu tippen und es ist davon auszugehen, dass das Crossplane CLI zukünftig noch im weitere Funktionalität erweitert wird.
$ crossplane xpkg install provider xpkg.upbound.io/crossplane-contrib/provider-kubernetes:v0.9.0
provider/crossplane-contrib-provider-kubernetes created
Unerheblich, für welche Installationsvariante man sich entscheidet, im Ergebnis legen alle drei ein entsprechendes Provider Objekt an.
Wie alle anderen Kubernetes Objekte wird nicht nur der Zielzustand, sondern auch der aktuelle Zustand über die Kubernetes API bereitgestellt.
Damit lässt sich der Stand der Installation des Providers verfolgen.
In der Übersicht von kubectl get providers
ist der Installationszustand und Health-Status des Crossplane Providers aufgeführt.
Mehr Details erhält man wie üblich durch kubectl describe
.
$ kubectl get providers
NAME INSTALLED HEALTHY
crossplane-contrib-provider-kubernetes True True
PACKAGE AGE
xpkg.upbound.io/crossplane-contrib/provider-kubernetes:v0.9.0 31s
Damit ist der Crossplane Provider installiert und prinzipiell einsatzbereit.
Zur Verwaltung von Objekten in einem Kubernetes Cluster benötigt der Provider jedoch noch Zugriff auf den Kubernetes Zielcluster.
Dies könnte ein anderer Cluster sein, oder aber auch der Cluster, in dem der Crossplane Provider installiert wurde.
Der Einfachheit halber soll hier der selbe Cluster verwendet werden, in dem auch Crossplane installiert ist.
Die entsprechenden Rechte zur Cluster Administration, die der Provider benötigt, werden dem ServiceAccount zugeordnet, mit dem Crossplane Kubernetes Provider betrieben wird.
Da der Name des ServiceAccount generiert ist, wird dieser dynamisch mit den Unix Tools grep
und sed
hergeleitet.
Anschließend wird für den ServiceAccount ein ClusterRoleBinding auf die Rolle cluster-admin
hergestellt.
Diese Rolle hat alle Rechte im Kubernetes Cluster.
Ob dies für den produktiven Betrieb unter Sicherheitsgesichtspunkten das beste Vorgehen ist, sollte im Einzelfall betrachtet und diskutiert werden.
Das Thema Clustersicherheit wird leider oft erst dann ernst genommen, wenn es bereits zu problematischen Situationen gekommen ist.
$ SA=$(kubectl -n crossplane-system get sa -o name | grep provider-kubernetes | sed -e 's|serviceaccount\/|crossplane-system:|g')
$ kubectl create clusterrolebinding provider-kubernetes-admin-binding --clusterrole cluster-admin --serviceaccount="${SA}"
Der Provider selbst muss nun noch wissen, wie er auf den Kubernetes Cluster zugreift. Dies wird durch eine ProviderConfig konfiguriert. Eine ProviderConfig wird entsprechend auch für den Zugriff anderer Provider auf externe APIs verwendet. Der Inhalt richtet sich dabei dann nach dem spezifischen Provider.
Im folgenden Beispiel wird durch source: InjectedIdentity
konfiguriert, dass der eigene Cluster mit der eigenen ServiceAccount Identität verwendet werden soll.
apiVersion: kubernetes.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
name: kubernetes-provider
spec:
credentials:
source: InjectedIdentity
Damit ist nun Crossplane mitsam einem ersten Provider installiert und konfiguriert. Die Verwendung des Providers wird im folgenden aufgezeigt.
Crossplane Verwaltung von Kubernetes Objekten
Als Beispiel für ein Kubernetes Objekt wird eine ConfigMap verwendet.
Die API wird durch den Crossplane Kubernetes Provider im Namespace kubernetes.crossplane.io
bereitgestellt.
Ein Kubernetes Objekt ist dann vom Typ kind: Object
.
In der Spezifikation werden dann durch die Felder forProvider
das Kubernetes Objekt und durch providerConfigRef
die zu verwendende Clusterkonfiguration spezifiziert.
apiVersion: kubernetes.crossplane.io/v1alpha1
kind: Object
metadata:
name: xp-managed-sample
spec:
forProvider:
manifest:
apiVersion: v1
kind: ConfigMap
metadata:
# name: in manifest is optional and defaults to Object name
namespace: default
labels:
crossplane: "true"
data:
sample-key: sample-value
providerConfigRef:
name: kubernetes-provider
Nachdem das Objekt für Crossplane konfiguriert wurde, kann die erzeugte ConfigMap abgefragt werden.
$ kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 25h
xp-managed-sample 1 2s
Änderungen des Objektes werden durch den Provider automatisch ausgebracht.
Wird die ConfigMap manuell gelöscht oder editiert, so stellt der Crossplane Kubernetes Provider den konfigurierten Zielzustand nach kurzer Zeit wieder her.
Änderungen an der Objektdefinition wirken sich dabei unmittelbar aus.
Um die ConfigMap zu löschen muss die Objektdefinition des Providers gelöscht werden.
Auch hier erfolgt unmittelbar eine Anpassung im Kubernetes Cluster durch den Provider.
Das genaue Verhalten von Providern kann weiter beeinflusst werden, ob bspw. lediglich Aktualisierungen durch den Provider verwaltet werden sollen, jedoch ein Administrator die Verantwortung für die Erzeugung und/oder Löschen der Objekte inne hat.
Helm
Um die Flexibilität von Crossplane konkreter aufzuzeigen wird noch ein zweiter Provider verwendet: Der Helm Provider erlaubt es, Helm Charts zu verwalten. Dabei läuft die Installation und Konfiguration recht ähnlich ab, erst bei der konkreten Konfiguration von zu verwaltenden Objekten zeigen sich deutlichere Unterschiede.
$ crossplane xpkg install provider xpkg.upbound.io/crossplane-contrib/provider-helm:v0.16.0
provider/crossplane-contrib-provider-helm created
Auch der Helm Provider benötigt einen Kubernetes Cluster, auf dem Helm angewandt werden soll. Die Konfiguration ist analog zum Crossplane Provider Kubernetes.
$ SA=$(kubectl -n crossplane-system get sa -o name | grep provider-helm | sed -e 's|serviceaccount\/|crossplane-system:|g')
$ kubectl create clusterrolebinding provider-helm-admin-binding --clusterrole cluster-admin --serviceaccount="${SA}"
Eine entsprechende ProviderConfig für den Crossplane Helm Provider wird ebenfalls benötigt.
apiVersion: helm.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
name: helm-provider
spec:
credentials:
source: InjectedIdentity
Die Konfiguration eines Helm Releases wird durch die API helm.crossplane.io
und kind: Release
ausgedrückt.
In dem Objekt werden dann die Parameter für den Helm Aufruf selbst, beispielsweise der zu nutzende Namespace, der zu nutzende Chart mit Namen, Repository und Version angegeben.
Zusätzlich befindet sich auch die Konfiguration des Charts in dem Objekt:
Die Helm-typischen Konfigurationsausprägungen als Values, die der jeweilige Chart anbietet.
Für den Clusterzugriff wird noch die zu verwendende ProviderConfig referenziert.
Zur Demonstration wird das von Bitnami als Helm Chart bereitgestellte Wordpress verwendet. Weitere Informationen dazu finden sich hier: https://bitnami.com/stack/wordpress/helm und auf GitHub: https://github.com/bitnami/charts/tree/main/bitnami/wordpress/#installing-the-chart
apiVersion: helm.crossplane.io/v1beta1
kind: Release
metadata:
name: wordpress-example
spec:
forProvider:
chart:
name: wordpress
repository: https://charts.bitnami.com/bitnami
version: 19.0.1
namespace: wordpress
skipCreateNamespace: false
# Konfiguration im Format von values.yaml
values:
service:
type: ClusterIP
# Konfiguration als key-value Parameter
set:
- name: param1
value: value2
providerConfigRef:
name: helm-provider
Nachdem das entsprechende Objekt erzeugt wurde wir der Crossplane Helm Provider aktiv und installiert das Chart.
$ kubectl get releases
NAME CHART VERSION SYNCED READY STATE REVISION DESCRIPTION AGE
wordpress-example wordpress 19.0.1 False 67s
...
NAME CHART VERSION SYNCED READY STATE REVISION DESCRIPTION AGE
wordpress-example wordpress 19.0.1 True True deployed 1 Install complete 9m3s
Entsprechend wird der Namespace wordpress
angelegt und in dem Namespace die zugehörigen Objekte des Wordpress Helm Charts erzeugt.
Fazit
Mit Crossplane lässt sich die flexible Kubernetes API nutzen, um darauf aufbauend DevOps Prozesse und Automatisierungen umzusetzen.
Als Administrator profitiert man von der Einheitlichkeit der Werkzeuge und Konfigurationssyntax, wenn Kubernetes bereits im Einsatz ist.
Als Entwickler von Plattformlösungen bekommt man eine einheitliche Abstraktion samt API geliefert, die es ermöglicht darauf aufbauend mit entsprechend geringem Entwicklungsauwand eigene Lösungen zu schaffen.
Im Verlgeich zu Terraform oder Ansible kann Kubernetes mit dem bestehenden Berechtigungssystem zur Abstraktion und Trennung der Verantwortlichkeiten genutzt werden. Auf diese Weise ergibt sich eine attraktive Alternative zu Produkten wie Ansible Tower oder der Terraform Cloud.
Zu den Themen Kubernetes, Docker und Cloudarchitektur bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.