You surely have heard about DevOps… Who hasn’t? ? You’re even here! But have you heard about Infrastructure as Code (IaC)? It’s on everybody’s lips these days.
According to Wikipedia, Infrastructure as Code is the process of managing and provisioning computer data centers through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools. Both physical equipment such as bare-metal servers as well as virtual machines and associated configuration resources are called “infrastructure”, although they have nothing to do with actual infrastructure. The definitions may be in a version control system. It can use either scripts or declarative definitions, rather than manual processes, but the term is more often used to promote declarative approaches.
But what does that mean when your company aims to achieve DevOps practices using Microsoft Tools and Azure in the “real world”.
Being a DevOps company since 2006, we recently had the opportunity, here at Emyode, to fully automate IaC to the best of our knowledge.
Let the expert decides what’s good and what’s best for the application.
- You know the basics of ARM templates. Meaning, what’s the general concept of the JSON structure and different object types.
- You have access to an Azure Subscription and can create resources in it.
- You have a VSTS instance configured with your Azure subscription linked (as an Azure Resource Management in the Services configuration).
- You have basic knowledge on how to use and manage VSTS Build and Release management.
- You’re using the new revamped UI of VSTS (which can be acknowledged by accepting to switch in the notifications of VSTS, you can return to the old version at any time).
How to design your template
- From the portal (Automation tab)
- From VS2017 (dialog boiler plate – Visual Studio Templates)
- From community template
- Visual Studio Templates (WebApp): This template gives you a bit of a head start with a few parameters already typed for you as well as the basic skeleton for the WebApp. This template also includes AppInsight components, be sure to remove them if you don’t plan on using them.
- Before you add any other resources, be sure to name the existing parameters according to your need. It will be less trouble if you have to use those parameters in new resources.
- Each parameter that will be a password or token needs to be defined as a “securestring”.
- Assuming you have an existing WebApp, you should add every configurable settings (ie: web.config) as a parameter given that you would want it editable (or as I like to call it, “devops-able”, throughout any given deployment.
“allowedValues”: [ “dev”, “qa”, “uat”, “staging”, “prod” ],
“minLength”: 1 }
- At Emyode, we put in place a simple, but straight forward naming convention to help define and maintain the different Azure services we create. For that reason, in the template, we are implementing different variables that will concatenate the name of the different services depending on the environment it is dedicated for. So deploying for a QA environment would concatenate something like “fooqawebapp”.
"FooWebAppName": "[concat('Foo', parameters('Environment'), 'webapp')]"} […]
- Since we are going to deploy a webapp, among other things, you will need to add a Web Deploy resource. You can right click the resource node and add it using the wizard. The end result should look something like that within your WebApp node.
"packageUri": "[concat(parameters('_artifactsLocation'), '/', parameters('WebDeployWebsitePackageFolder'), '/', parameters('WebDeployWebsitePackageFileName'), parameters('_artifactsLocationSasToken'))]",
"ConnectionString": "[concat('Server=tcp:', variables('sqlserverName'), '.database.windows.net,1433;Initial Catalog=', variables('databaseName'), ';Persist Security Info=False;User ID=', parameters('administratorLogin'), ';Password=', parameters('administratorLoginPassword'), ';MultipleActiveResultSets=False;Encrypt=True;
"IIS Web Application Name": "[variables('webSiteName')]"
- Artifacts config (created when you added the Web Deploy resource) : In order to be able to publish your application to Azure and push your IaC content to it, you will need to create a new storage space in its own resource group. This typically refers to an Azure Storage. This would preferably exist before you start publishing any release.
- AppSettings: In the real world, we all have specific settings we have for any given applications. Most of the time they will be different for specific environments. Thus you should create at that point those in the definition of your webapp.
- ARM Template parameter file: Now this is where you should decide which strategy you want to go for: using a template parameter file and/or override the template parameters later in the process during the Release management process. The idea of having multiple JSON parameters for each environment is probably easier to make it “devops-able”. But sometimes having the ability for certain reasons to override those parameters through the UI is surely handy.
- Racing condition: It’s very important to declare all the properties of your component in relation inside its definition. As you run into racing conditions – refer to this article. It’s something very difficult to debug as sometimes your deployment will succeed, sometimes not, and it’s most of the time a very weird error, totally unrelated.
As far as the build goes, no matter you’re using TFS or GIT as a source control, it doesn’t matter. What you need to ensure is that depending of your branching strategy you will want to grab the correct ARM Template. For the purpose of this article we will read the ARM template from the generated artifacts. But you could decide to add a step where they are copied to any given structure of your choice by adding the task to copy the files.
Config release management
Since we used a TFS build for our example, Build should be set as the source type. Then the other 2 settings are really based on your project name and build definition name. For the purpose of our example, we activated a continuous deployment trigger to take advantage, when continuously deploying, of any change that might be done.
Now this is the part where there is a lot to discuss!
Some companies will choose to have fixed scheduled releases, others will have continuously deploying with approvals and/or many other possible combinations. This is a very important decision to make as this is part of your whole quality process with your software delivery. This should be taken very seriously and thought through thoroughly, because we all like quality software, don’t we? ?
Depending on your company strategy, it would be very common at the very least to have a Development, QA, UAT and Production Environment.
No matter how many you have, the recipe doesn’t change whatever environment you work with, meaning we’re going to go through one same specific scenario. But depending on your situations and variables, it’s easily adjustable.
For the Dev Environment, since it’s the first “gate” for quality control, everything is mostly pushed through as is (obviously there would probably have been automated unit testing during the build process and these kinds of automated checks). The Triggers are set to be after a release, there is no pre-deployment approvers.
For the post-deployment, at that point, a team lead or lead developer could check if everything runs correctly in the environment and approve the release, which would need to be configured. For the purpose of this article, we left it to Automatic.
Now this is where it gets really interesting for the environment part. For the other subsequent environment (or parallel) you can set different pre- and post- deployment conditions, approval and so on. This all depends on your company strategy.
Tasks Configuration for the environment
For the purpose of this walk through, we will be adding 2 steps:
- Azure blob copy: to copy the artifacts in the cloud in the previously configured storage. Note that if you use version 2 of the next task, this task would be rendered obsolete in some cases. Output should be specified so we can use the values to get the artifacts (binaries) in subsequent tasks.
- Azure Deployment (Create or Update): for the purpose of this article, we went for always creating or updating a resource group. This isn’t necessarily the only way to go. As you could decide in certain cases to use a DevTestLab, for example, to deploy specific components and destroy it after. If you use v.2 of this task, you can choose to use a publicly available ARM Template. After you’ve selected where is located your ARM Template, you can specify if you wish to override specific template parameters. Depending on your specific enterprise strategy discussed at the beginning of this article you might have a parameter file or several other various combinations. Also note, at the time of writing this article, there is a bug in the GUI (tested with V2) that makes the override parameters dialog give you errors and will make your build fail. See this video in order to work around the problem.
TL;DR: Go to Browse dialog of the ARM template, select a node, click cancel, go back to the override dialog and the error will go away.
Phew! That’s it, you’re done !
As you can see, the tools are frankly pretty easy to use, but so flexible that it’s easy to get lost in this big DevOps world. The key here, in order to deliver quality software and have a seamless software delivery chain, is to take your time to think it through. Don’t be shy to think a bit outside the box, create environment test using a free VSTS account to test your release process.
Make baby steps. After all, being agile can apply to the implementation of your software delivery process in order to deliver quality product to your clients.
Rome wasn’t built in a day! ?