Deploying Web Apps for Containers with Azure Pipelines

January 4, 2019
[ azure  azure-devops  pipelines  docker  devops  ]

_config.yml

I am currently working on a project where we have elected to use .NET Core and have been asked to allow deployment flexibility. The platform versatility of .NET Core allows us the option to containerize our apps, which is exactly what we’re doing. But instead of diving into the deep end of what could eventually become Kubernetes right off the bat, we want to keep things simple. In this case, we’ve chosen to use Azure Web Apps for Containers. This post walks through our code management process and continuous delivery of infrastructure and containers.

Please see this Gist for full code references.

Code management

The overall solution we are creating has somewhere in the range of 10 API applications that need to be deployed. We are managing each of the apps within its own repository in Azure DevOps in order to tie the application deployment directly to a modified Gitflow process.

Infrastructure as code

There is nothing special about the App Service Plan deployment in this case, provided that you use the "kind": "linux" flag because Web Apps for Containers does not work on Windows as far as I know.

They key to making this work is within the Web App resource definition, specifically the siteConfig values. You may have seen other posts add an additional siteConfig value of "linuxFxValue": "DOCKER|<image-name>:<tag>", which only works for ARM template deployment. Note: if you are going to use Azure Pipelines (as I am in this post), do not set this value as it will get overwritten every time you deploy your ARM template. Our Release will override this value.

Continuous delivery

Since we’re using containers, the build definitions are fairly simple because the process steps are defined within our Dockerfile. I have included my YAML CI and CD build definitions in the Gist for reference.

The delivery process looks like this:

  1. Developer makes changes in a feature branch.
  2. Developer creates a Pull Request. CI Build is automatically queued, which is required for merge. Note: set this up as a branch policy, not a trigger in the CI Build definition.
  3. Lead merges Pull Request. CD Build is automatically queued.
  4. CD Build pushes container image automatically to our Azure Container Registry (ACR) instance.
  5. Release is triggered automatically on new ACR push. This is important, because a typical release would trigger on CD Build completion. We made this decision to keep our options open later - for example, this allows us to make minimal changes to the pipeline if we move to Kubernetes with Spinnaker instead of Pipelines.
  6. Dev environment Web App underlying image is updated by Release.

The Release only has a single Azure App Service Deploy task. To configure it to deploy containers, switch the App Type to Linux Web App, which then defaults to an image source of Container Registry.

I took a look at the logs from when the task runs, and it outputs the following:

Updating App Service Configuration settings. Data: {"appCommandLine":null,"linuxFxVersion":"DOCKER|<ACR-instance-name>.azurecr.io/<image>:<build-id>"}

This is why it’s OK that you left the linuxFxVersion value empty in the ARM template since Release overrides it.

Share this post!