NashTech Blog

πŸš€ Deploy Azure Kubernetes Service (AKS) and Azure Container Registry (ACR) Using Terraform

Table of Contents

1. Introduction

In this article, we’ll explore how to automate the deployment of Azure Kubernetes Service (AKS) β€” Microsoft Azure’s managed Kubernetes solution β€” along with two Azure Container Registries (ACR) for backend and frontend services.

By using Terraform, you can define all your infrastructure as code, making it easy to reuse, scale, and maintain across different environments (dev, staging, production).

This post will detail how to use Terraform to fully automate the deployment of an AKS cluster and two separate ACR instances for Backend and Frontend services, and configure the necessary access permissions.

2. Project Structure

Before we start coding, let’s look at the basic structure of our Terraform project.
This helps us understand where each configuration file fits into the overall setup.

infra/
└── terraform/
    β”œβ”€β”€ main.tf
    β”œβ”€β”€ outputs.tf
    β”œβ”€β”€ provider.tf
    β”œβ”€β”€ variables.tf
    β”œβ”€β”€ terraform.tfvars
    └── README.md

πŸ“„ provider.tf
This file defines the Azure provider and specifies the required Terraform version:

provider "azurerm" {
  features {}
  skip_provider_registration = true
}

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "3.62.1"
    }
  }
}

3. Defining Configuration Variables

Here we declare all parameters that make our Terraform configuration reusable across environments.
In variables.tf, we declare all configurable parameters for our deployment:

variable "resource_group_name" {
  type        = string
  description = "RG name in Azure"
}

variable "location" {
  type        = string
  description = "Resources location in Azure"
}

variable "cluster_name" {
  type        = string
  description = "AKS name in Azure"
}

variable "kubernetes_version" {
  type        = string
  description = "Kubernetes version"
}

variable "system_node_count" {
  type        = number
  description = "Number of AKS worker nodes"
}

variable "acr_backend_name" {
  type        = string
  description = "ACR Backend name"
}

variable "acr_frontend_name" {
  type        = string
  description = "ACR Frontend name"
}

πŸ“„ terraform.tfvars
Here we define actual values for those variables:

# Name of the existing Azure Resource Group where all resources will be deployed
# This resource group must already exist in your Azure subscription.
# Typically created manually beforehand (via Azure Portal or CLI).
# Example: az group create --name tuannguyen --location SoutheastAsia
resource_group_name = "tuannguyen"

# Azure region to deploy resources (example: EastUS, WestEurope, SoutheastAsia)
# Must match the location of the existing Resource Group above.
# Used when creating AKS, ACR, and other Azure resources.
location = "SoutheastAsia"

# Name for your Azure Kubernetes Service (AKS) cluster
# Terraform will create this AKS cluster during 'terraform apply'.
# You can customize this name, but keep it unique per subscription.
cluster_name = "msa-aks-cluster"

# Version of Kubernetes to use (check available versions via: az aks get-versions)
# This is a pinned version to ensure consistent cluster behavior across environments.
# It can be updated later if you need a newer AKS version.
kubernetes_version = "1.30.6"

# Number of worker nodes in your AKS cluster
# Terraform will create a node pool with this count during provisioning.
# Adjust depending on workload size and cost.
system_node_count = 2

# Name of the Azure Container Registry (ACR) for backend services
# Terraform will create this ACR in the same region.
# You can later push backend images (e.g., Node.js, Java, etc.) here.
acr_backend_name = "msabackend1"

# Name of the Azure Container Registry (ACR) for frontend services
# Terraform will create this ACR as well, typically used to store frontend (React/Angular) images.
acr_frontend_name = "msafrontend1"

4. Creating Azure Resources with Terraform

All main resources are declared in the main.tf file.

4.1 Get Existing Resource Group

We reference an existing Azure Resource Group to deploy our resources inside it.

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

4.2 Create Two Azure Container Registries (ACR)

Next, we create two separate Azure Container Registries β€” one for backend and one for frontend images.

resource "azurerm_container_registry" "acr_backend" {
  name                = var.acr_backend_name
  resource_group_name = data.azurerm_resource_group.aks-rg.name
  location            = var.location
  sku                 = "Standard"
  admin_enabled       = false
}

resource "azurerm_container_registry" "acr_frontend" {
  name                = var.acr_frontend_name
  resource_group_name = data.azurerm_resource_group.aks-rg.name
  location            = var.location
  sku                 = "Standard"
  admin_enabled       = false
}

4.3 Deploy Azure Kubernetes Service (AKS)

Now we define our AKS cluster, including the node pool and identity configuration.

resource "azurerm_kubernetes_cluster" "aks" {
  name                = var.cluster_name
  kubernetes_version  = var.kubernetes_version
  location            = var.location
  resource_group_name = data.azurerm_resource_group.aks-rg.name
  dns_prefix          = var.cluster_name

  default_node_pool {
    name                = "system"
    node_count          = var.system_node_count
    vm_size             = "Standard_DS2_v2"
    type                = "VirtualMachineScaleSets"
    zones               = [1, 2, 3]
    enable_auto_scaling = false
  }

  identity {
    type = "SystemAssigned"
  }

  network_profile {
    load_balancer_sku = "standard"
    network_plugin    = "kubenet"
  }
}

4.4 Grant AKS Access to ACR

To allow AKS to pull container images from both ACRs, we assign the AcrPull role to the AKS kubelet identity:

resource "azurerm_role_assignment" "role_acrpull_backend" {
  scope                            = azurerm_container_registry.acr_backend.id
  role_definition_name             = "AcrPull"
  principal_id                     = azurerm_kubernetes_cluster.aks.kubelet_identity.0.object_id
  skip_service_principal_aad_check = true
}

resource "azurerm_role_assignment" "role_acrpull_frontend" {
  scope                            = azurerm_container_registry.acr_frontend.id
  role_definition_name             = "AcrPull"
  principal_id                     = azurerm_kubernetes_cluster.aks.kubelet_identity.0.object_id
  skip_service_principal_aad_check = true
}

4.5 Save the Kubernetes Config File

Terraform will automatically export the AKS cluster configuration into a local kubeconfig file, so you can connect with kubectl.

resource "local_file" "kubeconfig" {
  depends_on = [azurerm_kubernetes_cluster.aks]
  filename   = "kubeconfig"
  content    = azurerm_kubernetes_cluster.aks.kube_config_raw
}

5. Outputs

The outputs.tf file prints important information after the deployment:

output "aks_id" {
  value = azurerm_kubernetes_cluster.aks.id
}

output "aks_fqdn" {
  value = azurerm_kubernetes_cluster.aks.fqdn
}

output "acr_backend_login_server" {
  value = azurerm_container_registry.acr_backend.login_server
}

output "acr_frontend_login_server" {
  value = azurerm_container_registry.acr_frontend.login_server
}

6. Authenticate with Your Azure Account

Before running Terraform, authenticate with your Azure subscription so Terraform can create resources in the correct environment.

Using Azure CLI (Recommended for local development)

# Authenticate with Azure
az login
az account show

Terraform will automatically reuse these credentials when you run:

terraform apply

7. Initialize and Apply Terraform

Run the following commands to deploy your resources:

terraform init
terraform plan
terraform apply -auto-approve

After the process completes, Terraform will output your AKS and ACR information and create the kubeconfig file.

8. Connect to the AKS Cluster

Use the kubeconfig file to access your cluster:

export KUBECONFIG=./kubeconfig
kubectl get nodes

You should now see your AKS worker nodes listed.

9. Conclusion

βœ… Terraform allows you to automate Azure infrastructure in a reproducible and scalable way.
βœ… Combining AKS + ACR provides a powerful foundation for modern CI/CD pipelines.
βœ… You can easily extend this setup by adding Application Gateway, Key Vault, or integrating with Azure DevOps / Jenkins.

10. Reference

For a complete working example, check out the GitHub repository below:
πŸ”— https://github.com/nashtech-tuannguyenhuu1/SD4994_azure_infrastructure

Picture of tuannguyenhuu1

tuannguyenhuu1

Leave a Comment

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

Suggested Article

Scroll to Top