Infrastructure as Code Before Terraform: Azure ARM Templates for DBAs

Terraform wasn't released until 2014. Ansible was around but Windows-focused Azure automation wasn't its strength. In 2013, if you wanted repeatable, version-controlled Azure infrastructure, the native answer was Azure Resource Manager templates — JSON documents that described the infrastructure you wanted and let Azure figure out how to create or update it. The concept was right, even if the tooling was rough. This is the story of adopting IaC principles before "infrastructure as code" was a common phrase in the DBA community.

The Problem ARM Templates Solved

By mid-2013, I was managing Azure infrastructure for multiple clients. VMs, virtual networks, storage accounts, NSGs — all created through the Azure Management Portal, all documented in a Word doc or a Visio diagram, none of it version-controlled or reproducible without clicking through the same wizard sequence again.

When something changed — a new VM added, a NSG rule modified, a storage account moved to a different region — the documentation became stale. The next person (or future me) looking at the Azure subscription couldn't tell what the intended state was versus what had accumulated through one-off changes.

ARM templates addressed this by treating infrastructure as data: you described what you wanted in a JSON file, stored that file in source control, and applied it to create or update the infrastructure. The template was the authoritative description of the environment. The portal was for viewing, not for making changes.

A Minimal ARM Template for a SQL Server VM

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "vmName": { "type": "string" },
    "adminUsername": { "type": "string" },
    "adminPassword": { "type": "securestring" },
    "vmSize": { "type": "string", "defaultValue": "Standard_DS3" }
  },
  "resources": [
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2015-06-15",
      "name": "[parameters('vmName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "hardwareProfile": { "vmSize": "[parameters('vmSize')]" },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftSQLServer",
            "offer": "SQL2012SP2-WS2012R2",
            "sku": "Standard",
            "version": "latest"
          },
          "dataDisks": [
            {
              "lun": 0,
              "diskSizeGB": 128,
              "createOption": "Empty",
              "name": "[concat(parameters('vmName'), '-datadisk')]"
            }
          ]
        }
      }
    }
  ]
}

This is simplified — a real template also defined the virtual network, NIC, NSG, and public IP. But the structure illustrates the model: parameters for the variable parts, resource definitions for the infrastructure components, and relationships between them expressed as template function references rather than hardcoded values.

The Version Control Discipline

The template by itself wasn't enough — it needed to be in source control with a meaningful commit history. The discipline I applied:

  • Every infrastructure change happened through a template change, not through the portal
  • Template changes were committed with a description of why the change was made
  • The environment name (dev/staging/prod) was a parameter, so the same template deployed all three environments with different parameter files
  • Parameter files for dev and staging lived in source control; production parameter files lived in a password manager and were passed at deploy time, never stored in source control

What This Changed About the DBA Role

DBAs who learned ARM templates in 2013 were ahead of the curve in a skill that became standard practice. The infrastructure-as-code model changed what it meant to "know" an environment: instead of knowing what was in the portal, you knew what was in the template. The template was testable, diffable, and could be applied to a new environment with a single command.

The mental model shift — from "I configure servers" to "I maintain the desired state description of servers" — is the foundation of everything that came after: Terraform, Ansible, Pulumi. The tool names changed. The concept didn't.

If you're still making Azure changes through the portal in 2013 and documenting them in a spreadsheet, this is the right time to change that habit. Start with one environment. Get one template into source control. The rest follows naturally. As always, I'm here to help.

Read more