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