wiki.getshifting.com

--- Sjoerd Hooft's InFormation Technology ---

User Tools

Site Tools


azuredevopsappconfiguration

Azure DevOps Pipeline with Azure App Configuration

Summary: On this page I'll show you how to use the Azure App Configuration in an Azure DevOps Pipeline.
Date: 5 January 2025

Note: See here for the bicep module to deploy an Azure App Configuration Store.

What is Azure App Configuration

Azure App Configuration is a service that allows you to centralize your application settings and feature flags. It provides a way to manage the settings of your application in a single place, and it can be used to store key-value pairs that can be accessed by your application at runtime. I found it very useful as it also allows you to import variables into your Azure DevOps pipeline, allowing you to also manage your pipeline variables in a single place.

Azure App Configuration Tasks

Before you can use the Azure App Configuration tasks in your Azure DevOps pipeline you need to install the Azure App Configuration extension:

In case you haven't done so, you also need to setup an Azure DevOps Service Connection to your Azure Subscription. You can check the documentation here (import) and here (export) on how to do that.

Azure DevOps Pipeline

Download Variables

The pipeline below downloads all variables from the Azure App Configuration Store. For more info on the pipeline see Cheatsheet Azure DevOps. It downloads all variables with a global or dev label. In the app configuration store that is used for this task, all variables either have a global label or an environment label (dev, tst, acc, prd). This makes sure the correct variables are downloaded for the correct environment.

The last task is optional as it only logs the variables. This is useful for debugging the pipeline.

name: $(Build.DefinitionName)-$(Build.BuildId)

variables:
  buildConfiguration: 'Release'
  deploymentSuffix: '$(Build.DefinitionName)-$(Build.BuildId).$(System.StageAttempt).$(System.JobAttempt)'

parameters:
  - name: alllogs
    displayName: "Enable all logging"
    type: boolean
    default: true

pool:
  vmImage: ubuntu-latest

trigger: none

stages:
- stage: build
  displayName: "Stage: Build"
  pool:
    name: BuildPoolDotNet

  jobs:
  - job: build
    displayName: "Job: Build & Test"
    steps:
    - checkout: self
      clean: true

    - task: AzureAppConfiguration@7
      displayName: "Pull App Configuration Variables"
      inputs:
        azureSubscription: 'arm-shift'
        AppConfigurationEndpoint: 'https://appcs-euw-shift.azconfig.io'
        KeyFilter: '*'
        Label: 'global,dev'
        SuppressWarningForOverriddenKeys: true
      retryCountOnTaskFailure: 3

    - task: PowerShell@2
      displayName: "Log: Variables"
      inputs:
        pwsh: true
        targetType: 'inline'
        script: |
          Write-Host "`n##[section]Show pipeline variables`n"
          Get-ChildItem -path env:* | Sort Name
Note that you could replace the label with a parameter from the pipeline:
        Label: 'global,${{ parameters.environment }}'

Push Variables

Pushing variables to the Azure App Configuration Store is a bit more complex. The pipeline below first creates a file with the variables that need to be pushed, in yaml format. If no variables are found that need to be pushed it sets a pipeline variable 'AppConfig' and sets it to false. The next task checks for this variable so it doesn't fail because there is no file with variables, and then it pushes the variables to the App Configuration Store.

  - task: PowerShell@2
    displayName: "App Config: Prepare"
    inputs:
      pwsh: true
      targetType: 'inline'
      script: |
        Write-Host "##[section]Create push file"
        $pushConfigFile = "$env:Build_SourcesDirectory\$(Build.Repository.Name)\push\appconfigupload.yml"
        Write-Host "Push file dir: $pushConfigFile "
        if (Test-Path -Path $pushConfigFile -PathType leaf){
          Write-Host "Push file already exists. Remove $pushConfigFile"
          Remove-Item -Path $pushConfigFile -Force
        }
        $services = Get-ChildItem -path env:* | Where-Object {$_.name -like '*SERVIVE'} | select name,value
        if ($services){
          # create empty file and needed directories
          New-Item -Path $pushConfigFile -ItemType File -Force
          # add the variables to yml file
          foreach ($ervice in $services){
            $name = $service.Name
            $value = $service.Value
            Write-Host "Adding service: $name; value: $value"
            Out-File -FilePath $pushConfigFile -InputObject "$name`: $value" -Append
          }
        }else{
          Write-Host "No service variables have been found to upload to App Configuration"
          Write-Host "##vso[task.setvariable variable=AppConfig]False"
        }

  - task: AzureAppConfigurationPush@6
    displayName: "App Config: Push variables"
    condition: and(succeeded(), not(eq(variables['AppConfig'], False)))
    inputs:
      azureSubscription: 'arm-shift'
      AppConfigurationEndpoint: 'https://appcs-euw-shift.azconfig.io'
      ConfigurationFile: '$(BUILD.SOURCESDIRECTORY)/$(BUILD.REPOSITORY.NAME)/push/appconfigupload.yml'
      Separator: ':'
      Label: ${{ parameters.environment }}
      Strict: false
      DryRun: false
      ImportMode: 'Ignore-Match'
    retryCountOnTaskFailure: 3

Backup Variables

Even though you can create replicas of the Azure App Configuration Store, it's always a good idea to have a backup of your variables. This allows you to check if a variable was present in the app configuration store at a certain point in time and what the value was of that variable. The first taks below creates a backup file for each label in the app configuration store. The second task publishes the backup files as a pipeline artifact. This means the backup files will be lost after a while, so you could think about using a separate script to change this.

- task: AzureCLI@2
  displayName: Backup App Configuration
  condition: succeededOrFailed()
  env:
    SYSTEM_ACCESSTOKEN: $(System.AccessToken)
  inputs:
    azureSubscription: 'arm-shift'
    scriptType: pscore
    scriptLocation: inlineScript
    inlineScript: |
      # Set variables for app configuration in production
      $subId = "aa123456-a123-a123-a123-abcd12345678"
      $appcsName = "appcs-euw-shift"
      $backupDir = "$env:BUILD_ARTIFACTSTAGINGDIRECTORY/exported-appcs-configs"
 
      # Create backup directory
      if ( -not (Test-Path $backupDir) ){
          New-Item $backupDir -Type directory -Force
      }
 
      az account set --subscription $subId
 
      Write-Host '##[Section]Create backup files per label'
 
      [array]$allLabels = az appconfig kv list --name $appcsName --auth-mode login | ConvertFrom-Json | Select-Object label -Unique
      foreach ($label in $allLabels) {
          $labelName = $label.label
          Write-Host "Creating backup for label: $labelName"
          az appconfig kv export --name $appcsName --auth-mode login --destination file --path "$backupDir/$labelName.yaml" --format yaml --label $labelName --yes
      }

- task: PublishPipelineArtifact@1
  displayName: 'Publish Backup App Configuration'
  inputs:
    targetPath: '$(Build.ArtifactStagingDirectory)/exported-appcs-configs'
    artifactName: backupAppConfig
    artifactType: pipeline
    parallel: true
azuredevopsappconfiguration.txt · Last modified: by 127.0.0.1