Creating Azure AKS Cluster using Terraform

October 05, 2023

aks_logo

In the world of container orchestration and cloud-native applications, Azure Kubernetes Service (AKS) stands as a powerful platform for managing and scaling containerized workloads seamlessly. To automate the deployment of your Kubernetes clusters on Microsoft Azure, Terraform emerges as the go-to tool. In this article, we will embark on a journey to explore the art of creating an Azure AKS cluster with Terraform

Link to Github code repo here

Prerequisites:

  1. Azure Subscription: You should have an active Microsoft Azure subscription. If you don't have one, you can sign up for a free trial here
  2. Terraform Installed: Ensure that Terraform is installed on your local development machine. You can download it from the official website here
  3. Azure CLI Installed: Install the Azure CLI, which is a command-line tool for managing Azure resources. You can download it from here
  4. Azure Service Principal: You'll need an Azure service principal with the appropriate permissions to create and manage resources. You can create one using the Azure CLI or Azure Portal
  5. Azure CLI Authentication: Authenticate the Azure CLI using your service principal credentials

Provider.tf

Provider.tf file in a Terraform configuration is used to define and configure the providers that Terraform should use for managing resources in a specific cloud or infrastructure platform. Providers are responsible for translating Terraform configurations into API calls and actions on the target platform

Let's create ours in a project folder with the following content:

provider "azurerm" {
  features {}
}

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
    }
  }
}
  1. Provider block specifies the Azure provider azurerm
  • features {} is an empty configuration block. In this example, no specific features are enabled or configured, but you can specify provider-specific features within this block if needed.
  1. terraform block is used to configure global settings for your Terraform configuration.
  • required_providers specifies the providers required for this configuration. We declare that the azurerm provider is required
  • source specifies that the provider should be fetched from the HashiCorp provider registry

It's a foundational part of our Terraform configuration, ensuring that Terraform knows which provider to use when creating and managing Azure resources

Main.tf

In our project folder, next step is to create a main.tf file, which serves as the foundation for our Terraform configuration. In this configuration, our initial task is to create a resource group that will house our future AKS (Azure Kubernetes Service) cluster.

resource "azurerm_resource_group" "aks-rg" {
  name     = var.resource_group_name
  location = var.location
}

Now let's set up a network configuration within an Azure resource group, defining the address space and subnet for the virtual network. In order to ensure that the network module is created after the Azure resource group is created, we would specify the depends_on attribute.

module "network" {
  source              = "Azure/network/azurerm"
  resource_group_name = azurerm_resource_group.aks-rg.name
  address_spaces      = ["10.20.0.0/16"]
  subnet_prefixes     = ["10.20.0.0/21"]
  subnet_names        = ["subnet1"]
  use_for_each = true
  depends_on = [azurerm_resource_group.aks-rg]
}

Our next step involves declaring a module to set up the AKS cluster. You can refer to the documentation link for detailed information

module "aks" {
  source  = "Azure/aks/azurerm"
  version = "7.4.0"
  
  prefix              = "dev"
  cluster_name        = var.cluster_name
  resource_group_name = azurerm_resource_group.aks-rg.name
  location            = var.location
  agents_pool_name    = "testpool"
  agents_availability_zones = [1, 2]
  agents_size         = var.vm_size
  orchestrator_version = var.orchestrator_version
  enable_auto_scaling = true
  agents_min_count = 1
  agents_max_count = 6
  agents_max_pods  = 100
  vnet_subnet_id   = module.network.vnet_subnets[0]
  network_plugin   = "azure"
  network_policy   = "calico"
  rbac_aad         = false
  private_cluster_enabled = false
  node_pools = {
    pool1 = {
      name                  = "pool1"
      vm_size               = var.vm_size
      enable_auto_scaling   = true
      node_count            = 1
      min_count             = 1
      max_count             = 5
      vnet_subnet_id        = module.network.vnet_subnets[0]
      orchestrator_version = var.orchestrator_version
      mode = "User"
    }
  }

  depends_on = [azurerm_resource_group.aks-rg, module.network]
}

Let's define couple of configuration options for the AKS cluster, including:

  • prefix: A prefix used for naming resources within the cluster.
  • cluster_name: The name of the AKS cluster, which is defined as a variable (var.cluster_name).
  • resource_group_name: Specifies the name of the Azure resource group where the cluster will be created.
  • location: Specifies the Azure region where the cluster will be deployed.
  • agents_pool_name: The name of the default agent pool.
  • agents_availability_zones: A list of Azure availability zones for the agent nodes.
  • agents_size: The size of the agent VMs.
  • orchestrator_version: The version of Kubernetes to use.
  • enable_auto_scaling: Enables auto-scaling for the agent pool.
  • agents_min_count and agents_max_count: Minimum and maximum node counts for the default agent pool.
  • agents_max_pods: Maximum pods per node in default node pool.
  • vnet_subnet_id: The ID of the virtual network subnet where the AKS cluster should be placed, referencing the subnet created in the module.network module.
  • network_plugin and network_policy: Network configuration settings.
  • rbac_aad: Specifies whether Azure Active Directory (AAD) integration is enabled.
  • private_cluster_enabled: Specifies whether the AKS cluster is private.
  • node_pools: Defines additional node pools within the AKS cluster.

Please note in order to avoid any errors orchestrator_version should be the same, or you can leave it as default - it will create lates version

Variables.tf

Here we would define all our variables:

variable "resource_group_name" {
  type        = string
  description = "RG name in Azure"
  default     = "test"
}
variable "location" {
  type        = string
  description = "Resources location in Azure"
  default     = "eastus"
}
variable "cluster_name" {
  type        = string
  description = "AKS name in Azure"
  default     = "test-aks"
}

variable "orchestrator_version" {
  type        = string
  description = "Kubernetes version"
  default     = "1.26.6"
}

variable "vm_size" {
  type        = string
  description = "Size of the agent VMs"
  default     = "Standard_DS3_v2"
}

Final Step - Deployment

In order to initialize terraform and download modules run:

`terraform init` 

You can also check which resources terraform is planning to create by running:

terraform plan

To provision resources run:

terraform apply

After terraform is applied you can connect to your AKS Cluster:

az aks get-credentials -n <YOUR_CLUSTER_NAME> -g <RESOURCE_GROUP_NAME>

You can find source code in our Github repo