Für Entwickler, Architekten, Projektleiter und...

Read more

In der Welt der Softwareentwicklung ist die...

Read more

QUIBIQ spendet für den guten Zweck – und für...

Read more

Eine bestimmte Antwort auf einen HTTP Request zu...

Read more

In einer Welt, die von stetigem Wandel geprägt...

Read more

In einem unserer Kundenprojekte, war das Ziel eine...

Read more

QUIBIQ Hamburg wird mit dem Hamburger...

Read more

Zwei Tage lang wurde vom 14.-15.11 wieder das...

Read more

Was ist ein Excel-Plugin – und wann ist es...

Read more

Wir expandieren, bringen Kunden und Talente besser...

Read more

How-to: Staged Deploy mit YAML-Pipeline-Templates in Azure DevOps

Auf Azure DevOps gibt es die alten “Classic Pipelines” und die neuen „YAML Pipelines“. Erstere sind in DevOps separat gespeicherte Artefakte (intern ebenfalls im YAML-Format), zweitere im Projekt-Repository selbst enthaltene und damit zusammen versionierte YAML-Dateien. Mittels Templates in YAML-Pipelines (parametrisierte Includes) können dieselben Deploy-Tasks für ein zu deployendes und zu konfigurierendes Artefakt für verschiedene Deploy-Stages (z.B. Develop, Testing, Production) wiederverwendet werden. Damit kann das DRY-Prinzip (don’t repeat yourself) gewährleistet werden – nur so garantiert (bei Änderungen) ein erfolgreicher Deploy auf Testing, dass dieser auch auf Production fehlerfrei durchlaufen wird.

YAML-Struktur

Haupt-YAML-Datei

Eine Pipeline mit Templates besteht zunächst aus einer Haupt-YAML-Datei, welche mit „New pipeline“ im Azure DevOps registriert wird:

Diese Datei ist als einzige im DevOps selbst editierbar. Sie besteht minimal aus folgenden Sektionen:

pool:

trigger:

variables:

parameters:

stages:

- stage:develop

- stage:testing

  dependsOn:

    - develop

- stage:production

  dependsOn:

    - testing

pool: definiert den Agenten, der die Pipeline ausführt und trigger: den Git-Branch, der bei Commits die Pipeline startet. Ein Beispiel der YAML-Struktur für eine Deploy-Stage folgt weiter unten.

 

Variablen versus Parameter

Die Sektionen „variables“ und „parameters“ sind zunächst ähnlich: Variablen definieren ausschließlich „flache“ benannte Strings, welche in $( )-Syntax anstelle von Platzhaltern eingefügt werden:

Variablen-Definitionsbeispiel

variables:

  BuildConfiguration:'Release'

Variablen-Platzhhalterbeispiel

    msbuildArguments:'/p:Configuration=$(BuildConfiguration)'

Parameter können spezifisch an inkludierte Templates übergeben werden, im Gegensatz zu Variablen, welche entweder global und somit für alle Templates gleichermaßen sichtbar sind, oder in der Haupt-YAML-Datei innerhalb eines Jobs für diesen Job lokal deklariert werden.

Parameter können auch als Key/Value-Dictionaries von Objekten mit einer Eigenschaftsliste deklariert werden. Genau diese Eigenschaft ist der Schlüssel für den Staged Deploy: Für jede Stage wird ein strukturidentisches Objekt mit den je spezifischen Werten für die jeweilige Stage deklariert. Die Objekt-Syntax ist etwas kompliziert (reine YAML-Syntax wäre simpler, wird aber von DevOps-Pipelines nicht akzeptiert). Ein Beispiel von Parameter-Objekten für eine Logic App, welche für drei Stages auf drei verschiedene Ressourcengruppen zu deployen ist:

Parameterobjekt--Definitionsbeispiel

parameters:

- name:LogicAppDev

  type:object

  default:

    ResoureGroup:'qbq-rg-liquid-dev'

    LogicAppName:'qbq-la-liquid'

    MapName:'AzureLiquidJSONValidator-dev'

- name:LogicAppTest

  type:object

  default:

    ResoureGroup:'qbq-rg-liquid-test'

    LogicAppName:'qbq-la-liquid'

    MapName:'AzureLiquidJSONValidator-test'

- name:LogicAppProd

  type:object

  default:

    ResoureGroup:'qbq-rg-liquid-prod'

    LogicAppName:'qbq-la-liquid'

    MapName:'AzureLiquidJSONValidator-prod'

Die Objekt-Deklaration mit „type:object“ und der syntaktisch notwendige „default:“ –Pseudo-Konstruktor sind DevOps-spezifisch. Das parameters-Objekt deklariert drei Properties LogicAppDev, LogicAppTest, LogicAppProd, welche auf drei Objekte verweisen, die wiederum jeweils drei Stage-spezifischen Properties ResoureGroup, LogicAppName, MapName deklarieren.

Die Template-Parameter-Platzhaltersymtax ist ${{ }} anstelle von $( ) wie bei Variablen. Ein Template-Include mit Objektparametern für das Template hat folgende Form, hier wird das Template deploy-logicapp.yml eingefügt und als Platzhalter-Parameter das Objekt für die Stage „Test“ übergeben:

Parameterobjekt-- Platzhhalterbeispiel

          - template:Templates.yml/deploy-logicapp.yml

            parameters:${{ parameters.LogicAppTest }}

 

YAML-Struktur für eine Deploy-Stage

Hier ein minimales Beispiel für eine Deploy-Stage mit einem Deployment-Job für Production, der voraussetzt, dass vorher auf Testing deployed wurde. Objektparameter sind grün hinterlegt, die beiden Job-lokalen Variablendeklarationen gelb. Das „workspace: clean:all“ ist nur nötig für Selbstgehostete Build Agents (dann aber wirklich, sonst wächst das Arbeitsverzeichnis mit jedem Lauf ins Unendliche).

- stage:production

  dependsOn:

    - testing

  jobs:

  - deployment:deploy_production

    workspace:

      clean:all

    environment:'qbq-env-production'

    variables:

      ArtifactPath:'$(ArtifactPathDownloaded)'

      MapsPath:'$(MapsPathDownloaded)'

    strategy:

      runOnce:

        deploy:

          steps:

          - template:Templates.yml/deploy-logicapp.yml

            parameters:${{ parameters.LogicAppProd }}

Inkludierte Template-YAML-Dateien

Die einzelnen Template-YAML-Dateien (vorzugsweise in einem eigenen Ordner) sind im DevOps-GUI nicht zugänglich, sondern müssen im Projekt-Repository (z.B. mit Visual Studio) selbst editiert werden. Templates können transitiv weitere Templates inkludieren, wobei dann der innere Pfad relativ zum inkludierenden Template angegeben muss, also im Beispiel ohne obiges „Templates.yml/“.

Die Templates sind wirklich als Include zu verstehen, nicht etwa als eigenständige Pipeline-YAML-Dateien: Es ist strukturell nur das erlaubt, was auch literal anstelle des Includes stehen könnte. So sind zum Beispiel keine Variablendefinitionen erlaubt für YAML-Dateien, die wie oben von einem Deploy-Task inkludiert werden.

Hier ein (gekürztes, daher nicht funktionsfähiges) Beispiel für ein YAML-Template, welche obige Objekte in zwei Deploy-Tasks verwendet. Übergebene Objektparameter sind grün hinterlegt, Variablen gelb.

- task:AzureResourceManagerTemplateDeployment@3

  displayName:'Deploy the Logic App to ${{ parameters.ResoureGroup }}'

  inputs:

    deploymentScope:'Resource Group'

    action:'Create Or Update Resource Group'

    resourceGroupName:'${{ parameters.ResoureGroup }}'

    location:'West Europe'

    templateLocation:'Linked artifact'

    csmFile:'$(ArtifactPath)LogicApp.json'

    csmParametersFile:'$(ArtifactPath)LogicApp.parameters.json'

    overrideParameters: >

      -logicAppName ${{ parameters.LogicAppName }}

    deploymentMode:'Incremental'

- task:AzurePowerShell@5

  displayName:'Set-AzIntegrationAccountMap'

  inputs:

    TargetAzurePs:LatestVersion

    scriptType:inlineScript

    script: |

      Set-AzIntegrationAccountMap `

          -ResourceGroupName "$(ResourceGroup)" `

          -Name "$(IntegrationAccount)" `

          -MapName "${{ parameters.MapName }}" `

          -MapType "Liquid" `

          -MapFilePath "$(MapsPath)AzureLiquidJSONValidator.liquid" `

          -Force

Deploy-Stages für ein Environment

Die  Environments für die jeweiligen Stages sind im DevOps-GUI zu definieren, genau wie in den Classic Pipelines, denn es gibt dafür keine Entsprechung in YAML-Pipelines selbst. Ein Beispiel:

   

Auch die Approvals für ein Environment (=Stage) sind gleich, also die Personen, die einen Deploy freigeben müssen, damit er tatsächlich erfolgt: (Klick auf die drei Punkte rechts oben).

Die Liste der Approvers wird durch Klick auf „Approvals and check“ bearbeitet, also zunächst:

Bei Klick auf das Element erscheint die Liste:

Validierung eines Deployments

Das Freigeben eines Deployment auf eine Stage (Approvals) ist der erste Schritt, die Pipeline sollte aber erst erfolgreich durchgelaufen sein, wenn jemand bestätigt hat, dass die Stage auch tatsächlich läuft. Das nennt sich „Manual Validation“ und ist in der YAML-Pipeline ein zusätzlicher Job in der Liste der Jobs für eine Stage, hier ein Beispiel mit einer Variable für die Liste der Leute, die validieren können:

variables:

  ManualValidationUsers: |

    karla.test@example.com

    karl.muster@example.com

    jon.doe@example.com

 

 (…)

  - job:waitForValidation

    dependsOn:deploy_production

    displayName:'Confirm that production is up'

    pool:server

    timeoutInMinutes:4320

    steps:

    - task:ManualValidation@0

      timeoutInMinutes:1440

      inputs:

        notifyUsers:$(ManualValidationUsers)

        instructions:'Please confirm that the that the production environment running'

        onTimeout:'reject'

Approvals für ein Environment sind implizit AND-verknüpft: Alle Approvers müssen ihr OK geben, damit der Deploy-Job überhaupt beginnt. Validierungen für eine Stage hingegen sind OR-verknüpft: Es reicht, wenn eine Person aus der Liste im DevOps-GUI ihr OK gibt, damit die Pipeline weiterläuft oder endet.

Geschrieben von Toni Arnold, Senior Developer QUIBIQ Schweiz AG

                                                                                                                                                                                         

© QUIBIQ GmbH · Imprint · Data protection