Skip to main content

Command Palette

Search for a command to run...

IaC 杂感

Updated
2 min read

IaC 的起源

IaC 是配置管理领域的一种技术,全称 Infrastructure as Code,字面意义:基础设施即代码,是一种使用可读文本发放和管理基础设施资源的方法。通常情况下,软件定义的基础设施管理平台,会为用户提供命令行、WebUI 的方式,让用户能够用手工或者工具化的方式进行资源发放和管理工作。随着“基础设施”这一概念的不断扩展,使用频度的不断提高,越来越多的基础设施平台会提供各自的 API 为自动化打开方便之门。为了更快、更多的发放更多种类的基础设施,用一致的代码对这些基础设施进行管控也是顺理成章。IaC 的发展史很清楚地证明了这种演进过程。

1993 年,Mark Burgess 在博士后期间,为了管理不同的 Unix 工作站,开发了 CFEngine。这个大概是 IaC 工具的鼻祖。据说他仅仅根据直觉和实践经验,为了简化在不同 Unix 下大量编写脚本的工作,而开发了这个软件,在这里他提出了面向最终状态进行收敛的思路。

2006 年,AWS 发布了 EC2,各种公有云、私有云随之兴起,企业面对的资源不再是少数的主机,取而代之的是数量更大、品种更多、生命周期更短的虚拟机和随之而来的、更复杂的 IT 环境。在这之后,Chef、Salt Stack、Ansible 等生态也先后浮出水面。

个人认为真正的变化,是接下来的 2021-2024 年,Cloudformation、Terraform 和 Kubernetes 陆续发布,使用声明式 API 进行 IaC 操作成了业界惯例。AWS Control API 和 Kubernetes 这样的基础设施,从底层保障了声明式 API 的实现能力。

IaC 是对物理资源的采样

IaC 真的能描述物理资源么?很显然答案是否定的,毕竟现实世界是连续的。例如下面的 EC2 Instance:

  MyEC2Instance: 
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: "ami-79fd7eee"
      KeyName: "testkey"
      BlockDeviceMappings: 
      - DeviceName: "/dev/sdm"
        Ebs: 
          VolumeType: "io1"
          Iops: "200"
          DeleteOnTermination: "false"
          VolumeSize: "20"
      - DeviceName: "/dev/sdk"
        NoDevice: {}

很明显,这几行代码不可能描述一个完整的 EC2 实例,结合前面提到的 Control API 和 Kubernetes,实际上,对资源的抽象从资源 API 层面就已经开始了,表现在 IaC 层面的,也只是这种抽象的结果。正如对声音的采样,IaC 中表达的资源不会是“完整的全貌”,越频繁的采样,能够保留越多的细节,也会造成这一描述的复杂度大大提高——但是无论如何提高,IaC 的描述能力甚至都达不到监控的细节水平。换句话说,使用 IaC 的方式来描述资源,就必须承担抽象带来的损失。

除了静态的属性之外,对象的状态也是对实际情况的大幅度抽象,例如下面的 Pod 状态:

虽然看起来很细致,但实际上中间忽略了很多细节,一个明显的例子就是,在各个状态之间切换失败时,往往都需要进一步的识别问题根因才能解决。

在《Thinking in Promises》中,有这样一段话:

我们的文化,偏好于对整体图景进行理解,这种偏好催生了控制系统:这些大型、集中式、无所不知的系统,像大脑一样运作运作,它们根据可用性和一致性的假设做出精确决策,根据我们的微观管理思路,产生直接的指令性的动作。集中化在逻辑上是合理的,然而它导致了规模上的限制。具备庞大处理能力的集中控制在逻辑上是合理的,然而在大规模系统下,仍然可能无法快速决策和执行动作。行动的延迟所导致的不准确和不一致,通常会造成未知后果。

随着计算、存储、网络的飞速进步,我们能够越来越多地获得系统中各种资源的细节信息,这可能会造成一种“膨胀”的心态——我们希望能够更多地获取系统中发生的所有细节,知晓其所有过往,甚至预测其所有未来。但是问题也很明显,我们面对的世界的复杂度的加速度,远高于我们的采集和管理能力的提升。将连续的物理资源抽象为离散的资源对象,并且以可读代码的方式进行表达,能有效地降低基础设施对注意力的消耗。同时针对软件开发过程设计的版本管理、访问控制、单元测试、文本比对、规则引擎、安全扫描、代码评审等一系列的方法都可以在 IaC 世界中大展拳脚,借助这一技术,管理员能更透明、更快、更大范围地对基础设施进行发放和管理。

IaC、面向对象和微服务

在我使用 IaC 的这一段时间里,新鲜感过后,我遇到了和推广容器化同样的困境——大量的实际业务和管控需求无法满足。在云原生语境中,我通常会用 12 要素等微服务要求来解释为什么你的“微服务”不能容器化。例如其中对进程、状态、配置、快速启动和优雅终止等。但是在 IaC 的落地过程中,我感觉缺乏了这样的理论后盾,有些底气不足。手里有了锤子,自然希望一切都是钉子——这些基础设施不过就是微服务运行所依赖的环境吧?面向对象、微服务架构的各种原则在这里是否继续有效呢?Terraform Provider 开发最佳实践中有这么几条:

  • Providers should focus on a single API or problem domain
  • Resources should represent a single API object
  • Resource and attribute schema should closely match the underlying API

很明显,这里将 TF Provider 视作了 Restful API 的延伸,而众所周知,Restful API 本身的设计,关注的也是“资源”及其 CURD-L 操作。因此作为 IaC 基础的 Provider 们,本身应该就可以用 OO 的方式进行构建了。IaC 资源就是对物理资源的抽象,我们在软件设计过程中所遵循的设计原则,应该也是适用于 IaC 的实施过程之中的,并且 IaC 应该是整个软件的一部分,因此其复杂度也是小于软件的整体的,顺着这个思路,就可以理直气壮的做些事了。

拆分堆栈

在公有云上运行软件,往往会涉及品类繁多的云资源,每次更新都是按照堆栈进行组织的,然而到底围绕一个微服务的堆栈应该由哪些资源组成呢?例如 VPC 算么?容器集群算么?浮动 IP 算么?按照上面的说法,把这些基础设施资源按照拆分微服务的方法进行组织,就方便多了。针对每个资源,简单地回答几个问题,就可以确定其归属了,例如记在谁的账上?谁在使用他?谁负责它的运维?哪些资源是一起更新的?这样几个维度判断下来,围绕着微服务,就能够构建合理的资源堆栈了。

Module 的划分

通常会使用 Module 对资源进行组合,这种组合有很多好处,例如可复用、规范化、降低认知负载等等,然而什么资源和什么资源应该组合成一个 Module 呢?Module 类似于日常开发中的 Library,完全可以使用和共享代码一样的方式,确定其共享范围和功能边界。

流水线设计

在 AWS 的 Builder's Library 中提到:

典型的微服务可能具有应用程序代码管道、基础设施管道、操作系统修补管道、配置/功能标记管道,以及运算符工具管道。同一个微服务拥有多个管道有助于我们更快速地将更改部署到生产环境。未通过集成测试且阻塞应用程序管道的应用程序代码更改不会影响其他管道。例如,它们不会阻止基础设施代码更改到达基础设施管道的生产阶段。同一微服务的所有管道看起来都十分相似。例如,功能标记管道使用的安全部署技术与应用程序代码管道相同,因为错误的功能标记配置更改就像错误的应用程序代码更改一样,可能会影响生产。

不难发现,上述不同的流水线,也采用了类似微服务的划分方法,多条流水线以独立运作、互不堵塞的方式,用不同的频率个自运行。

入乡应随俗

如你所知,不管是面向对象,还是微服务架构,还没有、也不可能一统天下,IaC 也是这样。在传统运维领域,我们更倾向于掌控变更的全部过程,面对 IaC/Provider 这样的黑盒子,这种追求可能就有些不合时宜了——尤其是对于自行实现的 Provider 来说。

要想穿透 IaC 资源的状态管理,实现基于流程的过程管控,通常可以有两种做法:

  1. 拆小堆栈:用尽可能小的颗粒度进行变更,这样就从宏观上提供了一个相对细致的管控能力。
  2. 暴露细节:将原本被状态迁移隐藏起来的过程,暴露给外部进行观测和限制。

小颗粒的堆栈,牺牲的是 IaC 变更的效率和完整性;而暴露内部细节的方式,则破坏了对象的封闭性——像是暴露了所有 Private 成员的类定义,客观上对于“不规矩”/“不完整”的 Provider 是一种鼓励。

正如对 Kubernetes 对象的操作一样,IaC 的管控应该是一个相对“肤浅”、“粗放”的过程,能够依赖的,只能是 Provider 主动开放出来的状态迁移过程。

More from this blog

龙虾恐慌:AIOps 又要改名了?

ChatGPT 开始,把 AI 拉近到普罗大众的面前,让无数人感受到 AI 的亲民魅力。而龙虾,则把大模型驱动的自动化能力,突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”,而是风口本身。热度高到让 Mac mini 一度断货,不知道这在不在库克的预料之内。 每代人都有每代人的鸡蛋,春节期间,我就领了我的鸡蛋。翻出古老的 MacBook Air M1,充值各种大模型。当然了,这个工具

Mar 9, 20261 min read

再见 2025

我猜不少人以为这个号废了吧?并没有,只是今年变化有点大,一直有种抄起键盘,无从说起的感觉,所以一直偷懒到今天,2025 的最后一天。 今年是我的第四个本命年,去年末一期播客里,大内说本命年不是灾年,是变化年,有危也有机。可是讲真啊,只看到危,没看到机。 各种因缘际会,从鹅厂跳槽到前东家,已经接近四年,第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫,后两年基本都是些鸡零狗碎的东西了,用老东家的术语说是——偏离主航道,可谓是前景暗淡了。 一旦确定要滚蛋,反倒心思轻松起来,每天骑着我的小红车...

Jan 5, 20261 min read

辅助编程?dora 说:我知道你很急可是请你别急

从 OpenGPT 把大模型的火烧旺了之后,这三年来,相信很多组织或摩拳擦掌、或躬身入局,希望借助聪明能干的大模型,或想偿还技术宅,或想降本增效,或想弯道超车。一时间,沉寂许久的 AIxx 又活过来了,LLM Ops、Vibe Coding、中医大模型、GPT 算命等等,全都老树发新芽,焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发,产生了什么触动,应该如何拥抱呢? DORA 的年度报告中给出了很有意思的结论——强者恒强。 执行摘要部分总结了几个有趣的点: 问题...

Oct 6, 20251 min read

[译]dora:ai 辅助软件开发状态报告

执行摘要 在 2025 年,科技领导者面临的核心问题已不再是“是否要采用 AI”,而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实:AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势,也会凸显组织的缺陷。 关键结论:AI 是放大器 AI 投资的最大回报并非来自工具本身,而是来自组织底层系统的战略性建设: 高质量的内部平台 清晰的工作流 团队的协同能力 缺少这些基础,AI ...

Oct 2, 202514 min read

僭越了,有人在用 Rust 写 Kubernetes

一个新语言问世,最爱做的事情之一,就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s(https://github.com/rk8s-dev/rk8s) 也可以归在这个范畴里,只不过这个项目重写的东西比较大,是 Kubernetes。 从 2025 年 1 月第一个 Commit 开始,到现在有了 200 多次 Commit,十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。 另外该项目也是国内第一个脱离 Cargo 转向使用 ...

Sep 27, 20253 min read

【伪】架构师

342 posts