多数配置故障起初看起来不像编程故障。它们更像是从另一个服务复制来的一段 YAML 字段,像在一处完成校验却在另一处被静默接受的 JSON 载荷,像和部署文件并排摆放、没有进入同一个审查界面的 Kubernetes 策略,也像一份生成文件,它的 schema 之所以被信任,只因为构建流水线通常表现正常。CUE 的有趣之处在于,它没有先往这堆东西上再加一个 linter。它提出的问题是:配置、schema、策略和数据能否共享同一条语言边界。[1][2][4][5]
FOSDEM 2022 这场名为 "A practical guide to CUE: patterns for everyday use" 的会议演讲,是一个有用的锚点,因为它没有把语言理论当作独立目的来推销。活动说明把这场演讲放在实践模式之中:校验、策略、与既有非 CUE 配置集成,以及面向已经在 JSON、YAML、Protocol Buffers 或 OpenAPI 中工作的人的示例。[2] 这正是合适的运行语境。CUE 的意义较少来自更漂亮的语法,更多来自它让配置契约在变成事故之前就能被运行和检查。[1][2][3]
观看时需要抓住的核心概念是统一。CUE 的导览解释说,只要值之间没有冲突,字段就可以被多次指定,struct 和 list 也会递归统一。[4] 约束页面进一步把这个点收紧:约束本身也是值,因此一份规格既可以说明什么被允许,也可以提供具体字段,这些字段会出现在约束被统一到的地方。[5] 语言中改变工程讨论的正是这一部分。团队的问题由“schema 在哪里?”和“配置在哪里?”两条分线,转向整个配置值是否仍然能够保持一致。[4][5]
开场动作是把配置视为带有义务的数据
在这场 37 分钟演讲的开头部分,重要的转移点不在某一个语法特性,而在这样一种主张:配置应当随身携带义务。[1][2] 一份普通的 YAML 文件可以说明系统当前想要什么。一份分离的 schema 可以说明这个文件应当具备什么形状。一个策略引擎可以说明在某个环境里哪些形状可以接受。一个生成器还可以为目标系统产出另一份制品。这些层次都很熟悉,但它们的分离会制造漂移。审查批准的也许是一层,而另一层在底下发生了变化。
CUE 的模型通过让约束与数据可组合,直接处理这种漂移。当导览说统一只在值之间没有冲突时成功,它描述的是一条实际的审查规则,并且也同时是一条语言规则。[4] 如果一个服务定义声明 replicas 必须是大于零的整数,那么环境叠加层可以收窄这个值,同时保留原始契约。如果另一个叠加层试图把这个值变成无法成立的状态,这个值就不只是在运行时意义上成为“坏配置”。它会统一失败。[4][5]
这也是这段视频值得和官方文档一起打开观看的原因。演讲给出了工作流的压力:既有格式、策略检查、日常校验,以及与人们已经使用的工具集成。[1][2][3] 文档则给出了这种工作流能够成立的机械原因:CUE 把约束和具体值看成同一个值格中的成员,摆脱了用约定把互不相关文件粘在一起的脆弱方式。[4][5]
演讲中段谈的是收拢与边界整理
到了中段,实践示例应当被理解为对制品蔓延的收拢。[1][2] 面对 CUE,人们容易把它称作“带类型的 YAML”之后就停下来。这个说法会错过更有用的模式。CUE 可以在常见配置格式之间导入、校验、转换和导出数据;FOSDEM 页面明确把 JSON、YAML、Protocol Buffers 和 OpenAPI 放进这场演讲的预设地带。[2] 项目的演讲页面同样把 CUE 相关演讲组织在策略、Terraform、Go 集成和配置工程周围,这说明这门语言的目标位置跨越边界,超出单一文件类型内部的语法改良。[3]
对于一个工程团队来说,价值不在于 CUE 消灭其他所有格式。实际工作里通常不会如此。Kubernetes 仍会接收 manifest。CI 系统也许仍然想要 YAML。API 也许仍然会发布 OpenAPI。价值在于,CUE 可以成为这些输出四散之前对照共享契约完成检查的地方。由此看,最容易被 CUE 吸引的,是那些配置已经跨越多种格式、审查也已经变得痛苦的团队。[2][3][5]
危险也在这里显现。如果 CUE 只变成一个聪明的生成器,它会把复杂性藏在又一个构建步骤背后。更好的用法是让契约可以被检查:定义应当围绕领域概念命名,约束应当说明它执行的运维规则,导出的制品应当被视为契约的产物,事实来源则留在契约本身。从演讲和文档中可以推导出,CUE 在减少真相存放位置时效果最好。[1][4][5]
统一会改变代码审查
最具体的收获,是 CUE 应当改变 pull request 里的提问方式。普通配置审查经常问的是局部问题:这个字段改了吗,这个环境文件还能解析吗,生成输出更新了吗?CUE 审查可以提出更强的问题:在所有叠加层、默认值、约束和导入相遇之后,最终得到的值是否仍然连贯?[4][5]
这是一种不同的审查习惯。它会鼓励小而可组合的约束,减少巨大顶层文件带来的审查负担。它推动团队把可复用定义和特定环境选择分开。它也为策略提供了一个更贴近其治理数据的位置。容器资源限制、必需标签,或者允许区域列表,都可以写入同一份契约,而这份契约也负责生成部署数据。部署工具看到数据之前,契约已经可以被测试。[2][4][5]
这里也是 CUE 要求纪律的地方。递归统一会让组合呈现出一种顺手的自动感,但自动组合仍然属于架构。团队需要名称、包边界、所有权,以及一条清楚规则,用来判断某个约束应当进入共享模块,还是留在本地服务文件。缺少这套纪律,语言会变成一张由聪明引用织成的密网。有了这套纪律,CUE 给审查者留下的,是更少而更耐久的检查位置。[3][4]
最后一课是边界放置
进入 FOSDEM 这场演讲的后三分之一后,有用的问题已经不再是“CUE 能校验这个文件吗?”答案经常是可以。[1][2] 更好的问题是“校验边界应该放在哪里?”如果边界放得太晚,CUE 就变成最后一刻的检查,而人在这之前已经审查了错误的制品。如果边界放得太早,它会在契约成熟之前拒绝有价值的本地实验。合适的边界通常落在一个值转入共享基础设施的时刻:可复用 schema、生成出来的 manifest、策略模块,或者被多个团队消费的配置包。[2][3][5]
这种边界放置,正是 CUE 应当进入 OSS 信息流的原因:它作为工程工具发挥作用,意义超出语言观光。它给团队提供了一种方式,把运维知识编码到依赖这些知识的配置附近。它也给出一个强承诺,而这个承诺容易被误解:语言可以证明你交给它的模型内部一致,但它不能判断你的模型是否映照了生产现实。领域判断仍由人负责。CUE 的贡献,是让这种判断进入可运行、可审查,并且更难被意外绕过的形态。[1][4][5]
顺着这个角度阅读,FOSDEM 这场演讲就超出了初学者介绍。它用紧凑的方式说明,配置安全可以更早前移,同时避免被送进一层分离的官僚流程。CUE 最好的本领不在语法本身,而在于让契约和值先相遇,然后系统才会为错误付出代价。[1][2][4][5]
来源
- CUE,"FOSDEM 2022 - A practical guide to CUE: patterns for everyday use",YouTube 视频。
- FOSDEM 2022,"A practical guide to CUE: patterns for everyday use"——活动页面、演讲说明、讲者和录像链接。
- CUE,"Talks and Presentations by the CUE Team"——项目演讲索引,以及围绕策略、Go、Terraform 和配置工程展开的话题框架。
- CUE 文档导览,"Unification"——重复字段、递归统一和冲突规则。
- CUE 文档导览,"Constraints"——作为值的约束,以及与具体数据的统一。
- Zeljko Filipin,"Testing and Automation devroom at FOSDEM 2013 Photo 2",Wikimedia Commons 照片。