Software-Auslieferungsprozess beherrschen, Teil 2 Continuous Delivery mit GitHub Actions
Anbieter zum Thema
Wie sich das bereits gezeigte Konzept YAML-gesteuerter Aktivitäten auf Continuous Delivery erweitern lässt, schauen wir uns hier am Beispiel von GitHub-Actions an. Dazu gehört auch die Möglichkeit, die Aktivitäten automatisiert auszuführen.

Im ersten Teil dieser Kurzserie haben wir jeweils ein YAML-Modell zur Beschreibung der IT-Infrastruktur und der konkreten Ausprägung eines Release entwickelt Basierend darauf haben wir mit einem einfachen Tool-Stack eine komplexe Checkliste mit durchzuführenden Aktivitäten generiert.
Sollen die im Modell hinterlegten Aktivitäten des Auslieferungsprozesses mit GitHub-Actions automatisiert werden, muss zunächst bestimmt werden, wie das Mapping der Modellelemente auf die CI/CD-Modellelemente unter GitHub-Actions wie (Reusable) Workflows, Jobs, Steps, Actions, Environments, … erfolgen soll.
Bei der hier gewählten Lösung spielt vor allem das Konzept der Environments eine zentrale Rolle, bei dem die einzelnen Umgebungen per sogenannter Protection Rules geschützt werden können. Dazu werden sogenannte Reviewer definiert, die die automatisierten Jobs erst nach expliziter Freigabe z.B. des Release Managers oder Integrators für die gesamte Umgebung anstoßen.
Damit ergibt sich die Gelegenheit, noch weiterhin benötige manuelle Aktivitäten nach der automatisierten Bestückung der letzten Umgebung und vor der Bestückung der nächsten Umgebung durchzuführen. Ein weiterer Vorteil dieses Konzepts besteht darin, den Automatisierungsgrad sukzessive ausbauen zu können. Das vorangestellte Bild zeigt ausschnittsweise dieses Zusammenspiel manueller und automatisierter Aktivitäten bei der Bestückung der einzelnen Umgebungen.
Zur Unterscheidung manueller oder automatisierter Aktivitäten wird im Modell das Attribut execution ausgewertet:
- Für die vor- und nachbereitenden Aktivitäten in den Umgebungen wird das Attribut mit manual oder mit auto belegt.
- Für die Aktivitäten der Komponenten wird das Attribut davon abweichend mit manualBefore, manualAfter oder mit auto gesetzt.
Workflows in GitHub Actions generieren
Zunächst erfolgt aus dem Klassifikationsmodell der Infrastruktur (Datei activities.yml) je Komponententyp die Generierung eines parametrisierbaren Reusable Component Workflow, der später über einen übergeordneten Release Workflow mit konkreten Parametern aufgerufen wird. Analog wird dazu jeweils auch ein Reusable Workflow für die umgebungsspezifischen Aktivitäten erzeugt, die vor bzw. nach dem Deployment aller Komponenten je Umgebung ausgeführt werden sollen.
Mit den Angaben zum Release im Instanzmodell (Datei release.yml) wird im Anschluss zum einen der konkrete, übergeordnete Release Workflow, aber auch eine dazu passende übergeordnete Aktivitätenliste mit den manuellen Aktivitäten wieder als Checkliste in der schon aus Teil 1 bekannten Form generiert.
Die Erzeugung der Reusable Component Workflows erfolgt in dem GitHub-Projekt delivery-master mit dem folgenden Befehl:
mvn clean generate-sources –DcomponentWorkflows
Ein Einblick in den generierten Boilerplate Code eines Reusable Component Workflow für den Komponententypen EAR gibt der folgende Auszug:
name: EAR Activities Workflow
on:
workflow_call:
inputs:
env:
required: true
type: string
name:
required: true
type: string
version:
required: true
type: string
tags:
required: false
type: string
jobs:
EAR-ReleaseBuild:
if: ${{ ( contains(inputs.tags, 'DEPLOY') ) && ( contains(inputs.env, 'INT') || contains(inputs.env, 'HOT') ) }}
runs-on: ubuntu-latest
environment: ${{ inputs.env }}
steps:
- name: ReleaseBuild
run: echo "ReleaseBuild with params (env=${{ inputs.env }}, name=${{ inputs.name }}, version=${{ inputs.version }})."
EAR-CheckApprovalRepo:
if: ${{ always() && !(contains(needs.*.result, 'failure')) && ( contains(inputs.tags, 'DEPLOY') ) && ( contains(inputs.env, 'INT') || contains(inputs.env, 'HOT') ) }}
needs: EAR-ReleaseBuild
runs-on: ubuntu-latest
steps:
- name: CheckApprovalRepo
run: echo "CheckApprovalRepo with params (env=${{ inputs.env }}, name=${{ inputs.name }}, version=${{ inputs.version }})."
...
Zunächst ist die Definition diverser Workflow-Parameter zu erkennen, die später aus der Release-Definition in der Datei release.yml (Instanzmodell) entnommen und übergeben werden, Beispiel:
- die konkrete Umgebung wie z.B. INT für Integrationsumgebung,
der konkrete Name der Komponente wie Program1,
die konkrete Version wie 2.1.0 oder auch
die konkreten Auslieferungsaspekte als Auflistung der Tags wie DEPLOY, DB, CONFIG
Je Komponentenaktivität wurde zu Demonstrationszwecken für den späteren Probelauf jeweils ein Job und ein Step mit dem Aufruf einer Shell generiert, in der die übergebenen Parameter ausgegeben werden. In einer weiteren Implementierungsstufe können die Shell-Aufrufe dann je nach vorliegender DevOps- bzw. IT-Infrastruktur durch die spezifischen Actions ersetzt werden.
Die modellierte Abhängigkeit in den Komponentenaktivitäten von den Umgebungen (Attribut envs) und den Auslieferungsaspekten (Attribut tags) findet sich auch hier in der if-Bedingung des jeweiligen Jobs wieder.
Mit der needs-Bedingung wird erreicht, dass die Jobs nicht parallel (default bei GitHub-Actions) sondern sequentiell abgearbeitet werden. Eine parallele Verarbeitung lässt sich dagegen später beim Aufruf der Reusable Workflows aus dem übergeordneten Release Workflow heraus gut erkennen, d.h. die Komponenten werden dann parallel ausgeliefert.
Ab dem 2-ten Job wird in der if-Bedingung noch berücksichtigt, dass vorausgesetzte Jobs in der needs-Bedingung auch in ihrer Ausführung vorher „skipped“ werden können und der aktuelle Job davon unabhängig dennoch anlaufen soll, wenn alle anderen Bedingungen zutreffen.
Die Erzeugung des übergeordneten Release Workflow erfolgt in dem GitHub-Projekt delivery-master mit dem folgenden Befehl:
mvn clean generate-sources –DrelWorkflow
Das folgende Code-Snippet liefert einen Blick auf den generierten Release Workflow (Ausschnitt):
name: Release Workflow
on:
workflow_dispatch
jobs:
INT-PreActivities:
uses: ./.github/workflows/activitiesPre.yml
with:
env: INT
INT-Program1:
uses: ./.github/workflows/componentEAR.yml
needs: INT-PreActivities
with:
env: INT
name: Program1
version: 1.0.6
tags: 'DEPLOY,DB,CONFIG'
INT-Program3:
uses: ./.github/workflows/componentEXE.yml
needs: INT-PreActivities
with:
env: INT
name: Program3
version: 1.2.7
tags: 'DEPLOY,DB,CONFIG'
INT-AdapterC:
uses: ./.github/workflows/componentMule-Adapter.yml
needs: INT-PreActivities
with:
env: INT
name: AdapterC
version: 1.2.0
tags: 'DEPLOY'
INT-PostActivities:
uses: ./.github/workflows/activitiesPost.yml
with:
env: INT
needs: [INT-Program1,INT-Program3,INT-AdapterC]
...
Der Release Workflow beginnt mit dem Aufruf des Reusable Workflow für die vorbereitenden Aktivitäten in der INT-Umgebung und ruft dann abhängig von der Definition des konkreten Release im Instanzmodell nacheinander die Reusable Workflows der betroffenden Komponenten mit den definierten Tags und der aktuellen Umgebung auf.
Die Aktivitäten der Komponenten laufen dann parallel los, wenn die vorbereitenden Aktivitäten abgearbeitet worden sind. Ebenso werden die nachbereitenden Aktivitäten erst dann angestoßen, wenn alle Komponentenaktivitäten in der betreffenden Umgebung erfolgreich durchgeführt werden konnten. So geht der Release Workflow dann sukzessive auch für die folgenden Umgebungen vor.
Zusätzlich zur Erzeugung des übergeordneten Release Workflows werden die manuellen Aktivitäten generiert, wie der Bildausschnitt vorne verdeutlicht. Die hervorgehobenen Zeilen signalisieren die Abzweigung in den automatisierten Release Workflow über die Reviews bzw. Approvals für die Umgebungen.
Die generierten Workflow-Dateien müssen anschließend nur noch in den Ordner ./github/workflows des GitHub-Projekts zur Nutzung durch GitHub-Actions übertragen werden. Unter dem Menüpunkt „Actions“ finden sich nach dem Hochladen der Dateien in GitHub die gewünschten (Reusable) Workflows, bereit für die Ausführung:
Release Workflow ausführen
Bevor der Probelauf gestartet werden kann, müssen in den Umgebungen noch die Reviewer als Protection Rule unter den Projekt-Settings angelegt werden. Nun kann der Release Workflow unter dem Menüpunkt „Actions“ ausgewählt und mit dem Schalter „Run Workflow“ manuell gestartet werden.
Der Release Workflow ist nun aktiviert und wartet für jede Umgebung auf das Approval durch einen der definierten Reviewer. Dazu wird der Schalter „Review Deployment“ benutzt, über den die Freigabe für jede Umgebung durchgeführt werden kann. Gemäß dem Konzept soll dies jedoch erst dann durchgeführt werden, nachdem die betreffenden manuellen Aktivitäten in der Check-Liste abgearbeitet sind.
Wenn der Release Workflow komplett über alle Umgebungen abgearbeitet ist, sieht der Lauf unter GitHub-Actions dann wie im vorangestellten Bild aus (mit Zoom auf einen Teilbereich). Die Jobs wurden alle erfolgreich abgearbeitet oder aufgrund der modellierten Bedingungen (tags, envs) „geskippt“. Im unteren Bereich des Screenshots erscheinen die durchgeführten Deployment Reviews bzw. Environment Appovals.
Die graphische Aufarbeitung lässt bei solchen komplexeren Workflows leider noch ein paar Wünsche offen. Hier hilft dann ein Mouse Over über einzelne Jobs, um die konkrete Verzweigung besser anzeigen zu können, wie dies oben im Bild zu sehen ist. An der im Bild konkret hervorgehobenen Verzweigung ist die oben versprochene, parallele Verarbeitung bei der Auslieferung der einzelnen Komponenten deutlich zu erkennen.
Fazit
Die Artikelserie hat gezeigt, dass das GitHub-Projekt delivery-master mit seinen verschiedenen Optionen eine sinnvolle Unterstützung im Release-Management leisten kann. Dabei steht primär die übergeordnete Betrachtung des gesamten IT-Systems mit all seinen Komponenten im Vordergrund.
Von der Checkliste mit der interaktiven Ausführung bis hin zur vollständigen Automatisierung kann sogar der Grad der Automatisierung bestimmt werden. So lässt sich mehr Kontrolle über den Auslieferungsprozess gewinnen. Anstelle von Continuous Delivery oder Continuous Deployment einzelner Komponenten können nun über ein „Conscious Delivery“ bewusst und kontrolliert Deployments aus der übergeordneten IT-Systemsicht heraus durchgeführt werden.
* Jürgen Kürpig ist Software Architect bei adesso insurance solutions und unterstützt seit vielen Jahren java-basierte IT-Projekte in unterschiedlichen Rollen in den Themengebieten Architektur, Integration, Konzepterstellung und Projektmethodik.
(ID:48284894)