CICD Pipeline with Azure Stack – Part 1

This is the first post in a series of getting a CICD pipeline working with Azure Stack.  You can read part 2 here, part 3 here, and part 4 here..  I will add links to additional posts as they are created.

There are a few things that have been coming up a lot lately at work that I would like to dive into some more to get a better understanding.  The first is Infrastructure as Code (IaC).  I’ve started doing my fair share of this in both Azure and AWS, but I feel like I’m just starting to truly get my head around the best practices and patterns to use when deploying IaC.  The next trend is a move towards continuous integration and continuous deployment, CICD.  How can I take the principles of a CICD pipeline and apply them to the IaC work I’ve been doing?  Finally, there is the hybrid cloud element that is coming with Azure Stack.  Unless you’ve been living under a rock, you’ve probably heard about Azure Stack.  If not, here are a couple resources to get you started.  I wanted to put all of those items together and build out a project that uses them.

The goals of my project are straightforward.

  1. Set up a CICD pipeline solution that can operate against both Azure and Azure Stack
  2. Create an IaC deployment that can be deployed on both Azure and Azure Stack
  3. Include built in unit tests and functional test for deployment of IaC
  4. Document the process and pitfalls

The first step is to pick a code repository and build server that will work with Azure Stack.  I’ve used Visual Studio Team Services to deploy from Visual Studio to Azure, so it seemed like a good fit for Azure Stack.  However, the Azure Stack POC doesn’t have a publicly exposed front-end that VSTS could interact with, so I need to go with something on premise.  I’ve decided on Team Foundation Server 2015 deployed on a VM in Azure Stack.  TFS will be both my build sever and my code repository,  Since I’m deploying to Azure Stack, I figured why not use an ARM template to automate as much of the deployment as possible?  I’ve done just that by first developing the template against Azure and then adding Azure Stack compatibility based off the Azure Stack quickstart templates.  I have created the template in such a way that it can be deployed to either environment.

Here is the template I developed. It deploys a single Windows 2012R2 VM in Standard_A2 size with a 100GB data disk.  I expose RDP and TCP port 8080 for the TFS website.  The custom script extension calls a PowerShell script that prepares the data disk, then it installs TFS 2015, Visual Studio Community 2015, and a Build agent.  When the deployment is complete, I have a working TFS 2015 server with the ability to create a project that deploys to Azure.

Within the template I have created a parameter called DeployLocation as such:


"DeployLocation": {
"type": "string",
"defaultValue": "Azure",
"allowedValues": [ "Azure", "AzureStack" ],
"metadata": {
"description": "Deploy to Azure or AzureStack"
}
}

The idea is that setting this parameter will automatically change components of the template to match what is available in Azure Stack.  For instance, there is only Standard_LRS storage in Azure Stack, so I can lock the storage account type down to that.  How do I do this?  In the variables section I define two variables:


"DeployAzure": {
"apiVersion": "2015-06-15"
},
"DeployAzureStack": {
"apiVersion": "2015-05-01-preview"
}

Each variable defines a set of values to be used in the rest of the template.  In this case I have only defined which API setting to use, but I can also define the VM sizes, storage account type, and location.  Now I need to combine the DeployLocation parameter value with the variables above.  That is done by defining a third variable.

"DeployLocation": "[variables(concat('Deploy',parameters('DeployLocation')))]"

This sets the DeployLocation variable to a concatenated value combining the string Deploy and the DeployLocation value to form either DeployAzure or DeployAzureStack.  Within the resource area I access the values within the variable like this.

"apiVersion": "[variables('DeployLocation').apiVersion]"

If you’ve taken the time to read Patterns for designing Resource Manager templates, you might recognize this from the t-shirt size examples.  So, I didn’t come up with this on my own.  It’s a powerful way to dynamically set values for your template, or pass a set of values to a linked template.

In order to install TFS 2015 and Visual Studio Community, I had to store the ISOs in Azure blob storage.  I had the blobs publicly accessible, but that’s probably not a good idea now that I am writing this post.  Instead, I plan to add a Shared Access Signature parameter and storage account URL to the template parameters so that I restrict access to myself.  I’ve set the blob container to Private for the moment.  I’ll drop a new post once the SAS and storage account parameters are in.

I’ve successfully deployed the template in Azure, and now I need to deploy it in Azure Stack and validate it is working.  Of course, my Azure Stack install died on me after the lab lost power unexpectedly.  So I’ve got an exciting weekend of reinstalling it.

3 thoughts on “CICD Pipeline with Azure Stack – Part 1

Leave a Reply

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