CI/CD mit Tekton
Tekton ist ein Open-Source-Framework zur Erstellung von CI/CD-Systemen. Mit Hilfe von Tekton können Entwickler:innen ihre Anwendungen kontinuierlich bauen, testen und deployen. Tekton kann als CI/CD-System in Kubernetes-Umgebungen zum Einsatz kommen. Auch in OpenShift kommt Tekton in Form des OpenShift Pipeline Operators zum Einsatz.
Tekton-Ressourcen
Tekton stellt verschiedene Ressourcen, wie bspw. Pipelines, Tasks, Trigger und EventListener zur Verfügung. Das Zusammenspiel dieser Ressourcen und ihre Konfiguration erfolgt über Custom Resource Definitions (CRD) für Kubernetes in Form von YAML-Dateien.
Eine minimale Tekton-Pipeline besteht i.d.R. aus einer Task-Ressource und einer Pipeline-Ressource, in der dieser Task zum Einsatz kommt. Ein einfacher Task kann dabei bspw. folgendermaßen aufgebaut sein:
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: say-hello
spec:
params:
- name: username
type: string
steps:
- name: echo
image: ubuntu
script: |
#!/bin/bash
echo "Hello $(params.username)!"
Eine einfache Pipeline, die diesen Task ausführt, kann folgendermaßen aussehen:
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: greeting
spec:
params:
- name: username
type: string
tasks:
- name: say-hello
taskRef:
name: say-hello
params:
- name: username
value: $(params.username)
Ein ausführlicher Einstieg in Tekton, seine Ressourcen und die damit verbundenen Konzepte findet man in der offiziellen Dokumentation.
Wiederverwendbarkeit von Ressourcen
Bestimmte Tekton-Ressourcen, wie bspw. Tasks sind darauf ausgelegt, dass man sie leicht wiederverwenden kann, bspw. in mehreren Pipeline-Ressourcen. Dennoch entsteht in größeren Projekten schnell eine große Anzahl von YAML-Dateien, die die Konfiguration der verschiedenen Ressourcen enthalten. Wenn zusätzlich zu Tasks und Pipelines auch Trigger und EventListener zum Einsatz kommen, verstärkt sich dieses Problem. Für jedes neue Projekt bzw. jede neue Anwendung, die in das CI/CD-System auf Basis von Tekton aufgenommen werden soll, müssen dann eine Vielzahl neuer YAML-Dateien erstellt und angepasst werden. Diese Aufgabe kann man per Copy-Paste-Modify, mit Hilfe von Merge-Strategien auf Basis von kustomize oder über einen einfachen Templating-Mechanismus realisieren.
YAML-Templating mit ytt
Meiner Erfahrung nach ähneln sich die verwendeten YAML-Dateien für bestimmte Tekton-Ressourcen innerhalb eines Teams oder Projektes inhaltlich schnell sehr stark. So bestehen Pipelines für gleichartige Anwendungen i.d.R. aus einer ähnlichen Abfolge von Tasks. Daher eignen sich diese Ressourcen sehr gut, um sie auf Basis eines Templates zu generieren. ytt ist ein einfaches Command-Line-Tool zur Generierung von YAML-Dateien auf Basis von Templates. Es unterstützt dabei u.a. die Verwendung von Platzhaltern. Die Installation von ytt ist in der Dokumentation beschrieben.
Templates für Tekton-Ressourcen
Der Einsatz von ytt in Verbindung mit Tekton soll exemplarisch anhand einer Pipeline-Ressource gezeigt werden. Die folgende Pipeline-Ressource enthält den Task git-clone
.
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: pipeline-project-a
spec:
params:
- name: branch
type: string
tasks:
- name: git-clone
params:
- name: url
value: ssh://git@scm.acme.com/project-a.git
- name: branch
value: $(params.branch)
taskRef:
kind: Task
name: git-clone
Es ist leicht vorstellbar, dass jede Pipeline-Ressource für jede Anwendung, die in einem Git-Repository verwaltet wird, einen solchen Task hat. Der einzige Unterschied zwischen den Pipeline-Ressourcen unterschiedlicher Anwendungen ist der konkrete Pfad zum Git-Repository. Die konkrete Pipeline-Ressource kann leicht in ein Template umgewandelt werden. Dazu werden die variablen Stellen mit ytt-spezifischen Platzhalter-Kommentaren versehen und am Anfang der Datei wird eine Import-Anweisung ergänzt, die dazu führt, dass ytt die Platzhalter mit Hilfe sog. data values
aus dem @ytt:data
-Modul ersetzt. Eine Template-Datei pipeline-template.yaml
hätte somit folgenden Inhalt:
#@ load("@ytt:data", "data")
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: #@ "pipeline-" + data.values.project.name
spec:
params:
- name: branch
type: string
tasks:
- name: git-clone
params:
- name: url
value: #@ "ssh://git@scm.acme.com/" + data.values.project.name + ".git"
- name: branch
value: $(params.branch)
taskRef:
kind: Task
name: git-clone
Die verfügbaren data values
werden anhand eines Schemas definiert. Die Schema-Datei schema.yaml
für das vorliegende Beispiel hat folgenden Inhalt:
#@data/values-schema
---
project:
name: "project-name"
Der Platzhalter data.values.project.name
hat als Default-Wert project-name
.
Tekton-Ressourcen generieren
Mit Hilfe des Templates und des Schemas können nun neue YAML-Dateien generiert werden. Die konkreten Werte für die Platzhalter können in einer eigenen Datei, wie bspw. values.yaml
definiert werden:
---
project:
name: "project-xyz"
Der Aufruf von ytt erfolgt anschließend über die Kommandozeile:
ytt --file schema.yaml --file pipeline-template.yaml --data-values-file values.yaml --output-files ./generated --file-mark "pipeline-template.yaml:path=pipeline/pipeline-xyz.yaml"
Das Ergebnis dieses Aufrufs ist eine konkrete Pipeline-Ressource für project-xyz
im Verzeichnis ./generated/pipeline
mit dem Dateinamen pipeline-xyz.yaml
.
Zusammenspiel mit kustomize
Wenn kustomize in Verbindung mit Kubernetes zum Einsatz kommt, müssen die erzeugen Dateien in entsprechende kustomization.yaml
Dateien eingetragen werden. Dies kann mit Hilfe von yq automatisiert werden. yq
ist ebenfalls ein Command-Line-Tool und kann verwendet werden, um YAML-Dateien zu manipulieren. Eine neu erzeugte Datei pipeline-xyz.yaml
kann mit folgendem Aufruf in die resources
-Liste einer kustomization.yaml
aufgenommen werden.
yq --inplace '.resources += "pipeline-xyz.yaml"' ./kustomization.yaml
Sowohl ytt
als auch yq
können sehr einfach ein einem Bash-Skript kombiniert werden, so dass unkompliziert Skripte erstellt werden können, die diese Art von wiederkehrende Aufgaben automatisieren können und dabei helfen Fehler zu vermeiden, wie sie bspw. beim Copy-Paste-Modify-Ansatz schnell auftreten können.
Fazit
Mit Hilfe von Tekton können CI/CD-Systeme in Kubernetes- bzw. OpenShift-Umgebungen erstellt werden. Die verfügbaren CRDs ermöglichen u.a. die Implementierung flexibler Pipelines. Die Konfiguration über YAML-Dateien ist im Kubernetes-Umfeld bekannt, führt aber bei vielen Anwendungen und vielen Pipelines schnell zu einer Vielzahl an Dateien. Der initiale manuelle Aufwand, um bspw. eine Pipeline für eine neue Anwendung zu erstellen, kann über den gezeigten Templating-Mechanismus mit yyt verringert werden. Kommen weitere Tekton-Komponenten, wie Trigger oder EventListener zum Einsatz steigt die Anzahl der YAML-Dateien und der Einsatz von Templates lohnt sich um so mehr.