一句话总结
前两个阶段管的是"集群里跑什么",但集群本身,网络,数据库,DNS 这些底座从哪来?
基础设施即代码(IaC)把"开服务器,建网络"也变成可版本化,可复现的声明式代码--其灵魂是一个你在前面没见过的新概念:状态(State).
前置回顾
阶段二我们让应用自动,安全地跑在了 Kubernetes 集群上.但有个一直被当作前提,从没追问的问题:那个集群本身是谁创建的? 它所在的 VPC 网络,它连的云数据库,它用的域名和证书--这些"底座"如果还靠人在云厂商控制台上点鼠标创建,那我们前面建立的"可复现,可追溯"就有个手工的地基.本篇是阶段三,也是整个 CI/CD 系列的收尾:把声明式思想从"应用"贯彻到"基础设施".
问题:点控制台建出来的基础设施,没人说得清
先看没有 IaC 的团队怎么准备基础设施--业界戏称 "ClickOps"(点点运维):
需要一套生产环境:登录云控制台 → 点"创建 VPC" → 点"创建子网" → 点"创建 K8s 集群" → 点"创建数据库" → 配安全组 → 配负载均衡 → 配 DNS...几十次点击,散落在十几个控制台页面里.
三个月后,要再开一套一模一样的灾备环境:"当时那个集群的网络是怎么配的来着?" → 没人记得;"安全组开了哪些端口?" → 得一个个翻;"为什么这个参数是这个值?" → 当时点的人离职了.结果:照着记忆又点一遍,开出来一套"看起来差不多但其实不一样"的环境.
这和第 01 篇手工发布,第 05 篇手动改集群是同一个病:依赖人的记忆和手工操作,不可复现,不可追溯,无法 review,会漂移.解药也是同一个思路--把它变成声明式代码.
ClickOps 像凭记忆手工搭一座房子,每次盖出来都不太一样,且没有图纸;IaC 像先画好施工蓝图(代码),施工队照图施工--同一张图,在哪盖,盖几次,都是一模一样的房子.
IaC 是什么:用代码声明基础设施
基础设施即代码(Infrastructure as Code,IaC)的主张:把服务器,网络,数据库,DNS 等基础设施,用代码声明出来,由工具读取代码去自动创建和管理.
注意这里又是熟悉的声明式(第 05 篇)--你描述"我要什么基础设施",而不是"一步步怎么点".以 Terraform 为例,声明"一台云服务器 + 一个数据库"大致长这样:
|
|
这套代码可以进 Git,可以 review,可以在任意地方 apply 出一模一样的环境--ClickOps 的所有毛病都被治好了.但 IaC 有一个 Kubernetes 世界里不存在 的独特难题,理解它才算真正理解 IaC.
IaC 的灵魂:状态(State)
这是本篇最关键,也最容易被初学者忽略的概念.先抛出一个问题:
一个要命的问题
你 apply 创建了一台服务器.现在你把代码里那台服务器删掉,再 apply.工具怎么知道"云上那台已经存在的机器"是之前由它创建,现在该删掉的,而不是别人手工建的,不该乱动的?它怎么知道"代码里的 aws_instance.web"对应"云上那台具体的 i-0abc123 实例"?
答案是:IaC 工具维护一份 状态文件(State)--一份"我管理的代码资源 ↔ 云上真实资源"的映射账本.每次 apply,它做的其实是三方对比:
IaC 的核心循环:代码,状态,现实三方对账
|
正是这份状态,让 IaC 能算出"从现状到期望,需要增,删,改哪些资源".terraform plan 展示的就是这个 diff.
为什么 Kubernetes 不需要你管状态,Terraform 却要?
对比第 05 篇:K8s 的"期望状态"和"实际状态"都存在 etcd 里,由集群自己持续调谐--状态是 K8s 内建托管的,你无感.而 Terraform 管的是外部的云资源,云厂商不会替它记"哪些资源归这套代码管",所以 Terraform 必须自己在外部存一份状态账本.这就是 IaC 比 K8s 多出来的心智负担,也是几乎所有 IaC 事故的源头.
状态带来的两个现实难题
- 状态必须共享且加锁:状态默认是本地一个文件.但团队协作时,每个人本地一份状态会彻底打架.所以生产实践中状态要放在远程后端(如 S3 + DynamoDB 锁,Terraform Cloud),并加锁防止两人同时
apply把账本搞乱. - 状态文件含敏感信息:数据库密码等可能被明文记进状态.因此状态后端必须加密,严格管控访问--它的敏感级别等同于密钥(回想第 02,04 篇对机密的谨慎).
永远不要手工编辑状态文件
手改状态会让"账本"和"现实"错位,后续 apply 可能误删生产资源或重复创建.要调整状态有专门命令(如 terraform state mv/rm 和 import),但日常应避免直接碰它.把状态当成只能由工具读写的数据库,而不是一个可以随便改的文本文件.
三个主流工具的定位与取舍
IaC 工具不少,挑三个有代表性,思路各异的,理解它们的取舍比记语法重要.
Terraform:行业事实标准
用专门的声明式语言 HCL 描述基础设施,通过 "Provider"(插件)对接几乎所有云厂商和服务(AWS,GCP,Azure,甚至 Cloudflare,GitHub).
- 优点:生态最庞大,Provider 最全,社区资料最多;声明式,跨云通用,是事实标准
- 取舍:要学一门新语言 HCL;表达复杂逻辑(循环,条件)时 HCL 略显笨拙
关于 OpenTofu
2023 年 Terraform 改用非开源许可后,社区 fork 出了完全开源的 OpenTofu,用法与 Terraform 基本兼容.理念和机制(尤其状态)完全一致,本篇所讲对两者都适用.
Pulumi:用通用编程语言写基础设施
Pulumi 让你用 Python,TypeScript,Go 等真实编程语言来声明基础设施,而非专用 DSL.
|
- 优点:复用你已掌握的语言和工具链(IDE,测试,包管理);复杂逻辑表达自然
- 取舍:灵活性是双刃剑--能写出难以维护的"基础设施程序";生态和社区规模不及 Terraform.注意它底层同样有"状态"概念,前面讲的状态难题一个都不少.
Crossplane:把基础设施变成 K8s 资源
Crossplane 思路最特别:它让你用 Kubernetes 的方式(写 YAML,kubectl apply)来管理云基础设施.一个云数据库,在 Crossplane 里就是一个 K8s 自定义资源:
|
这带来一个杀手级优势:它复用 K8s 的控制器和 etcd 来做调谐和状态管理--于是"状态"问题自动消失了,和第 05 篇 K8s 资源一样由集群托管.更妙的是,它能被 ArgoCD 直接管理:
Crossplane = 让 GitOps 也能管基础设施
因为云资源被表达成了 K8s 资源,第 05 篇的 ArgoCD 可以像同步 Deployment 一样同步它们.于是"创建一个数据库"也变成了"改 Git → ArgoCD 自动同步"--应用和基础设施,统一在同一套 GitOps 工作流里.这正是它最吸引云原生团队的地方.代价是:需要一个 K8s 集群来运行 Crossplane 本身(先有鸡还是先有蛋--通常用一个独立的"管理集群"来解决).
| Terraform | Pulumi | Crossplane | |
|---|---|---|---|
| 怎么写 | HCL 专用语言 | Python/TS/Go 等 | K8s YAML |
| 状态在哪 | 自管(远程后端) | 自管(类似) | K8s etcd 托管,无感 |
| 持续调谐 | 否(apply 才动) | 否(up 才动) | 是(控制器持续纠偏) |
| 接 GitOps | 需额外集成 | 需额外集成 | 原生(就是 K8s 资源) |
| 最适合 | 通用,跨云,团队标准 | 偏好用代码,逻辑复杂 | 已全面 K8s 化,想统一 GitOps |
IaC 与 GitOps:把整条链路彻底打通
IaC 让基础设施变成了代码,自然该和阶段二的工作流合流.两种程度:
程度一:IaC 进 CI/CD 流水线. 把 .tf 代码放进 Git,提 PR 时自动跑 terraform plan 把"将要发生的变更"贴到 PR 上供 review,合并后自动 apply.基础设施变更从此和应用代码一样:有 review,有审计,可回滚.
程度二:用 Crossplane 把基础设施纳入 GitOps. 如前所述,基础设施直接成为 ArgoCD 同步的对象,和应用共用一套声明式管线.
|
至此,从一行代码提交,到承载它的服务器,网络,集群,每一层都是声明式的代码,都在 Git 里,都可复现可审计.这就是现代云原生交付的完整图景.
整个 CI/CD 系列的收束
回头看这八篇,其实是同一个核心思想在不同层次的反复应用--用声明式代码替代人工操作,设好客观标准让机器自动决策:
| 阶段 | 解决的层次 | 同一思想的体现 |
|---|---|---|
| 一 · CI 与制品(01-04) | 代码 → 可信镜像 | 流水线代替手工构建,门禁代替人工评审 |
| 二 · GitOps 交付(05-07) | 镜像 → 安全上线 | Git 声明状态,控制器调谐,指标驱动放量 |
| 三 · IaC(08) | 底座 → 可复现的基础设施 | 代码声明基础设施,状态对账,apply 调谐 |
三个阶段层层向下:阶段一造出可信的"货",阶段二把货安全地送上"车"(集群),阶段三则保证"路和车"(基础设施)本身也是按图纸建的,可随时重建.人的角色,从"亲手操作每一步",变成"定义标准,审查变更,处理例外".
快速回顾
- 要解决的问题:ClickOps(点控制台建基础设施)不可复现,不可追溯,会漂移--和手工发布同病
- IaC:用声明式代码描述服务器/网络/数据库,工具读代码自动创建,可进 Git,可 review,可复现
- 状态(State)是灵魂:一份"代码资源 ↔ 云上真实资源"的映射账本,让工具能 diff 出增删改;K8s 内建托管状态故无感,Terraform 管外部云资源必须自管状态
- 状态的坑:必须远程共享 + 加锁,含敏感信息要加密,绝不手工编辑
- 三工具取舍:Terraform(HCL,事实标准,生态最全)/ Pulumi(通用语言,灵活但需自律)/ Crossplane(K8s YAML,状态由 etcd 托管,原生接 GitOps)
- 合流:IaC 进流水线(PR 上看 plan,合并后 apply),或用 Crossplane 让基础设施也走 ArgoCD,实现应用+底座的统一声明式管理
IaC 和配置管理工具(Ansible,Chef)是一回事吗?
侧重点不同.IaC(Terraform 等)偏供给(Provisioning)--从无到有创建基础设施资源(开机器,建网络,建集群),是声明式的.Ansible 这类配置管理偏在已有机器上做配置(装软件,改配置文件),偏过程式.实践中常配合:Terraform 先把机器开出来,Ansible 再上去装东西.不过在云原生时代,"装软件"这件事很大程度被容器镜像(第 03 篇)取代了,配置管理的地盘在收缩.
已经手工建了一堆资源,现在想用 IaC 接管,要全删了重建吗?
不用.IaC 工具提供 import 能力:把已存在的云资源"导入"到状态账本里,并补写对应代码,之后就由 IaC 管理了,无需删除重建.这正体现了状态的作用--import 本质就是在账本里登记"这个云上资源从此归这套代码管".对存量环境迁移到 IaC,这是标准做法.
动手练习
- 体验状态账本 装 Terraform(或 OpenTofu),用
local/random这类不花钱的 Provider 写几个资源,跑plan和apply,然后打开生成的terraform.tfstate看看状态账本长什么样. - 观察销毁推断 把代码里某个资源删掉,再
plan,观察它如何依据状态判断"这个该销毁";apply后再看状态变化. - 漂移检测 故意手工改一下已创建资源的某个属性,再
plan,观察 Terraform 如何检测到"现实偏离了代码"并打算纠正--对照第 05 篇的"自愈"体会异同. - 远程状态后端 把状态后端从本地改为远程(如用 Terraform Cloud 免费层),理解"团队为何不能各存一份本地状态".
- 串联全系列 画一张图:一次"新增一个微服务"的完整旅程,从 IaC 准备底座,到阶段一 CI,到阶段二 GitOps 上线,每一步分别由哪个工具,哪份代码负责.