How to deploy App Service settings via Azure DevOps pipeline
Introduction
In this article, I am going to demonstrate a building block that allows pushing run-time parameters to an App Service configuration via an Azure DevOps pipeline.
It is not far to seek that one would tend to use the Azure App Service Settings task (AzureAppServiceSettings@1
) for such an exercise. However, what's special about this proposal is that we are going to leverage Azure's App Configuration Service instead together with an Azure CLI task. The following diagram depicts the intended setup.
One can argue that I am misusing the App Configuration Service, as its main purpose is slightly different than what we are going to use it for...
What is the Application Config Store? - A fast, scalable parameter storage for app configuration, that is complementary to Azure Key Vault. It helps you manage application settings and control their access centrally. It also simplifies your deployment tasks and eases the burden of dealing with permutations of configurations created by multiple applications, dependencies, and environments.
... usually, you'd use a client library in conjunction with this service to retrieve parameters for your application at run-time (such as the Microsoft.Azure.AppConfiguration.AspNetCore
).
At the same time, it provides benefits such as feature toggling, reacting to events, point-in-time snapshots, and other benefits, to name a few. So it's more of a developers tool than a DevOps tool 😊
Anyway, we are going to make use of the import/export function, as it allows us to directly export key-value pairs to an App Service Configuration.
But hey, what's wrong with the Azure App Service Settings Task?
First of this task tigthly couples configurational aspects and the deployment logic to each other. To mitigate that, one might want to create a variable group per environment and then pass them to the task.
However, I find that needlessly effortful, as you would have to create the keys twice, which can be error-prone. At the same time, configurational parameters would live, and have to be maintained, in Azure DevOps. I rather prefer them to live in the Azure service.
Next, when dealing with many configuration parameters your pipeline can become confusingly long. To be fair, one could neaten that with pipeline templates.
Also there is no syntax validation available as the configuration is defined in JSON and passed as a string within the Azure YAML pipeline. Another point where things can go wrong.
Finally I found it rather inconvenient when dealing with more than a single environment (dev, sprint, production).
"Okay, okay I got it...", you say. "Give me that solution!"
Solution
The solution is rather simple. For demonstration purpose let us ramp up a demo environment, by using the following bicep code.
This will create two App Services (development, production) and an App Configuration store for us holding three key-value pairs.
Next you'll have to add the following Azure CLI
task to your pipeline.
- task: AzureCLI@2
displayName: 'Push config to development'
inputs:
azureSubscription: '<ARM_Service_Connection>'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
ID=$(az webapp show --name app-appcs-demo-development --resource-group rg-appcs-demo --subscription <subscription> --query id --output tsv)
az appconfig kv export --name appcs-demo --destination appservice --label development --yes --appservice-account $ID
At its core we are using Azure CLI to export all key-value pairs carrying a label called development
to the App Service named app-appcs-demo-development
.
Conclusion
And that is all there is to it, simple and clean. Maintaining App Service settings now feals more conveniant while the configurational aspect is decoupled from the deployment logic. Also any changes made to a parameter will show up in the history and can be easily reverted.
As an added benefit it lets you quickly duplicate environmental settings into a new one by exporting to a new label.
Oh, and did I mention that the smallest SKU of the App Configuration Service is sufficient that comes for free? 😀Sweet, isn't it 😎