This blog post is also available in English
Einrichtung der Pipeline
Wenn wir eine GitLab CI/CD-Pipeline als Service oder Basis für mehrere Entwicklungsteams bereitstellen, befindet sich der Pipeline-Code oft in einem separaten Repository. Die Entwicklungsteams binden dann die Pipeline in ihrer .gitlab-ci.yml ein und nutzen diese. Das Beispiel geht davon aus, dass die Pipeline im Ganzen verwendet wird, aber die Teststrategie kann auch verwendet werden, um einzelne Jobs eher im Stil von Unit-Tests zu testen.
Unser Beispiel besteht aus einem Pipeline-Repository und einem Anwendungs-Repository, wie unten dargestellt.
devops/ # Gruppe, die DevOps Projekte beinhaltet
pipeline # Das Pipeline Projekt
apps/
some-application # Eine Anwendung, welche die Pipeline als Konsument via include nutztpipeline/
jobs/
build.yml
test.yml
quality.yml
pipeline.ymlinclude:
- local: 'pipeline/jobs/build.yml'
- local: 'pipeline/jobs/test.yml'
- local: 'pipeline/jobs/quality.yml'
stages:
- build
- test
- qualityinclude:
- project: 'devops/pipeline'
file: 'pipeline/pipeline.yml'
ref: '1.0.0'Testen der Pipeline
Wie stellen wir jetzt bei Weiterentwicklung der Pipeline sicher, dass diese weiterhin funktioniert, bevor wir sie an unsere Nutzer:innen ausliefern und diese feststellen müssen, dass die Pipeline nicht mehr nutzbar ist?
Eine einfache Lösung besteht darin, ein Testprojekt zu erstellen, das unsere Pipeline verwendet und so die Funktionsfähigkeit unserer Pipeline prüft. Dies würde in etwa wie folgt aussehen.
devops/
pipeline
spring-boot-test-app # unsere Testanwendung
apps/
some-applicationinclude:
- project: 'devops/pipeline'
file: 'pipeline/pipeline.yml'
ref: 'main'Wie vielleicht aufgefallen ist, haben wir den ref Wert von 1.0.0, was auf einen Git Tag verweist, auf main geändert, was den Default Branch im Pipeline-Repository referenziert.
Nun wollen wir die Ausführung der Pipeline des Testprojekts bei jeder Änderung auf dem main Branch im Pipeline-Repository automatisieren. Das erreichen wir einfach, indem wir eine Pipeline zum Pipeline-Repository hinzufügen, welche GitLabs Downstream-Pipelines Feature und das trigger-Schlüsselwort nutzt. Das führt zu folgendem Code:
pipeline/
jobs/
build.yml
test.yml
quality.yml
pipeline.yml
.gitlab-ci.yml # <- Die Pipeline im Pipeline-Repositorystages:
- test-pipeline
test-spring-boot-app:
stage: test-pipeline
trigger:
project: 'devops/spring-boot-test-app'
strategy: depend
# der Job läuft nur bei Änderungen auf dem main Branch
rules:
- if: $CI_COMMIT_BRANCH == 'main'Der Ablauf sieht nun so aus
Jedes Mal, wenn ein Commit auf dem main Branch im Pipeline-Repository erfolgt, wird eine CI/CD-Pipeline in devops/spring-boot-test-app gestartet, die wiederum den Pipeline-Code aus devops/pipeline vom main Branch verwendet. Die Verwendung der depend Strategie im Trigger führt sogar dazu, dass die Upstream-Pipeline fehlschlägt, wenn die Downstream-Pipeline fehlschlägt.
Verbesserung der Idee
Wenn wir nur den main Branch der Pipeline testen, könnten wir immer noch auf Fehler stoßen, nachdem wir bereits ein neues Feature zur Pipeline hinzugefügt haben. Was wir eigentlich möchten, ist einen Feature Branch testen, bevor wir ihn in den main Branch mergen. Das ist überraschend einfach, da wir die Branch-Information in vordefinierten GitLab-Variablen wie CI_COMMIT_BRANCH und CI_COMMIT_REF_NAME zur Verfügung haben und wir ebenfalls eine Variable im ref des include verwenden können. Es gibt zwar einige Einschränkungen hinsichtlich der Variablen, die im include verwendet werden können, aber wir können mit einer Projekt- oder Gruppen-Variable arbeiten, und - das ist wichtig - einer Trigger-Variablen, die wir PIPELINE_REF_NAME nennen werden.
Wir müssen PIPELINE_REF_NAME als Projekt- oder Gruppen-Variable für die Testanwendung in devops/spring-boot-test-app deklarieren und deren Wert auf main setzen, damit standardmäßig der main Branch von devops/pipeline inkludiert wird. Anschließend übergeben wir den Namen des aktuellen Pipeline Branches im Trigger an die Downstream-Pipeline.
stages:
- test-pipeline
test-spring-boot-app:
stage: test-pipeline
variables:
PIPELINE_REF_NAME: $CI_COMMIT_REF_NAME # <- wir übergeben den aktuellen Branch Namen an die Downstream-Pipeline
trigger:
project: 'devops/spring-boot-test-app'
strategy: dependinclude:
- project: 'devops/pipeline'
file: 'pipeline/pipeline.yml'
ref: $PIPELINE_REF_NAME # <- nutzt den Wert, den wir im Trigger setzen, oder den Standard aus der Projekt-VariableNun wird das include in der Downstream-Pipeline des Testprojekts dynamisch aufgelöst, abhängig vom Namen des Branches in der Upstream-Pipeline, was es uns ermöglicht, unseren geänderten Pipeline-Code vor dem Merge zu testen.
Fazit
Dieser Ansatz bietet natürlich keinen absoluten Schutz vor Fehlern und ist immer noch zeitaufwändig und ressourcenintensiv, aber er ermöglicht uns ein paar Testprojekte für häufig vorkommende Fälle zu erstellen und einige Fehler frühzeitig zu erkennen. Die Automatisierung erleichtert die Einbindung von Tests in den Pipeline-Entwicklungsprozess, genauso wie wir es mit anderen Softwarekomponenten auch tun würden, und verbessert sehr wahrscheinlich die Qualität unseres Produkts.