1. Azure Provider 配置与认证
一句话总结: azurerm Provider 通过 subscription_id、tenant_id 与认证链完成初始化,生产推荐用 Managed Identity 或 Service Principal,密钥从环境变量注入而非硬编码。
Azure 资源的逻辑容器是订阅(Subscription),订阅之下再按资源组(Resource Group)组织。动手前先把订阅、租户与 Provider 版本固定下来,后续所有资源都挂在这三层之上。
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
subscription_id = var.subscription_id
tenant_id = var.tenant_id
}
1.1 认证方式的取舍
| 方式 | 配置途径 | 适用场景 |
|---|---|---|
| 环境变量 | ARM_CLIENT_ID / ARM_CLIENT_SECRET | CI 注入、本地开发 |
| Service Principal | client_id + client_secret | 团队统一身份、跨租户 |
| Managed Identity | 运行在 Azure 上的资源自动获取 | 云端 Runner、AKS 内运行 |
| Azure CLI | az login 后 SDK 自动读取 | 单机日常开发 |
生产环境最推荐 Managed Identity + Service Principal 的组合:代码里不出现任何长期密钥,权限由 Azure RBAC 统一治理。用环境变量跑通第一步最简单。
export ARM_SUBSCRIPTION_ID="<subscription-id>"
export ARM_CLIENT_ID="<app-id>"
export ARM_CLIENT_SECRET="<secret>"
export ARM_TENANT_ID="<tenant-id>"
terraform plan
一句话:Provider 是「配置模板」,subscription 与 tenant 决定资源归属,认证链决定「谁在操作」。
2. 资源组与 VNet 网络设计
一句话总结: 资源组是逻辑边界,VNet 提供网络隔离,子网划分内网/外网,NSG 是子网与网卡级防火墙,组合时先规划地址空间再让资源通过引用建立依赖。
一套最小可用的 Web 架构,Azure 网络层的正确组合顺序是:资源组 → VNet → 子网 → NSG → 公共 IP → 网卡。
resource "azurerm_resource_group" "main" {
name = "rg-${var.environment}-${var.region_short}"
location = var.location
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "azurerm_virtual_network" "main" {
name = "vnet-${var.environment}"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
address_space = ["10.0.0.0/16"]
}
resource "azurerm_subnet" "web" {
name = "snet-web"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_subnet" "db" {
name = "snet-db"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.0.2.0/24"]
}
2.1 网络安全组只放行必要端口
NSG 支持子网关联与网卡关联两级,遵循最小放行原则:Web 只开放 80/443,SSH 只对办公网段开放。
resource "azurerm_network_security_group" "web" {
name = "nsg-web"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
security_rule {
name = "Allow-HTTP"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "Allow-SSH"
priority = 110
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefixes = var.office_cidrs
destination_address_prefix = "*"
}
}
resource "azurerm_subnet_network_security_group_association" "web" {
subnet_id = azurerm_subnet.web.id
network_security_group_id = azurerm_network_security_group.web.id
}
一句话:VNet 划好网段、子网分好用途、NSG 按需放行,地址空间在创建时就要预留充足,避免事后重划。
3. 计算 VM 与扩展脚本
一句话总结: Azure VM 由网卡、公共 IP、SSH 密钥与 custom_data 组合声明,镜像用 source_image_reference 指定,登录密钥优先用 SSH 公钥而非密码。
Azure 虚拟机通过 azurerm_linux_virtual_machine 声明,它依赖网卡与公共 IP,初始化逻辑写进 custom_data。
resource "azurerm_public_ip" "web" {
name = "pip-web-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_network_interface" "web" {
name = "nic-web-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.web.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.web.id
}
}
resource "azurerm_linux_virtual_machine" "web" {
name = "vm-web-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
size = "Standard_B2s"
admin_username = "ubuntu"
network_interface_ids = [azurerm_network_interface.web.id]
disable_password_authentication = true
admin_ssh_key {
username = "ubuntu"
public_key = file(var.ssh_public_key_path)
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts"
version = "latest"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
custom_data = base64encode(<<-EOT
#!/bin/bash
apt-get update -y
apt-get install -y nginx
systemctl enable nginx
EOT
)
}
一句话:VM 编排的关键是「引用不硬编码」——网卡、IP、密钥都从上游资源取,删除重建时依赖图自动按序执行。
4. 存储账户与托管磁盘
一句话总结: 存储账户承载 Blob/文件/队列等对象服务,托管磁盘随 VM 生命周期管理,两者都要开启加密并用 access tier 与生命周期规则控制成本。
存储账户是 Azure 的对象存储底座,用于静态资源、备份与日志;托管磁盘是 VM 的系统/数据盘,加密默认启用。
resource "azurerm_storage_account" "static" {
name = "st${var.environment}static"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
account_tier = "Standard"
account_replication_type = "GRS"
min_tls_version = "TLS1_2"
allow_blob_public_access = false
blob_properties {
versioning_enabled = true
}
}
resource "azurerm_storage_container" "assets" {
name = "assets"
storage_account_name = azurerm_storage_account.static.name
container_access_type = "private"
}
一句话:存储是「内容与 IaC 解耦」的地方——桶与容器的生命周期由 Terraform 管理,具体对象由应用或流水线写入。
5. AKS 集群编排
一句话总结: AKS 用 azurerm_kubernetes_cluster 声明控制面与节点池,身份用 system_assigned_identity,网络用 kubenet 或 Azure CNI,kubeconfig 通过 data source 安全获取。
AKS 是 Azure 的托管 Kubernetes,Terraform 只负责声明集群与节点池,控制面由微软托管。
resource "azurerm_kubernetes_cluster" "aks" {
name = "aks-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
dns_prefix = "aks${var.environment}"
default_node_pool {
name = "default"
node_count = 3
vm_size = "Standard_D2s_v3"
}
identity {
type = "SystemAssigned"
}
network_profile {
network_plugin = "azure"
network_policy = "calico"
}
tags = { Environment = var.environment }
}
5.1 节点池与升级
工作负载差异大时拆成多个节点池,系统池跑平台组件,用户池跑业务,并设置 autoscaling 让节点数随负载伸缩。
resource "azurerm_kubernetes_cluster_node_pool" "user" {
name = "user"
kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id
vm_size = "Standard_D4s_v3"
enable_auto_scaling = true
node_count_min = 2
node_count_max = 8
node_labels = {
role = "workload"
}
}
获取 kubeconfig 用 data source,并把内容标为敏感,避免输出到日志。
data "azurerm_kubernetes_cluster" "aks" {
name = azurerm_kubernetes_cluster.aks.name
resource_group_name = azurerm_resource_group.main.name
}
output "kubeconfig" {
value = data.azurerm_kubernetes_cluster.aks.kube_config_raw
sensitive = true
}
一句话:AKS 是「托管控制面 + 自管节点池」的组合,版本升级、网络插件、节点池隔离在创建时就要定好。
6. RBAC 与 IAM 最小权限
一句话总结: Azure 权限体系以 RBAC 为核心,用角色分配(role_assignment)把最小权限授予身份,先 Scope 到资源组或资源,再按需扩展。
RBAC 三要素是「谁(主体)→ 对什么(作用域)→ 能做什么(角色)」。Terraform 里分别对应 principal_id、scope 与 role_definition_name。
data "azurerm_client_config" "current" {}
resource "azurerm_role_assignment" "aks_storage" {
scope = azurerm_storage_account.static.id
role_definition_name = "Storage Blob Data Reader"
principal_id = azurerm_kubernetes_cluster.aks.identity[0].principal_id
}
resource "azurerm_role_assignment" "ops_contributor" {
scope = azurerm_resource_group.main.id
role_definition_name = "Contributor"
principal_id = data.azurerm_client_config.current.object_id
}
一句话:RBAC 最小权限用「角色 + 作用域 + 主体」三要素表达,先给最小动作集,审计发现越权再逐步收紧。
7. 成本治理与预算
一句话总结: 成本治理靠「标签打底 + 预算告警 + 按需关闭」三件套,Terraform 用 tags、budget 与 schedule 资源把成本策略固化成代码。
云成本失控多半是「忘了关」与「没人看」。用统一标签标记环境与成本中心,再挂预算告警,达到阈值自动通知。
resource "azurerm_consumption_budget_resource_group" "monthly" {
name = "budget-rg-${var.environment}"
resource_group_id = azurerm_resource_group.main.id
amount = 5000
time_grain = "Monthly"
time_period {
start_date = "2026-10-01T00:00:00Z"
}
notification {
enabled = true
threshold = 80
operator = "GreaterThan"
contact_emails = [var.budget_owner_email]
}
}
7.1 标签与资源规划
所有资源统一补 cost_center 与 environment 标签,云账单按标签聚合,成本归属一目了然。开发环境还可以定时关机。
locals {
common_tags = {
Environment = var.environment
CostCenter = var.cost_center
ManagedBy = "terraform"
}
}
一句话:成本治理不是「事后看账单」,而是把预算、标签、关机策略写进 IaC,让平台在创建资源的那一刻就带上成本纪律。
8. 总结
一套真实可用的 Azure 基础设施,核心是把资源组、网络、计算、存储、容器、权限、成本七类资源按「引用组合」的方式组织起来:
| 环节 | 要点 |
|---|---|
| Provider | subscription/tenant + 认证链 + features 块 |
| 资源组 | 逻辑边界,统一标签承载成本归属 |
| 网络 | VNet/子网/NSG 引用组合,地址空间预留充足 |
| 计算 | VM + custom_data,SSH 公钥而非密码 |
| 存储 | 存储账户 + 生命周期规则,默认加密 |
| 容器 | AKS + 节点池自动伸缩,kubeconfig 敏感输出 |
| 权限 | RBAC 角色分配,作用域限定到资源组/资源 |
| 成本 | 标签 + 预算告警 + 定时关机固化成代码 |
一句话收尾:Azure 实战的关键不是「创建资源」,而是「编排资源之间的引用关系与权限边界」。把地址空间规划、RBAC 作用域、成本预算这三件事做对,这套模板就能在 dev/staging/prod 之间稳定复制。下一篇「GCP 基础设施实战」将把同一套思路搬到 Google Cloud,对照两种云的编排差异。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。