<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=521127644762074&amp;ev=PageView&amp;noscript=1">

Getting Started with Terraform and AKS: a Step-by-Step Guide to Deploying Your First Cluster

We are major advocates of using infrastructure as code to manage Kubernetes. Terraform is one tool we use to mange the entire lifecycle of Kubernetes infrastructure. Read about the benefits of using Terraform here.

This blog provides a step-by-step guide on how to get started with Terraform and Azure Kubernetes Service (AKS) by deploying your first cluster with infrastructure as code.

Prerequisites for Deploying an AKS Cluster in Terraform

If you want to follow along and create your own AKS Cluster in Terraform, follow these steps.

  • Create an Azure Account and login (there is a free account tier available).
  • Create a Subscription — and confirm that the Subscription has Owner rights

AKS screenshot

  • Install the following:

Steps to Get Started with Terraform

Create a directory for the project (for example, terraform-aks). Next, set up an ssh key pair in the directory by running this command: ssh-keygen -t rsa -f ./aks-key. Then, runaz login from the command line to log into your Azure account.

Create provider.tf

We'll now set up several Terraform files to contain the various resource configurations. Let's name the first fileprovider.tf.Create the file and add these lines of code:

provider "azurerm" {
  version = "~> 2.5.0"
  features {}

provider "azuread" {
  version = "0.9.0"

Create cluster.tf

Now, create a file called cluster.tf. This new file will include our modules for a virtual network, cluster, and node pool. Now we can add a resource group, which is something Azure requires for resources to be created in.

## Create a resource group to place resources
resource "azurerm_resource_group" "aks" {
  name     = "myakscluster"
  location = "centralus"

This code will set up the network for your AKS cluster, add this to cluster.tf as well.

## Create the virtual network for an AKS cluster
module "network" {
  source              = "git@github.com:FairwindsOps/azure-terraform-modules.git//virtual_network?ref=virtual_network-v0.6.0"
  region              = "centralus"
  resource_group_name = azurerm_resource_group.aks.name
  name                = "myakscluster"
  network_cidr_prefix = ""
  network_cidr_suffix = 10
  subnets = [{
    name       = "aks-subnet"
    cidr_block = 16

You'll notice that in thesourcefield, thenetworkmodule is being pulled from our git repo: git@github.com:FairwindsOps/azure-terraform-modules.git//virtual_network.

If you explore that repo, look under theaks_clusterdirectory; you’ll notice theaad.tf file. This module supports an Azure Active Directory integration, but we won't be using that here. You can also see all the other resources that are being created by this module. Next, add this code to the cluster.tf file for the AKS cluster itself:

## Create the AKS cluster
module "cluster" {
  source              = "git@github.com:FairwindsOps/azure-terraform-modules.git//aks_cluster?ref=aks_cluster-v0.8.0"
  region              = "centralus"
  cluster_name        = "myakscluster"
  kubernetes_version  = "1.16.10"
  resource_group_name = azurerm_resource_group.aks.name
  node_subnet_id      = module.network.subnet_ids[0] # use the subnet from the module above
  network_plugin      = "azure"
  network_policy      = "calico"
  public_ssh_key_path = "aks-key.pub"

Note: This sample code uses Kubernetes 1.16.10. Check the AKS release notes to confirm the latest supported version.

Note that certain values, such asmodule.network.subnet_ids[``0``],are referenced from thenetworkmodule. This feature of Terraform enables you to set values in one module or resource and using them in others. Lastly, add this code tocluster.tfto set up the node pool that will contain the AKS worker nodes:

## Create the node pool
module "node_pool" {
  source         = "git@github.com:FairwindsOps/azure-terraform-modules.git//aks_node_pool?ref=aks_node_pool-v0.4.0"
  name           = "myakspool"
  kubernetes_version  = "1.16.10"
  aks_cluster_id = module.cluster.id
  node_subnet_id = module.network.subnet_ids[0]

Note: Again, this sample code uses Kubernetes 1.16.10. Check AKS release notes to confirm the latest supported version.

That’s it! Your Terraform files are all ready to go.

Initialize Terraform

The next step is to initialize Terraform by runningterraform init.Terraform will generate a directory named.terraformand download each module source declared incluster.tf.

Initialization pulls in any providers required by these modules. In this example, it will download thegoogleprovider. If configured, Terraform will also configure thebackendfor storing the state file.

terraform init
Initializing modules...
Downloading git@github.com:FairwindsOps/azure-terraform-modules.git for cluster...
- cluster in .terraform/modules/cluster/aks_cluster
Downloading git@github.com:FairwindsOps/azure-terraform-modules.git for network...
- network in .terraform/modules/network/virtual_network
Downloading git@github.com:hashicorp/terraform-cidr-subnets.git?ref=v1.0.0 for network.subnet_addrs...
- network.subnet_addrs in .terraform/modules/network.subnet_addrs
Downloading git@github.com:FairwindsOps/azure-terraform-modules.git for node_pool...
- node_pool in .terraform/modules/node_pool/aks_node_pool

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "azurerm" (hashicorp/azurerm) 2.5.0...
- Downloading plugin for provider "azuread" (hashicorp/azuread) 0.9.0...
- Downloading plugin for provider "kubernetes" (hashicorp/kubernetes) 1.11.3...
- Downloading plugin for provider "null" (hashicorp/null) 2.1.2...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.kubernetes: version = "~> 1.11"
* provider.null: version = "~> 2.1"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Run terraform plan

Once you successfully initialize Terraform, you'll be able to runterraform plan.It's always a good idea to runterraform planand review the output before allowing Terraform to make any changes.

terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

module.cluster.data.azurerm_subscription.current: Refreshing state...


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.aks will be created
  + resource "azurerm_resource_group" "aks" {
      + id       = (known after apply)
      + location = "centralus"
      + name     = "myakscluster"

  # module.cluster.azurerm_kubernetes_cluster.cluster will be created
  + resource "azurerm_kubernetes_cluster" "cluster" {
      + dns_prefix            = "myakscluster"
      + fqdn                  = (known after apply)
      + id                    = (known after apply)
      + kube_admin_config     = (known after apply)
      + kube_admin_config_raw = (sensitive value)
      + kube_config           = (known after apply)
      + kube_config_raw       = (sensitive value)
      + kubernetes_version    = "1.16.9"
      + location              = "centralus"
      + name                  = "myakscluster"
      + node_resource_group   = (known after apply)
      + private_fqdn          = (known after apply)
      + resource_group_name   = "myakscluster"
      + tags                  = {
          + "cluster-name"  = "myakscluster"
          + "created-by"    = "Terraform"
          + "module-source" = "github.com/FairwindsOps/azure-terraform-modules/aks_cluster"

      + addon_profile {
          + aci_connector_linux {
              + enabled = false

          + azure_policy {
              + enabled = false

          + http_application_routing {
              + enabled                            = false
              + http_application_routing_zone_name = (known after apply)

          + kube_dashboard {
              + enabled = false

      + default_node_pool {
          + availability_zones    = [
              + "1",
              + "2",
              + "3",
          + enable_auto_scaling   = true
          + enable_node_public_ip = false
          + max_count             = 10
          + max_pods              = 110
          + min_count             = 1
          + name                  = "default"
          + node_count            = 1
          + os_disk_size_gb       = 50
          + type                  = "VirtualMachineScaleSets"
          + vm_size               = "Standard_D2_v2"
          + vnet_subnet_id        = (known after apply)
Plan: 4 to add, 0 to change, 0 to destroy.

Note: this snippet has been been edited to cut down on the size of this article.

As shown in the example above, Terraform will take action to add our four AKS resources. When applied, Terraform will create our network, subnetwork (for pods and services), AKS cluster, and node pool.

Run terraform apply

After the plan is validated, apply the changes by runningterraform apply.For one last validation step, Terraform will output the plan again and prompt for confirmation before applying. This step takes around 10 minutes to complete. To interact with your cluster, run this command in your terminal.

az aks get-credentials --resource-group myakscluster --name myakscluster --admin

Then you should be able tokubectl get nodesand you'll see two worker nodes from your cluster!

kubectl get nodes
NAME                                STATUS   ROLES   AGE     VERSION
aks-default-14693408-vmss000000     Ready    agent   8m24s   v1.16.9
aks-myakspool-14693408-vmss000000   Ready    agent   4m31s   v1.16.9

Congratulations, you’ve successfully deployed a Kubernetes AKS cluster using Terraform! You can now begin deploying your applications to Kubernetes.


Free Download: A Platform Engineers Guide to Kubernetes

This post was originally published on July 14, 2020 and has been updated.