为什么 Ansible 是程序化的而 Terraform 不是?

为什么 Ansible 是程序化的而 Terraform 不是?

我试图理解为什么 Ansible 是程序化的而 Terraform 不是。所有博客似乎都举了一个例子 - 如果您在 Ansible 中创建 2 个 EC2 实例并将计数更改为 4,那么您将再有 4 个;但在 Terraform 中,当您更改计数时,您将总共有 4 个 EC2 实例,而不是再创建 4 个 EC2 实例。

但我相信这并不是一个真正的程序性/声明性的例子?

有没有更好的例子来解释为什么 Ansible 是程序性的而 Terraform 是声明性的?

答案1

这些广泛的分类只有在我们知道它们的含义的范围内才有用,不幸的是(但不可避免地)每个人对“声明性”的含义都有自己的理解,因此我认为做出“Terraform 是声明性的”这样的一般性陈述并不是很有用。

相反,我认为值得深入挖掘并讨论这些系统的一些特点涉及的想法声明式编程。特别是,我将重点关注我在撰写本文时在 Wikipedia 文章开头描述的显式与隐式控制流的概念,但我要先说一下(正如我们在 Wikipedia 页面上看到的)声明式编程有各种其他定义,它们并不关注控制流,因此可能会导致不同的分析。

(披露:我在 HashiCorp 从事 Terraform 工作,并设计了 Terraform 语言的最新版本。因此,尽管我打算尽力客观地描述这两个系统,但我对 Terraform 的了解远胜于对 Ansible 的了解,所以我对 Ansible 的陈述是从我作为它用户的角度出发的,而我关于 Terraform 的陈述也受到我对其实现的了解的影响。)

地形

关于 Terraform 语言,我们可以说的一件事是,我们写在其中的信息是应该存在什么,而不是描述实现这一目标的一系列步骤。当我们运行terraform plan(或 Terraform 将其作为 的一部分隐式运行terraform apply)时,Terraform 采用的配置大致由以下部分组成:名词(一个 EC2 实例、一个云运行定义、一个虚拟网络)以及Terraform 本身将其变成一组动词创造EC2 实例,更新云运行定义,删除虚拟网络)。

Terraform 的另一个与动态规划相关的方面是,通常没有关于订购Terraform 配置中的操作。就像 Terraform 本身生成计划的操作集一样,Terraform 本身也会确定这些操作的顺序以及哪些操作可以同时执行。我们可以说 Terraform 使用数据流(值通过表达式从一个资源传播到另一个资源的方式)来推断控制流。

我特别要指出的是,Terraform 没有控制流的说法是不正确的根本:仍然需要正确的操作顺序来产生预期结果。但控制流是通过对象之间的数据传播来暗示的,​​作者没有明确描述。

尽管用户经常使用“循环”一词来描述 Terraform 的重复结构,如for表达式、资源for_eachdynamic块,但它们的设计更像是函数式编程组合器,如地图,我们描述的是将一个值转换为另一个值,而不是要执行的一系列操作。Terraform 可以使用各种控制路径实现该转换,只要最终结果与用户通过表达式描述的内容相匹配即可。

Terraform 中的概念provisioner使 Terraform 总体上有点像混合体:配置程序是用户指定的命令式步骤序列,作为“创建”或“销毁”步骤的一部分。Terraform 包含配置程序作为实用主义的衡量标准,因为对于虚拟机等有状态对象,我们通常必须使用命令式技术来确保副作用以 Terraform 无法自然推断的特定顺序出现。话虽如此,Terraform 的供应商被记录为最后的手段具体来说因为它们脱离了通常的模型,导致 Terraform 无法完全模拟正在采取的一系列操作。Terraform 还缺乏用于编写动态控制流的构造在语言中使用供应商:没有机制来编写循环和条件分支,相反,供应商(从 Terraform 的角度来看)只是一个扁平、固定的操作序列。

Ansible

任务列表Ansible 剧本中是一系列有序的动词,指示要采取的操作。其中许多任务类型都以“确保...”的形式呈现,例如“确保/etc/foo存在并包含此内容”,因此我认为可以说这些任务是以清单形式呈现的声明性语句:如果文件已经存在并且已经包含该内容,那么从外部观察者的角度来看,该任务将根本不会采取任何行动。

Ansible 的一些任务是 Terraform 会委托给配置程序的任务,例如“运行这个单独的程序以产生副作用”。在这种情况下,就像 Terraform 中的配置程序一样,作者有责任了解副作用并确保步骤按正确的顺序进行,以使这些副作用有意义。

控制流是 Terraform 和 Ansible 模型差异较大的领域。正如我之前提到的,任务列表是有序序列,因此作者必须明确指定该任务列表中描述的操作的适当顺序。Ansible 不会像 Terraform 那样自动从数据流推断控制流。

Ansible 具有循环更像命令式编程。在常见情况下,它们在原则上类似于函数式编程组合器,但对于任务循环而言,任务本身可能具有副作用这一事实意味着循环的执行顺序很重要,因此 Ansible 循环是显式控制流。


基于上述特点,我的感觉是 Terraform 和 Ansible 都可以以声明式方式和程序式方式使用。然而,Terraform 的语言设计为优先考虑声明式编程风格的解决方案,限制/阻止程序化方法,而 Ansible 优先考虑程序化方法,同时可能允许作者选择采取声明式的方法。

相关内容