Terraform 管理 ACK 集群

解读

在国内云原生面试中,阿里云容器服务 ACK(Alibaba Cloud Kubernetes)是出镜率最高的托管 K8s 产品。面试官问“如何用 Terraform 管理 ACK 集群”,并不是想听你背文档,而是考察三条线:

  1. 是否把 IaC 理念真正落地到阿里云平台,而不是“控制台点一点”;
  2. 是否能把 PHP 业务场景(高并发、弹性伸缩、低成本)映射到 ACK 的节点池、弹性伸缩组、Spot 实例等配置;
  3. 是否具备“可演进”的架构思维:灰度、多环境、多地域、GitOps、备份、费用审计。
    一句话:让你证明“我能用代码把 ACK 从 0 到 1 再到 100 地管起来,且让 PHP 团队无感接入”。

知识点

  1. 阿里云 Provider 链路与认证
    • 环境变量 ALICLOUD_ACCESS_KEY / ALICLOUD_SECRET_KEY 与 STS 临时凭证区别
    • Provider block 版本锁定策略(>=1.200.0 才支持 ACK Pro 托管版)
  2. ACK 资源拓扑
    • alicloud_cs_managed_kubernetes:托管版集群
    • alicloud_cs_kubernetes_node_pool:节点池(支持 Spot、ESS、Taints、Labels)
    • alicloud_cs_autoscaling_config:节点池级 HPA 阈值
    • alicloud_cs_autoscaling_config 与 cluster-autoscaler 组件的协同
  3. 网络与安全
    • Terway ENI vs Flannel 在 PHP 长连接场景下的性能差异
    • 白名单式安全组:只暴露 80/443/9000(PHP-FPM Status)
    • 使用 alicloud_ram_policy 给 CI 角色最小权限:cs:Describe*,cs:ScaleCluster
  4. 状态与流水线
    • 远端状态锁:OSS Backend + DynamoDB 模拟(国内用 Tablestore 锁)
    • GitLab-CI / GitHub Action 调用 terraform plan/apply 的 Role 切换
  5. PHP 业务耦合
    • 通过 ConfigMap 注入 PHP_INI_SCAN_DIR,实现不同版本 ini 热更新
    • 节点池 Label:workload=php-api,配合 nodeSelector 把 IO 密集 Pod 绑定到 ESS 按量节点,把计算密集 Pod 绑定到 Spot 节点
  6. 成本治理
    • 使用 alicloud_cs_kubernetes_node_pool 的 instance_types 多规格兜底,结合 preemptible_percentage 控制 Spot 比例
    • 通过 alicloud_bss_openapi 拉取账单,按 namespace 打标签做成本分摊
  7. 灾备与可观测
    • 使用 alicloud_cs_kubernetes_addon 一键安装 alicloud-monitor-controller、logtail、arms-prometheus
    • 跨地域备份:通过 alicloud_cs_kubernetes_backup 做 etcd 快照并转储到 OSS 跨区域复制
  8. 合规
    • 等保 2.0 要求:Master 节点强制加密盘,通过 encrypted_enable = true 开启

答案

下面给出一套可直接落地到生产环境的“最小可扩展” Terraform 结构,并穿插解释面试时要口头强调的细节。目录结构:

.
├── environments
│   ├── dev.tfvars
│   └── prod.tfvars
├── modules
│   ├── ack
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   ├── network
│   └── addons
├── main.tf
├── backend.tf
└── ci.tf
  1. 主入口 main.tf(面试时口头说明“模块化解耦,可支持多地域多 AZ”)
provider "alicloud" {
  region = var.region
  # 生产环境用 assume_role 方式,避免 AK 泄露
  assume_role = {
    role_arn = "acs:ram::${var.account_id}:role/terraform-ci"
  }
}

module "vpc" {
  source      = "./modules/network"
  region      = var.region
  vpc_cidr    = var.vpc_cidr
  cluster_name = var.cluster_name
}

module "ack" {
  source              = "./modules/ack"
  cluster_name        = var.cluster_name
  vpc_id              = module.vpc.vpc_id
  vswitch_ids         = module.vpc.vswitch_ids
  service_cidr        = var.service_cidr
  pod_cidr            = var.pod_cidr
  php_node_pool_size  = var.php_node_pool_size
  spot_percentage     = var.spot_percentage
  key_name            = var.key_name
  encrypted_enable    = true   # 等保合规
}
  1. modules/ack/main.tf(只展示核心资源,面试时要能讲出“为什么用节点池而不是手动加节点”)
resource "alicloud_cs_managed_kubernetes" "pro" {
  name                  = var.cluster_name
  cluster_spec          = "ack.pro.small"
  version               = "1.26.3-aliyun.1"
  vpc_id                = var.vpc_id
  vswitch_ids           = var.vswitch_ids
  service_discovery_types = ["CoreDNS"]
  load_balancer_spec    = "slb.s2.small"
  # 托管版默认不暴露 API Server EIP,安全
  is_enterprise_security_group = true
  encrypted_enable      = var.encrypted_enable
  # 关键:Pod 与 Service CIDR 提前规划,避免和 PHP 内部微服务冲突
  pod_cidr              = var.pod_cidr
  service_cidr          = var.service_cidr
  # 开启日志转存,方便 PHP 业务排障
  cluster_log_ttl       = 7
}

resource "alicloud_cs_kubernetes_node_pool" "php" {
  cluster_id       = alicloud_cs_managed_kubernetes.pro.id
  name             = "php-api"
  vswitch_ids      = var.vswitch_ids
  instance_types   = ["ecs.c6e.large", "ecs.c6.large"] # 多规格兜底
  system_disk_category = "cloud_essd"
  system_disk_size = 100
  key_name         = var.key_name
  # 成本优化:Spot 实例
  spot_strategy    = "SpotWithPriceLimit"
  spot_price_limit = 0.25
  # 节点池级自动伸缩
  scaling_config {
    min_size = 2
    max_size = var.php_node_pool_size
  }
  # 给 PHP-FPM 预留 CPU 绑定
  taints {
    key    = "workload"
    value  = "php"
    effect = "NoSchedule"
  }
  labels = {
    workload = "php-api"
    env      = terraform.workspace
  }
  management {
    auto_repair   = true
    auto_upgrade  = true
    surge         = 1
    max_unavailable = 0
  }
}
  1. backend.tf(面试亮点:状态锁 + 多环境)
terraform {
  backend "oss" {
    bucket = "tf-state-ack"
    prefix = "php/ack/${terraform.workspace}"
    region = "cn-shanghai"
    # 用 Tablestore 做行锁,避免并发 apply
    tablestore_endpoint = "https://tf-lock.cn-shanghai.ots.aliyuncs.com"
    tablestore_table    = "tf_lock"
  }
}
  1. ci.tf(GitLab-CI 调用示例,面试时强调“无 AK 落地”)
data "alicloud_ram_policy" "terraform_ci" {
  name = "TerraformCIPolicy"
  # 最小权限:仅 ACK 只读 + 节点池伸缩
}

resource "alicloud_ram_role" "ci" {
  name        = "terraform-ci"
  document    = jsonencode({
    Statement = [{
      Action   = "sts:AssumeRole"
      Effect   = "Allow"
      Principal = { Service = ["ci.aliyuncs.com"] }
    }]
  })
}
  1. 变量与输出(面试时主动说“我把 kubeconfig 加密输出到 SSM,PHP CD 系统通过 SDK 拉取”)
output "kubeconfig" {
  value     = alicloud_cs_managed_kubernetes.pro.kube_config
  sensitive = true
}

落地步骤(面试时按 30 秒版本口述)

  1. 准备:在 RAM 创建 terraform-ci 角色并授予最小权限,OSS 新建 tf-state-ack 桶并开启版本控制;
  2. 本地 terraform workspace new prod,terraform plan -var-file=environments/prod.tfvars;
  3. MR 合并后,GitLab-Runner 使用 OIDC 扮演 terraform-ci 角色,自动 apply;
  4. 集群就绪后,通过 alicloud_cs_kubernetes_addon 安装 arms-prometheus,PHP 应用使用社区版 fpm-exporter 暴露指标;
  5. 节点池根据 PHP 业务高峰自动伸缩,Spot 实例被回收时,Pod 优雅终止时间设为 30s,保证正在处理的请求不丢失;
  6. 每周通过 Terraform 的 -target=alicloud_cs_kubernetes_backup 做 etcd 快照并转储到 OSS,保留 30 天,满足等保审计。

拓展思考

  1. 多集群联邦:如果 PHP 业务要做单元化部署,上海+深圳双活,可用 Terraform 的 for_each 批量创建 ack 资源,并通过 ACK One 联邦统一管理;
  2. GitOps 深化:用 Terraform 只负责“基础设施层”,应用层用 ArgoCD + ApplicationSet,PHP 镜像版本变动不再走 Terraform,而是走 Git 标签;
  3. 费用闭环:通过 alicloud_bss_openapi 把每日账单写入自建 PHP 财务系统,按 namespace+label 做成本分摊,实现“业务团队自费扩容”;
  4. 安全左移:在 Terraform PR 阶段使用 Checkov 扫描,禁止公网 SLB、禁止开放 0.0.0.0/0 入站,扫描结果以 JSON 回传 GitLab,MR 合并前必须清零高危;
  5. 灾备演练:通过 Terraform 的 -replace 参数模拟整个可用区节点池故障,验证 PHP 会话中心(Redis Cluster)跨 AZ 高可用,RTO<5min;
  6. 混合云:线下 IDC 已有 PHP 老集群,可通过 Terraform 创建 ACK 注册集群,把线下 Kubelet 注册到云端,实现统一运维视角;
  7. Serverless 趋势:PHP 业务若改造成 Knative 模式,可用 Terraform 创建 ACK Serverless 集群,并配置 alicloud_cs_serverless_kubernetes,按需付费,彻底去掉节点池维护成本。