Continous Deployment on Azure App Services - Customize the deployment process

Post Tags:

So this is already the third part of my serie about Continous Deployment on Azure App Services (which is the new name of Azure Websites). In the first part I talked about what Continuous Deployment is and how it could easily be configured on Azure App Services. In the second post I showed how to add a staging environment so that you have a chance to test your changes before they are deployed to production. Now in this post I will show how the deployment process can be customized.

Cusom deployment script

The most transparent way to customize the deployment process is to have a custom deployment script. In fact what Azure does during deployment when there is no script, it just creates one for you. The easiest starting point is to let Azure create this deployment script which can then be customized according to your needs. In order to generate this script you need the Azure CLI tools. You can use the Windows Installer to install those tools or run npm install azure-cli -g if you have node installed.

Now navigate to the root folder of your repository with your favorite command line tool. If you have a ASP.NET application run this command to create the script:

azure site deploymentscript --aspWAP .\path\to\Website.csproj --solutionFile MySolution.sln  

Replace .\path\to\Website.csproj and MySolution.sln with the relative path to the csproj of your ASP.NET website of to your solution. Now this created a deployment script called deploy.bat in the root of your repository. The next time a deployment happens on Azure, this script will be used. If you look at the script there are basically 3 steps which are performed by default:

  1. Restore NuGet packages
  2. Build the website and deploy with Web-Deploy to a temporary location
  3. Sync the temporary location to the webite root directory

To customize the process just edit the deploy.bat. We could for example add a Web.config transformation during the deployment. Normally you have different configurations for your local development environment and for the production environment, e.g. connection strings. This can be handled from the Azure Portal but then the config is not versioned under source control. Instead we just could create a XDT File called Web.Prod.config which contains all the settings for the production. In order to perform the Web.config transform during the deployment, we need to call msbuild with the following parameter: /p:PublishProfile=Prod;VisualStudioVersion=12.0. In the generated script the msbuild looks like this:

:: 2. Build to the temporary path
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (  
  call :ExecuteCmd "%MSBUILD_PATH%"
      "%DEPLOYMENT_SOURCE%\path\to\Website.csproj"
      /nologo /verbosity:m /t:Build
      /t:pipelinePreDeployCopyAllFilesToOneFolder
      /p:_PackageTempDir="%DEPLOYMENT_TEMP%";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release
      /p:SolutionDir="%DEPLOYMENT_SOURCE%\.\\"
      %SCM_BUILD_ARGS%
) ELSE (
  call :ExecuteCmd "%MSBUILD_PATH%"
      "%DEPLOYMENT_SOURCE%\path\to\Website.csproj"
      /nologo /verbosity:m /t:Build
      /p:AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release
      /p:SolutionDir="%DEPLOYMENT_SOURCE%\.\\"
      %SCM_BUILD_ARGS%
)

You can see that MSBuild is called with different parameters in case the deployment happens directly in the web root or if it happens in a temp directory which is then copied to the web root. Basically we need to add our parameters to the SCM_BUILD_ARGS variable. To do this add the following line after :: 2. Build to the temporary path:

SET SCM_BUILD_ARGS="%SCM_BUILD_ARGS% /p:PublishProfile=Prod;VisualStudioVersion=12.0"

So now when the next deployment happens the Web.Prod.Config file will be transformed to the Web.config file.

Summary

In this post I only showed an example what could be customized during the deployment pipeline. However with a custom deployment script you can just do anything you would like to do during the deployment.

comments powered by Disqus