CICD Pipeline for Serverless, release Azure Functions with VSTS.

While Serverless, Azure Functions, are just a few lines of code, they still require a release with all the principles a good pipeline. For example:

  • High quality by default.
  • Work in small batches.
  • Automate repetitive tasks.
  • Continuous improvement.
  • Everyone is responsible.
  • Transparency everywhere.

and some of the factors in the 12Factor methodology

  1. Codebase. One codebase tracked in revision control, many deploys
  2. Dependencies. Explicitly declare and isolate dependencies
  • Config. Store config in the environment
  1. Backing services. Treat backing services as attached resources
  2. Build, release, run. Strictly separate build and run stages
  3. Processes. Execute the app as one or more stateless processes
  • Port binding. Export services via port binding
  • Scale out via the process model
  1. Disposability. Maximize robustness with fast startup and graceful shutdown
  2. Dev/prod parity. Keep development, staging, and production as similar as possible
  3. Logs. Treat logs as event streams
  • Admin processes. Run admin/management tasks as one-off processes

Azure Function via Portal.

The implementation of an Azure Function can be written in the Azure portal (see: Create your first Azure Function). Not ideal for repeatability, automation, versioning, traceability, etc.  (see list above and select more).

Backed-up with GIT

For more control, the Azure Function can be connected to GitHub or VSTS (see screenshot). Better, but not ideal. When your release pipeline contains multiple environments, dev, test, staging and production you need the same number of branches in your Git repository, losing the ‘one codebase’ principle. There is also no control on the deployment other than a Pull to a specific branch. The config is decoupled from the release (App Function application settings), development is done locally in files where only a Pull to a certain branch results in compilation and validation, all functions are deployed at once and more disadvantages … defiantly not optimal.

Visual Studio Tools

With the latest Visual Studio Azure Function Tools, the development experience gets better. It is possible to build, run, validate, remote debug and deploy Azure Functions to Azure from a development environment. This also makes it possible to set up a more mature release pipeline for Azure Functions.


Within Visual Studio a solution can be created with multiple Azure Function projects (a funproj…), which can contain multiple Functions. A Visual Studio Azure Function project is a deployable grouping, all functions in a funproj are deployed together. So, when a system requires that functions evolve separately than they need to be in separate funproj’s.

The deployment of a funproj works just the same as the deployment of an Azure WebApp. It simply is a Web Deploy which needs a Publish profile, downloadable from the Azure portal.

ARM and Application Settings.

Only a comfortable way to deploy and run from a development environment isn’t enough to follow the principles of:

  • One code base,
  • configuration close to the environment,
  • separate build and run stages,
  • dev/prod parity

Dev/prod parity and destroy recreated can be reached via ARM definition files. The ARM definition for a single Azure Function App is not complex, the ‘special’ thing is the storage account the app needs, it won’t run without a proper configuration of this.

ARM can also be used for configuration and separate build/run stages. An Azure Function uses application settings the same way as Azure Web Apps, via the portal. Which is the best place to store all application settings, you can’t get any closer to the environment than that (the other place is the Azure KeyVault).

The integration points created in a function are registered in the application settings.

Also, these settings can be used in the function itself via WebConfigurationManager.AppSettings.Get(“settingname“);

In the ARM definition, this setting can be created via a resource setting in the Web App. Some settings will be overridden by the release process in a later deployment stage, mainly passwords. Most settings can be constructed out of parameters with variables and an environment setting (the preferred way).

VSTS Build and Release.

The Azure Function solution with multiple Azure Function projects and an ARM template is used to deploy to multiple environments, dev, test, staging, and production. All artifacts are in one code base and a branching strategy takes care we are always in a deployable state.

A resource group per environment and a separation between dev/test and staging/production for security and separation of costs are the landing environment for the functions. The grouping of functions (per funproj) is deployed separately.

With all this in place, ARM, config, solution and projects, the build can be configured. Actually, not a real build, functions are compiled on the platform (you can deploy precompiled bits too). But the build step is mainly a copying activity.

VSTS Build, CI.

The build for ARM and Azure Functions is minimal, normally it would compile, get the depending packages, unit test, code quality etcetera, but for Functions, all this can’t be done (yet?). For ARM we use some template validation tasks for naming conventions, security and other validations.

The publishing of the Function artifacts is only a copy action. A Function on Azure only exists of a Function.json and a run.csx (click the show files button in the Azure portal). This is also what the Visual Studio deployment does. It copies the artifacts to a temp folder, see C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\AzureFunctions\ Microsoft.AzureFunctions.Publishing.targets.

Something also the build definition needs to do, create build artifacts in a folder so the release can use them.

VSTS Release, CD.

The release contains two deployment activities (the test tasks are skipped for this post. Azure Functions is an integration solution, so a descent set of integration tests would be welcome).

The first activity is the ‘create or update Azure Resource Group’ with the parameters for the environment settings.

The second task is the deployment of the Azure Function. This task uses a small PowerShell script which reads the publish profile and uses MSDeploy.exe to deploy the function to Azure.

cmd.exe /C $(“msdeploy.exe -source:IisApp=’$wwwroot’ -dest:IisApp=’$websiteName’,computerName=’https://$publishURL/msdeploy.axd’,userName=’$userName’,password=’$password’,authtype=’Basic’,includeAcls=’False’ -verb:sync -enableLink:contentLibExtension  -enableRule:AppOffline  -retryAttempts:2”)

To use this MSDeploy in VSTS Release you can add an Azure PowerShell release step, which calls the PowerShell function with several parameters. To create a PowerShell script file which executes MSDeploy, look at:

For the deployment I’m using a little tweaked version of this script: Publishes a Windows Azure Web App from a Web Deploy Package using MSDeploy it accepts a publish settings file, which makes our live easier.

I’m using the same PowerShell for this: Build, publish and release DotNet Core 1.0.0 apps on Azure Websites with VSTS.

All this resulting in a mature release pipeline with all the capabilities which are available inside VSTS for traceability, transparency, testing and more.

Happy releasing in 2017.

Clemens Reijnen


Clemens Reijnen is a Management Consultant at Sogeti, specializing in Application Lifecycle Management. He facilitates ALM courses throughout Europe and is a frequent speaker at many conferences.

More on Clemens Reijnen.

Related Posts

Your email address will not be published. Required fields are marked *

4 + 1 =

  1. Melvin Vermeer January 5, 2017 Reply

    Hi Clemens,
    Great article! I was wondering why you are using a custom script to kick off msdeploy.exe?
    I deploy azure functions using the VSTS ‘Azure App Service Deploy’-task and that works fine.
    Makes live a little easier again, right?

  2. Clemens January 6, 2017 Reply

    @Melvin : agree, it is an old habit… noticed it too and changed it. thanks,