Software-Auslieferungsprozess beherrschen, Teil 2 Continuous Delivery mit GitHub Actions

Ein Gastbeitrag von Jürgen Kürpig *

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.

Zusammenspiel manueller und automatisierter Aktivitäten.
Zusammenspiel manueller und automatisierter Aktivitäten.
(Bild: J. Kürpig)

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.

Zusammenspiel manueller und automatisierter Aktivitäten.
Zusammenspiel manueller und automatisierter Aktivitäten.
(Bild: J. Kürpig)

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:

Jetzt Newsletter abonnieren

Täglich die wichtigsten Infos zu Softwareentwicklung und DevOps

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung

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.

Manuelle AKtivitäten.
Manuelle AKtivitäten.
(Bild: J. Kürpig)

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.

Workflows unter dem Menüpunkt Actions in GitHub.
Workflows unter dem Menüpunkt Actions in GitHub.
(Bild: J. Kürpig)

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

Environments mit Reviewer einrichten.
Environments mit Reviewer einrichten.
(Bild: J. Kürpig)

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.

Reviews bzw. Approvals durchführen.
Reviews bzw. Approvals durchführen.
(Bild: J. Kürpig)

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.

Fertiger Release Workflow.
Fertiger Release Workflow.
(Bild: J. Kürpig)

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.

Jürgen Kürpig
Jürgen Kürpig
(Bild: adesso)

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)