Terraform/OpenTofu tạo VNet + Subnet trên Azure
🎯 Mục tiêu: Dùng Terraform (hoặc OpenTofu) tạo Resource Group, Virtual Network và Subnet trên Azure bằng vòng đời đầy đủ: init → validate → plan → apply → inspect state → destroy.
🧰 Công cụ / nền tảng: Terraform CLI ≥ 1.7 hoặc OpenTofu CLI ≥ 1.7, Azure CLI, VS Code + HashiCorp Terraform extension.
📦 Chuẩn bị:
# Cài Terraform (Windows - winget)
winget install HashiCorp.Terraform
# Hoặc cài OpenTofu (drop-in replacement)
winget install OpenTofu.OpenTofu
# Cài Azure CLI
winget install Microsoft.AzureCLI
# Đăng nhập Azure
az login
az account show # xác nhận subscription đúng
az account set --subscription "<subscription-id>"
▶️ Các bước:
# 1. Tạo thư mục project
mkdir iac-azure-vnet && cd iac-azure-vnet
# 2. Tạo providers.tf
cat > providers.tf << 'EOF'
terraform {
required_version = ">= 1.7"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
provider "azurerm" {
features {}
# Credentials từ az login (Azure CLI auth) - không cần hard-code
}
EOF
# 3. Tạo variables.tf
cat > variables.tf << 'EOF'
variable "location" {
description = "Azure region"
type = string
default = "southeastasia"
}
variable "resource_group_name" {
description = "Name of the resource group"
type = string
default = "rg-iac-lab"
}
variable "vnet_address_space" {
description = "VNet CIDR block"
type = string
default = "10.10.0.0/16"
}
variable "subnet_prefixes" {
description = "Map of subnet name to CIDR"
type = map(string)
default = {
"snet-app" = "10.10.1.0/24"
"snet-db" = "10.10.2.0/24"
}
}
EOF
# 4. Tạo main.tf
cat > main.tf << 'EOF'
resource "azurerm_resource_group" "main" {
name = var.resource_group_name
location = var.location
tags = {
Environment = "lab"
ManagedBy = "terraform"
Module = "m18-iac"
}
}
resource "azurerm_virtual_network" "main" {
name = "vnet-iac-lab"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
address_space = [var.vnet_address_space]
tags = azurerm_resource_group.main.tags
}
resource "azurerm_subnet" "subnets" {
for_each = var.subnet_prefixes
name = each.key
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [each.value]
}
EOF
# 5. Tạo outputs.tf
cat > outputs.tf << 'EOF'
output "resource_group_id" {
value = azurerm_resource_group.main.id
}
output "vnet_id" {
value = azurerm_virtual_network.main.id
}
output "subnet_ids" {
value = { for k, v in azurerm_subnet.subnets : k => v.id }
}
EOF
# 6. Vòng đời đầy đủ
terraform init # tải provider azurerm ~3.100
terraform validate # kiểm tra syntax
# Output: Success! The configuration is valid.
terraform plan -out=tfplan # preview changes
# Output: Plan: 4 to add, 0 to change, 0 to destroy.
terraform apply tfplan # tạo resources (xác nhận "yes" hoặc thêm -auto-approve)
# Output: Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
# 7. Inspect state
terraform state list
# azurerm_resource_group.main
# azurerm_virtual_network.main
# azurerm_subnet.subnets["snet-app"]
# azurerm_subnet.subnets["snet-db"]
terraform show # chi tiết từng resource
terraform output # xem output values
# 8. Verify trên Azure CLI
az network vnet list --resource-group rg-iac-lab --output table
az network vnet subnet list --resource-group rg-iac-lab --vnet-name vnet-iac-lab --output table
🖥️ Đối chiếu GUI (Portal): Azure Portal → Resource Groups → rg-iac-lab → xem VNet và 2 Subnet; tag "ManagedBy: terraform" hiển thị rõ.
✅ Kết quả mong đợi: terraform state list liệt kê 4 resources; terraform output subnet_ids trả về map JSON chứa ID của snet-app và snet-db; Portal hiển thị VNet với address space 10.10.0.0/16.
🧹 Cleanup:
terraform destroy # xóa toàn bộ resource (xác nhận "yes")
# Output: Destroy complete! Resources: 4 destroyed.