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