1. 课程导入
在云原生时代,Kubernetes 已经成为容器编排的事实标准,但“把 Kubernetes 跑起来”和“把 Kubernetes 交付好”是两件完全不同的事。很多团队在第一次搭建集群时,习惯用 kubeadm init 加几条手工命令,或者点开云控制台逐个勾选节点规格、网络插件和存储类。这种方式在单集群、单环境时勉强可行,一旦面对多环境(dev/staging/prod)、多集群、多区域,手工操作就会迅速演变成不可维护的“雪花集群”——每个集群的配置都略有不同,没人说得清差异从何而来,更不敢轻易重建。
这正是 Terraform 与 Kubernetes 组合要解决的核心问题。理解两者的角色分工,是整门课程的第一块基石。
一、角色定位:谁负责“造”,谁负责“用”
可以把基础设施交付分成两个层次。第一层是基础设施层:虚拟机、网络、子网、安全组、负载均衡器、托管 Kubernetes 控制面、节点池、IAM 角色、对象存储等。这些资源由云厂商 API 提供,生命周期长、创建慢、删除有风险。第二层是集群内工作负载层:Namespace、Deployment、Service、Ingress、ConfigMap、Secret、HPA、CRD 等。这些资源由 Kubernetes API 提供,生命周期短、变更频繁、与业务发布节奏强相关。
Terraform 的定位是基础设施即代码(IaC)工具,它通过 Provider 调用云厂商 API,用声明式配置描述“我要什么”,并维护一份 state 文件记录“现在有什么”。它擅长处理有向无环的资源依赖、创建顺序、幂等收敛和销毁回收。Kubernetes 的定位是集群内资源的声明式控制平面,它通过控制器循环不断把实际状态拉向期望状态,擅长处理滚动更新、自愈、扩缩容和服务发现。
因此,一个清晰的分工原则是:用 Terraform 交付“集群及其依赖的云资源”,用 Kubernetes 清单(或 Helm/Kustomize)交付“集群内的工作负载”。两者边界不是绝对的,Terraform 的 Kubernetes Provider 也能创建 Namespace 和 Deployment,但把高频变更的业务负载放进 Terraform state,会让每次发布都触发一次基础设施计划,既慢又危险。更合理的做法是让 Terraform 管“地基和框架”,让 Kubernetes 管“房间里的家具”。
二、核心价值:为什么不是“二选一”
有人会问:既然 Terraform 的 Kubernetes Provider 能创建 Deployment,为什么还要学 Kubernetes 清单?反过来,既然 Helm 能装 Ingress Controller,为什么还要 Terraform?答案在于变更频率与状态归属。
Terraform 的 state 是一份全局账本,任何一次 terraform plan 都会刷新所有被管理资源的真实状态。如果把业务 Deployment 也纳入其中,那么每次改一个镜像 tag,plan 阶段都要去查询 VPC、节点池、IAM 等大量无关资源,执行时间长、API 调用多、失败面大。更严重的是,一旦 state 损坏或锁冲突,业务发布会被基础设施流程阻塞。相反,Kubernetes 的 kubectl apply 或 Helm upgrade 只影响目标对象,控制器在集群内部完成收敛,速度快、影响面小、回滚简单。
反过来,如果用 Kubernetes 清单去创建 VPC 或托管控制面,就会遇到“鸡生蛋”问题:集群还没建好,kubectl 连不上,清单无处可施。而且云资源的创建顺序、依赖关系、删除保护,远不是 Kubernetes 控制器擅长的领域。所以两者不是竞争,而是上下游协作:Terraform 产出集群的 kubeconfig 和节点就绪状态,Kubernetes 在此基础上接管工作负载。
三、实战环境准备:把工具链先跑通
本课程后续所有实验都围绕一个可复现的最小环境展开。你不需要一开始就拥有生产级云账号,可以用本地模拟或云厂商免费额度完成大部分练习。核心工具只有四个:Terraform CLI、kubectl、一个云厂商 CLI(如 AWS CLI / gcloud / az),以及一个可用的 Kubernetes 集群(可以是托管集群,也可以是 kind/minikube 本地集群)。
先验证 Terraform 与 kubectl 是否就绪:
terraform version
# 期望输出示例:Terraform v1.7.x
kubectl version --client
# 期望输出示例:Client Version: v1.29.x
接着准备一个工作目录,并初始化 Terraform 的 Provider 缓存。下面是一个最小化的 versions.tf 示例,用于锁定 Terraform 与 Kubernetes Provider 的版本,避免不同机器上解析出不同版本导致行为差异:
terraform {
required_version = ">= 1.5.0"
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.27"
}
}
}
执行 terraform init 后,如果看到 “Terraform has been successfully initialized”,说明 Provider 已下载到 .terraform 目录。此时可以用 terraform providers 查看已安装的 Provider 及其版本,确认与预期一致。
对于 Kubernetes 侧,先用 kubectl config current-context 确认当前上下文指向你要操作的集群。如果是本地 kind 集群,典型输出类似 kind-kind;如果是云托管集群,输出会是类似 arn:aws:eks:cn-north-1:123456789012:cluster/demo 的标识。务必确认上下文正确,因为后续 Terraform 的 Kubernetes Provider 会读取同一份 kubeconfig,一旦指向错误集群,可能误删生产资源。
destroy 会真实删除资源,操作前先用 terraform plan 确认变更范围。
四、本课程的学习路径
整门课程按“环境 → 集群 → 工作负载 → 模块化 → 流水线”推进。第一阶段先跑通工具链和最小示例,理解 Provider、state、plan/apply 的基本节奏;第二阶段用 Terraform 交付网络与托管 Kubernetes 集群,掌握变量、输出、远程 state 和依赖关系;第三阶段把工作负载交给 Kubernetes 清单与 Helm,理解两者边界;第四阶段抽象可复用模块,并接入 CI/CD,实现从代码提交到集群变更的自动化闭环。
每进入一个新阶段,都建议保留一份可回滚的 state 备份,并在实验后执行 terraform destroy 清理资源,避免产生意外费用。把“计划—执行—验证—清理”变成肌肉记忆,比记住任何一条命令都重要。
现在,工具链已经清晰,边界已经划定。接下来就从第一个 Terraform 配置开始,让基础设施真正变成可版本化、可审查、可重建的代码。