Im ersten Artikel haben wir die Tekton-Installation gemeistert, erste API-Objekte kennengelernt und dabei eine erste kleine Pipeline erstellt. Hier eine kurze grafische Zusammenfassung als Erinnerung.
Jetzt werden wir eine praktisch nutzbare Pipeline erstellen, die, wie für ein CI-System üblich, bei neuen Commits neue Images erstellt. Die Wiederverwendbarkeit von Tekton-Komponenten, sowohl Tasks als auch ganze Pipelines, ist eine Stärke, die ich gerne in diesem Artikel praktisch darstellen möchte.
Wie bauen wir?
Container Images können wir auf verschiedene Arten erstellen. Docker, die Firma, die Container in die Breite getragen hat, sah es vor, ein Dockerfile
zu schreiben, das durch einen docker build
schrittweise ein Container Image gebaut hat. Ein Dockerfile
zu schreiben ist sehr simpel, jedoch wird es schnell sehr aufwendig, wenn man einen sicheren, stabilen Build und Betrieb gewährleisten möchte.
Ich möchte nur zwei Impulse setzen, die man klären sollte:
- Sollte das CI-System wirklich einen Docker Socket an die Build-Container weitergeben?
- Sollte innerhalb des Docker Images wirklich der Root User genutzt werden?
Für diese Themen gibt es viele Lösungsmöglichkeiten. Im Folgenden werde ich den Buildpack-Ansatz beleuchten.
Cloud-Native Buildpacks sind eine einfache Lösung, um Container Images zu erstellen. Was ist also zu tun? Es reicht ein pack build my-image
, um die Anwendung im aktuellen Verzeichnis als my-image
zu bauen und in einem Image Repository abzulegen. Zugegebenermaßen ist die Lösung sehr einfach zu nutzen, gleichzeitig passiert viel im Hintergrund, um einen optimalen Image Build zu gewährleisten. Themen wie z. B. Caching und Security werden transparent gelöst.
Integration in Tekton
Wir werden eine Pipeline benötigen, die Schritt für Schritt die benötigten Tasks ablaufen lässt. Die Pipeline wird zuerst den Sourcecode aus einem Git-Repository klonen und in einem Verzeichnis ablegen. Der zweite Schritt wird den Sourcecode in diesem Verzeichnis lesen und mit Buildpack Tooling das Image erstellen und in ein Container Registry pushen.
Im ersten Artikel haben wir uns angeschaut, wie wir eine Pipeline erstellen können und Tasks verknüpfen, aber mit Dateien haben wir noch nicht gearbeitet.
Workspaces
Verzeichnisse können in Tekton mithilfe von Workspaces zwischen Tasks geteilt werden. Workspaces können auf diverse Kubernetes-Storage-Typen zurückgreifen; so kann z. B. ein PersistentVolumeClaim, eine Config-Map oder ein emptyDir verwendet werden.
Bei der Definition einer Pipeline legen wir die benötigten Workspaces fest. In unserem Fall definieren wir einen Workspace, um den Sourcecode aus dem Git-Repository für die Laufzeit der Pipeline zu speichern. An dieser Stelle sind nur der Name und die Verknüpfung zu den Tasks bekannt. Tasks können Workspaces erwarten, die dann unter einem bestimmten Namen durch die Pipeline bereitgestellt werden können.
Hier sehen wir eine kurze Pipeline, die den Sourcecode aus einem Git-Repository in einen Workspace mit dem Namen source-workspace klont.
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: git-clone-sample-pipeline
spec:
params:
- name: git-clone-url
type: string
description: HTTP URL of the git repository to clone
- name: git-revision
type: string
default: "main"
description: Git revision (branch, tag, commit-id) to clone
workspaces:
- name: source-workspace # Directory where application source is located. (REQUIRED)
tasks:
- name: fetch-repository # This task fetches a repository using the `git-clone` task you installed
taskRef:
name: git-clone
workspaces:
- name: output
workspace: source-workspace
params:
- name: url
value: $(params.git-clone-url)
- name: revision
value: $(params.git-revision)
- name: subdirectory
value: ""
- name: deleteExisting
value: "true" |
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: git-clone-sample-pipeline
spec:
params:
- name: git-clone-url
type: string
description: HTTP URL of the git repository to clone
- name: git-revision
type: string
default: "main"
description: Git revision (branch, tag, commit-id) to clone
workspaces:
- name: source-workspace # Directory where application source is located. (REQUIRED)
tasks:
- name: fetch-repository # This task fetches a repository using the `git-clone` task you installed
taskRef:
name: git-clone
workspaces:
- name: output
workspace: source-workspace
params:
- name: url
value: $(params.git-clone-url)
- name: revision
value: $(params.git-revision)
- name: subdirectory
value: ""
- name: deleteExisting
value: "true"
PipelineRun
Wie schon im ersten Artikel beschrieben, erzeugen wir einen PipelineRun
zum Start der Pipeline und zur Übergabe von Parametern und Workspaces.
Im folgenden Beispiel starten wir die oben definierte Pipeline mit den gewünschten Werten. Das Git-Repository wird auf einen festen Wert gesetzt und der source-workspace
wird mit einem vorhandenen PersistentVolumeClaim
verknüpft.
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: git-clone-sample-pipeline-
spec:
serviceAccountName: tekton-service-account
pipelineRef:
name: git-clone-sample-pipeline
workspaces:
- name: source-workspace
subPath: source
persistentVolumeClaim:
claimName: source-workspace-pvc
params:
- name: git-clone-url
value: https://github.com/marcopaga/feeding-the-ci-process-single-project.git |
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: git-clone-sample-pipeline-
spec:
serviceAccountName: tekton-service-account
pipelineRef:
name: git-clone-sample-pipeline
workspaces:
- name: source-workspace
subPath: source
persistentVolumeClaim:
claimName: source-workspace-pvc
params:
- name: git-clone-url
value: https://github.com/marcopaga/feeding-the-ci-process-single-project.git
Jetzt startet die Pipeline, klont das Repository und terminiert erfolgreich.
Credentials für Clone und Push bereitstellen
Für Open-Source-Projekte mit einem öffentlich verfügbaren Repository sind wir damit am Ziel. Bei dem internen Einsatz mit Credentials auf einem Repository müssen wir diese noch dem Git-Prozess zur Verfügung stellen.
Bei der Recherche zu diesem Aspekt habe ich verschiedene Informationen gefunden. Für mich hat diese Variante, die dort beschrieben wird, funktioniert. Im Kern wird ein Secret mit den Anmeldeinformationen erstellt und mit Annotations erweitert, die beschreiben, für welchen Einsatz und welchen Server dies zu verwenden ist. Der Key tekton.dev/git-0
gibt an, dass dies für github.com-Repositorys zu verwenden ist.
apiVersion: v1
kind: Secret
metadata:
name: github-clone-secret
annotations:
tekton.dev/git-0: https://github.com
type: kubernetes.io/basic-auth
stringData:
username: git-clone-user-name
password: git-clone-password |
apiVersion: v1
kind: Secret
metadata:
name: github-clone-secret
annotations:
tekton.dev/git-0: https://github.com
type: kubernetes.io/basic-auth
stringData:
username: git-clone-user-name
password: git-clone-password
Das alleine reicht noch nicht, denn die zu benutzenden Secrets müssen dem ServiceAccount des PipelineRuns hinzugefügt werden. Wie im folgenden Beispiel zu sehen, wird das Secret einfach mit aufgeführt.
Für den Container Image Push ist ebenfalls ein Secret notwenig. Hierbei reicht es, ein normales Docker Registry Secret anzulegen, wie hier in den Tekton Docs beschrieben. Wichtig auch hierbei ist, dies dem ServiceAccount hinzuzufügen.
Im Folgenden ist ein ServiceAccount mit den beiden definierten Secrets zu sehen.
apiVersion: v1
kind: ServiceAccount
metadata:
name: buildpacks-service-account
secrets:
- name: docker-registry-secret
- name: gitlab-clone-secret |
apiVersion: v1
kind: ServiceAccount
metadata:
name: buildpacks-service-account
secrets:
- name: docker-registry-secret
- name: gitlab-clone-secret
Vorhandene Pipeline und Tasks nutzen
Jetzt haben schon einmal eine Pipeline angelegt, mit der wir den Code klonen können. Wir können jetzt mit unserem Wissen weitermachen und schrittweise die nächsten Schritte hinzufügen.
Auf dem Tekton Hub finden wir Tasks für den Build. So weit, so gut! Die Tasks sind gut dokumentiert und eigentlich können wir diese direkt einbauen.
Man kann auch nach Pipelines suchen. Wenn wir das machen, finden wir eine komplette Pipeline, die schon fertig und getestet ist.
Die Buildpacks-Pipeline ist wunderbar dokumentiert. Wir finden Informationen zum Hintergrund, den benötigten Abhängigkeiten und der Installation.
Wie im ersten Artikel beschrieben, werden diese installiert und direkt benutzt. Der vorhandene PipelineRun
wird der Dokumentation folgend angepasst und schon ist alles fertig.
Fazit
Diese Wiederverwendbarkeit erlaubt eine Zusammenarbeit und einen Austausch von CI-Komponenten innerhalb der eigenen Organisation und sogar im Open-Source-Umfeld.
Wir konnten durch Verwendung und Konfiguration von Community-Komponenten mit sehr wenig Aufwand eine funktionierende Pipeline erstellen. Damit haben wir jetzt einen Startpunkt, um die eigenen Erweiterungen vorzunehmen und auch dabei von der Community des Tekton Hubs zu profitieren und hoffentlich sogar eigene Contributions zurückzugeben.
Im nächsten Artikel werden wir mit Tekton Triggers auf dieser Basis weitermachen und beim Push in ein Repository einen Build dieser Pipeline starten.