
Dynamische Pipelines in GitLab sind eine Teilmenge der Child-Pipelines. Sie haben dieselben Funktionen wie Child-Pipelines - der Unterschied besteht darin, wie Sie die Datei erstellen.
Einer der schwierigsten Aspekte beim Schreiben von Pipelines ist die Berücksichtigung von Permutationen. Oft wiederholen Sie dieselben Arbeitsabläufe mit nur geringen Unterschieden. Das ist besonders frustrierend, wenn Sie viele verschiedene Umgebungen ansteuern müssen.
Wir alle sind es gewohnt, unsere Workflow-Dateien zu erstellen und sie dann in die Versionskontrolle einzuchecken. Sie sind feststehende Gebilde, die wir unter Berücksichtigung aller Variationen erstellen müssen. Aber das muss nicht so sein - wir können Workflow-Dateien bei Bedarf erstellen. Mit dynamischen Pipelines ist genau das möglich.
Im ersten Beispiel wird ein
bashSkript verwendet, um die dynamischen Pipeline-Dateien zu erzeugen. Spätere Beispiele werden ein Python-Skript verwenden.
Ein grundlegendes Beispiel
Im Folgenden finden Sie eine kleine Einführung in die Erstellung einer dynamischen Pipeline.
Den Quellcode finden Sie im Referenz-Repository.
Wir definieren alles in .gitlab-ci.yml:
create-dynamic-pipeline-file:
script: |
cat <<EOF > dynamic-pipeline.yml
dynamic-job:
script:
- echo "This job is created dynamically"
EOF
artifacts:
paths:
- dynamic-pipeline.yml
trigger-dynamic-pipeline:
needs: [create-dynamic-pipeline-file]
trigger:
include:
- artifact: dynamic-pipeline.yml
job: create-dynamic-pipeline-file
In dem Auftrag create-dynamic-pipeline-file verwendet script hier die Dokumentennotation, um einen einfachen Auftrag zu erstellen. Das Ergebnis wird in eine Datei ausgegeben und als Artefakt gespeichert.
Der Auftrag trigger-dynamic-pipeline hängt von dem vorherigen Auftrag ab und löst die Child-Pipeline aus. Dies ist fast identisch mit dem Beispiel der Child-Pipeline.
Beachten Sie, dass Sie den Namen des erstellenden Auftrags zweimal angeben müssen. Einmal für
needsund ein weiteres Mal, um dem Trigger mitzuteilen, von welchem Auftrag die Pipeline stammt.

Dynamische Child-Pipeline-Ausgabe
Die Ausgabe der Child-Pipeline ist das, was wir angegeben haben.

Die dynamisch erstellte Pipeline-Datei ist zu einer untergeordneten Pipeline geworden
Die Pipeline-Ansicht ist fast dieselbe wie beim Auslösen einer regulären untergeordneten Pipeline - mit dem Zusatz, dass zuerst der Auftrag erstellt wird.
Eine dynamische Pipeline auf Python-Basis
In diesem nächsten Beispiel wird Python verwendet, um die Child-Pipeline-Datei zu erstellen.
Den Quellcode finden Sie im Referenz-Repository.
Auch hier beginnen wir mit .gitlab-ci.yml:
default:
image: python:3.7
create-file-job:
script: |
pip install -r requirements.txt
python generate_pipeline.py
artifacts:
paths:
- dynamic-pipeline.yml
trigger-dynamic-pipeline:
needs: [create-file-job]
trigger:
include:
- artifact: dynamic-pipeline.yml
job: create-file-job
Dies ist der Code für die Python-Datei generate_pipeline.py, die den Pipeline-Code erstellt:
import yaml
pipeline = {
"dynamic-pipeline": {
"script": [
"echo Hello World!"
]
}
}
with open("dynamic-pipeline.yml", "w") as f:
f.write(yaml.dump(pipeline, default_flow_style=False))
Beachten Sie, dass durch die Verwendung einer Sprache mit mehr Funktionen die YAML-Struktur in einer anderen Form als Text definiert werden kann. Das macht die programmatische Bearbeitung von YAML viel einfacher.
Umgekehrt wird dadurch die Fehlersuche in Ihrem endgültigen Pipeline-Code erschwert.
Und schließlich brauchen wir requirements.txt:
PyYAML
Wenn Sie unseren Code pushen, erhalten Sie die folgende Ausgabe:

Ausgabe der mit Python generierten dynamischen Pipeline
Wenn Sie den Großteil Ihrer Pipeline-Erstellung in ein Skript verlagern, können Sie Funktionen, Variablen, Schleifen und andere Programmiertricks verwenden, um die Komplexität zu verringern.
Übergabe von Argumenten an den Pipeline-Generator
Die Definition komplexer Pipelines in statischen Dateien bedeutet in der Regel die Erstellung komplizierter Regeln. Child-Pipelines nehmen uns einen Teil dieser Last ab, aber Sie müssen immer noch alles vordefinieren. Ein Skript, das den minimal notwendigen Pipeline-Code generiert, ist die bessere Lösung. Durch die Verwendung von Variablen haben Sie eine genaue Kontrolle darüber, was Ihr Skript ausgibt.
Den Quellcode finden Sie im Referenz-Repository.
Erweitern wir generate_pipeline.py und lassen Sie es ein paar Argumente aufnehmen:
import yaml
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--filename", help="Name of the file to write to")
parser.add_argument("--environment", help="The environment to deploy to", default="dev")
args = parser.parse_args()
pipeline = {}
pipeline["dynamic-pipeline"] = {
"script": [
"echo Hello World!"
]
}
environment = {
"needs": ["dynamic-pipeline"],
"script": [
f"echo Deploying to {args.environment}"
]
}
pipeline[f"deploy-to-{args.environment}"] = environment
print(pipeline)
with open(args.filename, "w") as f:
f.write(yaml.dump(pipeline, default_flow_style=False, sort_keys=False))
Beachten Sie, dass Python ab Version 3.7 die Reihenfolge der Wörterbuchschlüssel beibehält(siehe hier).
Wir können Variablen verwenden, um die Namen der Aufträge zu überarbeiten und die endgültige Datei zu erstellen.
Jetzt übergibt die Datei .gitlab-ci.yml Argumente an das Skript:
default:
image: python:3.7
variables:
PIPELINE_FILE: dynamic-pipeline.yml
ENVIRONMENT: test
create-file-job:
script: |
pip install -r requirements.txt
python generate_pipeline.py --filename=$PIPELINE_FILE --environment=$ENVIRONMENT
cat $PIPELINE_FILE
artifacts:
paths:
- $PIPELINE_FILE
trigger-dynamic-pipeline:
needs: [create-file-job]
trigger:
include:
- artifact: $PIPELINE_FILE
job: create-file-job
In diesem Fall sind die Argumente Dateiname und Zielumgebung Variablen. Diese können aus der GUI oder sogar aus einer vorgelagerten Pipeline stammen. Je nach Ihren Bedürfnissen muss die generierte Pipeline nur den wichtigsten Code enthalten. Sie müssen auch keine verschlungenen Regeln schreiben.

Die dynamische Child-Pipeline, einschließlich Abhängigkeiten
Beachten Sie, dass wir sogar Abhängigkeiten zwischen den dynamischen Aufträgen einrichten können.

Die Ausgabe des Auftrags 'deploy-to-test'.
Anhand der Ausgabe sehen wir, dass der Auftrag entsprechend den Variablen auf die 'Test'-Umgebung abzielt.
Fazit
Wenn Sie Ihre Pipeline mit Code generieren, heben Sie Ihre Builds auf die nächste Stufe. Oft ist die Diskrepanz zwischen dem Schreiben von Code und dem Schreiben von YAML-Pipelines ziemlich groß. Wenn Sie sich jemals gewünscht haben, Ihre Pipelines als Code schreiben zu können, sind dynamische Pipelines die Antwort.
Verfasst von
Jeffrey Zaayman
Contact