Streamline your App Settings management for App Services

Azure App Service allows launching your apps quickly. You can run app as a code if you are using one of the supported languages, or run a docker container (or even a docker-compose).

Modern applications should be configurable by using some external data. Settings should not be stored in code repository.  Storing configuration in repo and building specialized packages requires doing a release every time there is a need to change a single setting. Injecting configuration during startup allows using a single code base for any of the environments. A need to prepare a dedicated package for each environment is no longer required. That approach greatly improves the CI/CD process and lowers the risk of deploying applications with the wrong configuration.

There are multiple ways to configure settings, starting from setting environmental variables up to using dedicated service like App Configuration. Let's focus on App Settings today.

Managing App Settings

When it comes to configuring App Service, you can use App Settings. App settings in Azure App Service are key-value pairs used to store configuration data for your application. They allow you to manage the configuration of your app without changing code or redeploying the application. App settings can (but not always should) store various types of information such as database connection strings, API keys, or feature flags.

💡
For storing sensitive values like conenctions strings or API keys consider using Key Vault.

If you are using any Infrastructure as a Code (IaaC) tool (e.g. Terraform) app settings can be configured there.

resource "azurerm_app_service" "cloudoing_app_service" {
  name                = "cloudoing"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  app_settings = {
    "key" 						 = "value"
    "environment"                = "demo"
    "color"                      = "azure"
    "address"				     = "cloudoing.com"
  }
}

That is definitely a great way to standardize the setup when you are starting working with IaaC. It streamlines configuration management, configuration is versioned and is linked to the deployed environment. Sounds great, right?

The challenges

After a while, you realize that every time, there is a need to update an app setting, you have to deploy the infrastructure code. On a small scale, that approach does work well, but when the infra grows things became more complicated.

Imagine there is a common set of variables that have to be deployed to 1, 5, 100 App services. Your IaaC can be well written, so it might be just a change of a single variable.  But it might not… :)

Another challenge is a team's and responsibilities. It is still very common that roles and responsibilities are separated between Infra & Apps teams. Especially in big organizations. The process of enabling a single team to make changes in every single place required to deliver a solution is challenging.

Decoupling Infrastructure settings from App Settings

As always, there are many ways to configure things. There is no single approach that covers all scenarios. Decoupling App Settings from infrastructure management is one of them. My experience shows that it is one of the easiest to start with. It doesn't require many changes, can be implemented quickly, and pays back fast by improving general app delivery agility.  

Managing settings by pipelines

The common way to manage settings is to update them on release. That approach decouples application changes from infrastructure and grants more control over the scope of the changes.

Azure DevOps currently offers two ways to manage releases. Modern – using pipelines and YAML definitions. It generally offers a better experience as the pipelines can be templated and stored as a code. And the classic way – releases, allowing more user-friendly release management.

Classic release pipelines

Create a new release and add the “Deploy Azure App Service” task.

App Settings and configuration settings in release pipeline

By clicking on the three dots, you can enter edit form. There, you can specify key-value pairs that will be set as app settings. The same can be done for Configuration settings.

YAML Pipelines

Similar can be achieved by using YAML pipelines variables.

Choose tasks AzureRMAppDeployment@4. If you are using Azure DevOps editor, use the tasks creation helper.

OK, environment variables (app settings) are decoupled from infra settings. But is there a better way to manage them now?

Yes – let's explore DevOps libraries.

Variables Library

Moving app settings configuration did not resolve the issue of storing the same configuration values in multiple places. Azure DevOps variables library might help you there.

Let's create our first variable group and add variables we previously included in pipelines.

💡
Sensitive variable value can be hidden. However, the best way would be to use Azure Key vault integration to pull sensitive values. 

Using variables stored in the Azure DevOps library

First, let's set it up for classic releases

Edit the previously created release and select the variables tab.

Managing linked variable group to the release pipeline

Link variable group

Linking Azure DevOps library variable group to release pipeline

It's worth highlighting that a variable group can target a single or multiply stages or the whole release pipeline. If you are using a single classic release pipeline to deploy to multiple environments, stages targeting might be useful to inject the proper set of variables.

Once linked, it's time to tell Azure DevOps to pull values from the Azure DevOps library during run.

To do so, replace values with ADO reference to variable - $(variableName)

Reference Azure DevOps library varaibles

Once this is done, Azure DevOps will replace variables with the values during the release.

Using Azure DevOps library in YAML Pipeline

Firstly, a variable group needs to be linked to the YAML pipeline

variables:
- group: demo
v

The next step is to replace variables values with references to variable group elements. This is done the same way as for the classic release pipelines.

variables:
- group: demo

trigger:
- None
pool:  
	vmImage: ubuntu-latest
    
steps:
- task: AzureRmWebAppDeployment@4  
	inputs:    
    ConnectionType: 'AzureRM'    
    appType: 'webApp'    
    WebAppName: cloudoing.com    
    packageForLinux: '$(System.DefaultWorkingDirectory)/**/*.zip'  
    AppSettings: |      
			-key $(key) 
			-environment $(environment)      
			-color $(color) 
			-address $(address)

Summary

App configuration management can be challenging when done manually or when it is too depended on processes that are not strictly linked to Application release process.

The demonstrated example is one of the ways to manage environmental variables. It is worth to be highlighted because it is a recommended step to move away from storing variables with a code. This approach helps to simplify the CI/CD process. The built package is always the same, regardless of what the target environment is, and variables will be injected at a later stage.

You've successfully subscribed to Cloudoing
Great! Next, complete checkout to get full access to all premium content.
Error! Could not sign up. invalid link.
Welcome back! You've successfully signed in.
Error! Could not sign in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.