Versioned Azure App Configuration

post

Overview

App Configuration is a great way to store application configuration, it brings together both configuration, secrets and feature flags in a performant centralised manor.

This article covers an approach to use App Configuration with deployment slots so an application can be test against a staging slot and staged configuration before going live.

Versioned Backend

The first thing that I find useful for this process is to create a versioning strategy that works for your needs, the approach we often adopt is {MAJOR}.{MINOR}.{BUILD} which is Semantic Versioning. There is no need to snapshot each build version in App Configuration so {Major}.{Minor} works for this purpose.

Program.cs

The key part to note here is the '.Select(KeyFilter.Any, packageVersion);', this means that when the backend loads it will get the assembly versioned configuration values from App Configuration:

builder.Configuration.AddAzureAppConfiguration(options =>
{
    var programAssembly = typeof(Program).Assembly;
    var fileVersionInfo = FileVersionInfo.GetVersionInfo(programAssembly.Location);
    var packageVersion = $"{fileVersionInfo.ProductMajorPart}.{fileVersionInfo.ProductMinorPart}";
    var connectionString = builder.Configuration.GetValue<string>("APP_CONFIGURATION_CONNECTION_STRING_PROPERTY");
    var tenantId = builder.Configuration.GetValue<string>("AAD_TENANT_ID_PROPERTY");

    options.Connect(connectionString).ConfigureKeyVault(kv =>
    {
        kv.SetCredential(new DefaultAzureCredential(
            new DefaultAzureCredentialOptions
            {
                InteractiveBrowserTenantId = tenantId,
                SharedTokenCacheTenantId = tenantId,
                VisualStudioCodeTenantId = tenantId,
                VisualStudioTenantId = tenantId
            }));
    })
    .Select(KeyFilter.Any, packageVersion);
});

Update Version in Pipelines

For this to work well there needs to be proper versioning throughout your pipelines, whatever the approach, it needs to be

  - task: DotNetCoreCLI@2
    displayName: "DOTNET BUILD"
    inputs:
      command: publish
      publishWebProjects: false
      projects: "$(System.DefaultWorkingDirectory)/SOME_PROJECT/SOME.sln"
      arguments: "--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory) /p:Version=$(MinorVersion)"
      zipAfterPublish: true

In the above instance, the $(MinorVersion) is determined elsewhere using git commands as demonstrated below:

$build = $env:REVISION
$env = $env:BUILDSUFFIX
$source = "$(Build.SourceBranch)"

if($source.indexOf('sources/tags') -gt -1){
  $sources = $source.split('/')
  $incrementedVersion = [version]::parse($sources[($sources.length - 1)])
  $tagMessage = git tag -l $source.substring(10) --format='%(contents)' $BITRISE_GIT_TAG
} else {
  $gitTags = git tag --sort=-creatordate
  $tagMessage = $(git tag -n --sort=-creatordate --format='%(contents)' $BITRISE_GIT_TAG)[0]

  if($gitTags[0].indexOf('/') -gt -1){
    $tag = $gitTags[0].split('/')[1]
    $incrementedVersion = [version]::parse($tag)
  } else {
    $tag = $gitTags[0] 
    $version = [version]::parse($tag)
    $incrementedVersion = [version]::new($version.Major, ($version.Minor + 1), $buildNumber)
  }
}

echo "##vso[task.setvariable variable=MinorVersion;isOutput=true]$($incrementedVersion.Major).$($incrementedVersion.Minor)"

App Configuration

By this point, the backend is versioned effectively and expecting version configuration to exist in App Configuration, this means its required to start adding the version during the Azure infrastucture deployments, the following is an example in Bicep:

resource appConfigurationResource 'Microsoft.AppConfiguration/configurationStores@2022-05-01' = {
  tags: {}
  name: 'APP_CONFIG_NAME'
  location: 'West Europe'
  sku: {
    name: 'Basic'
  }
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    encryption: {
    }
  }
}

resource appConfigKeyValue 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = {
  name: 'MY_CONFIG_ITEM$3.3'
  parent: appConfigurationResource
  properties: {
    value: 'Some config'
  }
}]

This means that in App Configuration, the configuration values will all be nested by the version as in the image at the top.

Slot Switch

All of this means that the latest release can be deployed to a staging slot of an App Service, validated in a safe manor and then switched to production once confident.

  - task: AzureCLI@2
    displayName: 'SWAP SLOT'
    inputs:
      azureSubscription: 'CONNECTION_NAME'
      scriptType: pscore
      scriptLocation: inlineScript
      inlineScript: |
        az account set --subscription $(SUBSCRIPTION_ID)
        az webapp deployment slot swap -g $(RESOURCE_GROUP) -n $(APP_SERVICE_NAME) --slot staging --target-slot production
Tim Hills

Tim Hills

Tim has been working in solution delivery for over 15 years and has really exceled in the industry. He has been fortunate enough to work with some high-profile clients and challenging projects which has positioned him well for turning business requirements into reality.

Registered office

Address: Arceau Solutions Ltd, Dane John Works, Gordon Rd, Canterbury, CT1 3PP

Telephone: 0208 191 7030