<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>terraform | 伪架构师</title>
    <link>/tags/terraform/</link>
      <atom:link href="/tags/terraform/index.xml" rel="self" type="application/rss+xml" />
    <description>terraform</description>
    <generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>zh</language><lastBuildDate>Sun, 07 Jul 2024 06:58:46 +0800</lastBuildDate>
    <image>
      <url>/img/logo-wide.png</url>
      <title>terraform</title>
      <link>/tags/terraform/</link>
    </image>
    
    <item>
      <title>介绍一个小工具：Terranetes</title>
      <link>/post/terranetes-controller-intro/</link>
      <pubDate>Sun, 07 Jul 2024 06:58:46 +0800</pubDate>
      <guid>/post/terranetes-controller-intro/</guid>
      <description>

&lt;h2 id=&#34;iac-不只是-terraform&#34;&gt;IaC 不只是 Terraform&lt;/h2&gt;

&lt;p&gt;虽然几年前的一次讨论中，我嘲讽过某同事说，Terraform 目前最靠谱的 Provider，也就只有 Kubernetes 一个而已，相对于顾头不顾尾的 Provider 来说，Kubernetes + Operator 才是正道；然而形势比人强，目前 Terraform 的确是能帮用户踏上 IaC 旅程的方便法门。&lt;/p&gt;

&lt;p&gt;就像 Kubernetes 之于云原生，对于 IaC 来说，Terraform 也同样有着 Day2 的问题。并且由于面对更大范围、更大成本的调度能力，Terraform 的管控也面临更大的挑战。例如工作流、合规、安全、成本等方面的考虑，以及偏差检测、模块安全等特性的应用，都是摆在管理员面前的明显问题。围绕这一工具，想要构建一个稳健的自助平台，是个颇为复杂的困难过程。&lt;/p&gt;

&lt;h2 id=&#34;terranetes-简介&#34;&gt;Terranetes 简介&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;appvia.io&lt;/code&gt; 是一个位于伦敦的解决方案厂商，它的开源项目 &lt;code&gt;Terranetes&lt;/code&gt; 就尝试解决 Terraform 的 Day2 问题。这个 golang 项目在 22 年开源，到现在为止，发布了一百多个 Release，Star 数量只有 135 个，上次代码更新是在两个月前，从运作成绩来看，似乎不太成功。然而从平台工程的角度来看，这个项目提供的众多特性，却是非常值得关注和致敬的。&lt;/p&gt;

&lt;p&gt;Terranetes 首页有这样一张图，形象地描述了这一产品的 IaC 治理思路：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/terranetes-controller-arch.png&#34; alt=&#34;governerce&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;工作流&#34;&gt;工作流&lt;/h3&gt;

&lt;p&gt;图里简单地描述了一个工作流，平台团队制定规则、开发团队申请资源，控制器接收申请、引用凭据、执行规范，按照流程中设定的审批、Lint 等环节，完成资源申请过程。&lt;/p&gt;

&lt;p&gt;他把用户明确地区分为平台和开发两种角色：&lt;/p&gt;

&lt;h4 id=&#34;平台团队&#34;&gt;平台团队&lt;/h4&gt;

&lt;p&gt;平台用户的主要职责是为开发者用户提供自助服务的基础支持：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;接入资源供应商&lt;/strong&gt;：用 CRD 的形式定义资源供应商，以此来支撑开发者使用指定供应商的资源。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;凭据管理&lt;/strong&gt;：管理接入资源供应商的身份凭据，开发者无需自行管理凭据，即可获得操作资源的权限。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;策略管理&lt;/strong&gt;：从成本、合规、安全等方面，提供策略支持，保障开发者对资源的有效使用。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;开发团队&#34;&gt;开发团队&lt;/h4&gt;

&lt;p&gt;开发者的职责相对集中一些：引用平台团队维护的凭据、规则、模板等，按照既定工作流进行资源的申请和使用。&lt;/p&gt;

&lt;h2 id=&#34;上手一试&#34;&gt;上手一试&lt;/h2&gt;

&lt;p&gt;官方提供了 Quick Start 文档，网络条件允许的话，几分钟就可以完成第一次资源分配。下面的例子我使用 AWS 作为资源供应商，本机的 OrbStack 提供给 Terranetes 作为控制器的 Kubernetes 运行平台。&lt;/p&gt;

&lt;h3 id=&#34;先决条件&#34;&gt;先决条件&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes 集群&lt;/li&gt;
&lt;li&gt;AWS 账号，有能够创建 S3 Bucket 的 AK/SK&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;部署&#34;&gt;部署&lt;/h3&gt;

&lt;p&gt;基于 Helm 的老套部署方式：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ helm repo add appvia https://terranetes-controller.appvia.io
$ helm repo update
$ helm install -n terraform-system terranetes-controller appvia/terranetes-controller --create-namespace
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;运行后可以看到多出了 &lt;code&gt;terraform-system&lt;/code&gt; 命名空间，其中运行了两个控制器 Pod。&lt;/p&gt;

&lt;h3 id=&#34;crd&#34;&gt;CRD&lt;/h3&gt;

&lt;p&gt;看看多出了哪些 CRD：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl api-resources | grep terraform
cloudresources                                 terraform.appvia.io/v1alpha1      true         CloudResource
configurations                                 terraform.appvia.io/v1alpha1      true         Configuration
contexts                                       terraform.appvia.io/v1alpha1      false        Context
plans                                          terraform.appvia.io/v1alpha1      false        Plan
policies                                       terraform.appvia.io/v1alpha1      false        Policy
providers                                      terraform.appvia.io/v1alpha1      false        Provider
revisions                                      terraform.appvia.io/v1alpha1      false        Revision
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;官网文档用下图来描述对象之间的关系：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;images/cloudresources.png&#34; alt=&#34;CRDs&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CloudResources&lt;/strong&gt;：这个对象用来描述 Terraform 中的云资源，CloudResources 会选择性的向用户公开属性，从而减少开发者的心智负担，并确保选项符合组织意图。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revisions&lt;/strong&gt;：Revision 是云资源的模板，在实际环境中，应该是经过策划和测试的版本化资产，其中会包含组织所需的默认设置，并只公开与上下文相关的功能：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Revision 指向 Terraform 模块。&lt;/li&gt;
&lt;li&gt;包含平台希望模块默认设置的所有默认选项，并向消费者公开部分可见选项。&lt;/li&gt;
&lt;li&gt;可以跟踪 Terraform 模块，也可独立演进。&lt;/li&gt;
&lt;li&gt;所有 CloudResources 都会引用集群中的 Revision。&lt;/li&gt;
&lt;li&gt;要升级 CloudResource 消费者，需要更新其指向的 Revision。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Configurations&lt;/strong&gt;：另一种描述云资源的方法，相对于 CloudResource，它相对传统一些，采用了和 Module 进行一对一连接的方式。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Providers&lt;/strong&gt;：用来连接云资源提供方的定义。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plans&lt;/strong&gt;：无需主动创建，随 &lt;code&gt;Revision&lt;/code&gt; 对象的定义自然产生。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policies&lt;/strong&gt;：对策略的引用，其中包含了 &lt;code&gt;Checkov&lt;/code&gt; 规则的引用方法、对 Module 的限制。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contexts&lt;/strong&gt;：上下文提供了一种在配置之间共享通用配置的方法。集群中任何组件都可以引用该资源。&lt;/p&gt;

&lt;h3 id=&#34;配置凭据和-provider&#34;&gt;配置凭据和 Provider&lt;/h3&gt;

&lt;p&gt;接下来配置用来连接 AWS：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl -n terraform-system create secret generic aws \
--from-literal=AWS_ACCESS_KEY_ID=${AWS_AK} \
--from-literal=AWS_SECRET_ACCESS_KEY=${AWS_SK} \
--from-literal=AWS_REGION=${AWS_AGN}
secret/aws created
$ export PROVIDER=&amp;quot;https://raw.githubusercontent.com/appvia/terranetes-controller/master/examples/provider.yaml&amp;quot;
$ kubectl apply -f $PROVIDER
provider.terraform.appvia.io/aws created
provider.terraform.appvia.io/aws-irsa created
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到 Provider 对象的 &lt;code&gt;spec&lt;/code&gt; 内容：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;  spec:
    preload:
      cluster: wayfinder-production
      context: default
      enabled: false
      region: eu-west-2
    provider: aws
    secretRef:
      name: aws
      namespace: terraform-system
    source: secret
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中指定了 AWS 作为资源供应商，并且使用前面的 Secret 作为连接凭据。&lt;/p&gt;

&lt;h3 id=&#34;配置-revision&#34;&gt;配置 Revision&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ export REV=&amp;quot;https://raw.githubusercontent.com/appvia/terranetes-controller/master/examples/revision.yaml&amp;quot;
$ kubectl apply -f ${REV}
revision.terraform.appvia.io/bucket.v1 created
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;打开 Revision 文件，能够大致观察到其中包含的信息：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;configuration&lt;/strong&gt;：其中有 Module 的地址、Context 引用、Provider 引用以及&lt;strong&gt;默认值&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;inputs&lt;/strong&gt;：这里定义了用户可以控制的内容（此处只有 &lt;code&gt;bucket&lt;/code&gt; 可写）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;plan&lt;/strong&gt;：则定义了该对象所属的计划。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Revision&lt;/code&gt; 中定义的 &lt;code&gt;Plan&lt;/code&gt; 也被自动创建了：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get plan bucket -o yaml
apiVersion: terraform.appvia.io/v1alpha1
kind: Plan
metadata:
  ...
spec:
  revisions:
  - name: bucket.v1
    revision: v0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;使用-plan-revision-创建资源&#34;&gt;使用 Plan-&amp;gt;Revision 创建资源&lt;/h2&gt;

&lt;p&gt;上面两节完成了平台管理或者资源管理角色的任务，接下来要真正地申请资源了。这里需要创建如下的 &lt;code&gt;CloudService&lt;/code&gt; 对象：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: terraform.appvia.io/v1alpha1
kind: CloudResource
metadata:
  name: bucket
spec:
  plan:
    name: bucket
    revision: v0.0.1
  providerRef:
    name: aws
  writeConnectionSecretToRef:
    name: test
  variables:
    bucket: forever8384
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;执行之后，我们会看到，系统中有了一个运行成功的 &lt;code&gt;Job&lt;/code&gt; 对象，以及一个 &lt;code&gt;CloudResource&lt;/code&gt; 对象：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl get jobs
NAME                  COMPLETIONS   DURATION   AGE
bucket-tgbrl-1-plan   1/1           28s        8m37s
$ kubectl get cloudresources.terraform.appvia.io
NAME     PLAN     REVISION   SECRET   CONFIGURATION   ESTIMATED     UPDATE   SYNCHRONIZED   AGE
bucket   bucket   v0.0.1     test     bucket-tgbrl    Not Enabled   None     OutOfSync      8m50s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;任务已经完成，打开 AWS 控制台，也找不到我们要的 Bucket。看看 Job 对应的 Pod 日志：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;kubectl logs -f bucket-tgbrl-1-plan-lj7hd
[info] Checking if required flags have been provided.
[info] Waiting 10 seconds for pod logs to be available (attempt 1/15)..
[info] waiting for the job to be scheduled
...
  # aws_s3_bucket_server_side_encryption_configuration.this[0] will be created
  + resource &amp;quot;aws_s3_bucket_server_side_encryption_configuration&amp;quot; &amp;quot;this&amp;quot; {
...
  # aws_s3_bucket_versioning.this[0] will be created
  + resource &amp;quot;aws_s3_bucket_versioning&amp;quot; &amp;quot;this&amp;quot; {
...
Plan: 6 to add, 0 to change, 0 to destroy.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;搞 Terraform 的读者会看得出来，他似乎只做了 Plan，没有做实际的 Apply。&lt;/p&gt;

&lt;p&gt;文档解释说，默认情况下，资源的创建是需要被批准的，除非是使用了注解：&lt;code&gt;terraform.appvia.io/apply=true&lt;/code&gt;，所以我们现在加入这个：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-command&#34;&gt;$ kubectl annotate cloudresources bucket &amp;quot;terraform.appvia.io/apply&amp;quot;=true --overwrite
cloudresource.terraform.appvia.io/bucket annotated
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来会看到一个新的 Job 在运行，类似 &lt;code&gt;bucket-l6jkf-1-apply-xp45d&lt;/code&gt; 这样的名称。这个 Pod 运行成功之后，会看到 S3 桶已经创建。&lt;/p&gt;

&lt;h3 id=&#34;客户端&#34;&gt;客户端&lt;/h3&gt;

&lt;p&gt;Terranetes 还有个叫 &lt;code&gt;tnctl&lt;/code&gt; 的命令行客户端软件，提供了任务跟踪、审批等能力，避免大量使用 &lt;code&gt;kubectl&lt;/code&gt; 来完成这些任务。&lt;/p&gt;

&lt;h2 id=&#34;其他&#34;&gt;其他&lt;/h2&gt;

&lt;h3 id=&#34;偏差检测&#34;&gt;偏差检测&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;CloudResource&lt;/code&gt; 有个字段 &lt;code&gt;spec.enableDriftDetection&lt;/code&gt;，设置为 &lt;code&gt;True&lt;/code&gt; 就可以启动偏差检测。例如上面的 CloudResource，我们修改这个字段为 True 之后，删除对应的桶，一段时间之后，这个资源就会变成 &lt;code&gt;OutOfSync&lt;/code&gt; 状态。&lt;/p&gt;

&lt;h3 id=&#34;监控&#34;&gt;监控&lt;/h3&gt;

&lt;p&gt;Controller 自带了 Prometheus 的指标抓取端口，提供了请求数、延迟时间等简单的指标。&lt;/p&gt;

&lt;p&gt;除了这些基本功能之外，Terranetes 还能对接 &lt;code&gt;Infracost&lt;/code&gt; 进行成本数据采集和预测，不过这是个商业产品，就没有进一步尝试了。&lt;/p&gt;

&lt;p&gt;总之，Terranetes 提供了一个相对全面的框架，其中展示的工作流、策略、分权等设计，都是很好的范本，很值得工具平台、IaC 相关方案的设计者们参考和学习。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Crossplane vs Terraform</title>
      <link>/post/crossplane.vs.terraform/</link>
      <pubDate>Wed, 04 May 2022 15:12:39 +0800</pubDate>
      <guid>/post/crossplane.vs.terraform/</guid>
      <description>

&lt;p&gt;原文：&lt;a href=&#34;https://blog.crossplane.io/crossplane-vs-terraform/&#34; target=&#34;_blank&#34;&gt;Crossplane vs Terraform&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：&lt;a href=&#34;https://blog.crossplane.io/author/negz/&#34; target=&#34;_blank&#34;&gt;Nic Cope&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Crossplane 经常被拿来和 HashiCorp 的 Terraform 作比较。企业平台团队往往会在淘汰 Terraform 寻求替代品的过程中发现 Crossplane。这两个项目还是有些相似的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;这两个产品都支持工程师用声明式的配置来对基础设施进行建模&lt;/li&gt;
&lt;li&gt;它们都可以用 &lt;code&gt;Provider&lt;/code&gt; 的形式支持多种多样的基础设施&lt;/li&gt;
&lt;li&gt;这两个产品都是具有强大社区的开源工具&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;二者的最大区别在于，Crossplane 是一个控制平面，而 Terraform 是一个命令行工具——或者说是一个控制平面的界面。本文会谈到企业在规模化应用 Terraform 的时候遇到的诸多痛点，并阐明 Crossplane 的解决之道。&lt;/p&gt;

&lt;h2 id=&#34;协作&#34;&gt;协作&lt;/h2&gt;

&lt;p&gt;通常情况下，Terraform 是由运维团队引入企业的。对于较小的工程师团队来说，Terraform 是一个很好的基础设施治理方案。用声明式配置的方法来表达基础设施，运维团队就可以采用软件工程的最佳实践进行工作——用版本控制的方式对配置进行管理，并对变更进行评审，而且还能在必要的时候进行回滚。&lt;/p&gt;

&lt;p&gt;在较多工程师协作管理组织的基础设施的情况下，Terraform 就显得有些凌乱了。Terraform 依赖一个单体式的状态文件，以此在基础设施的目标状态和实际状态之间进行映射。在应用配置时，必须锁定状态文件，所以 Terraform 的配置应用过程可能会产生一个数分钟的阻塞。在这个阻塞时间内，配置被独占，其他工程师或者实体都无法进行变更。类似地，Terraform 使用了一个单体式的 &lt;code&gt;apply&lt;/code&gt; 进程——并没有什么最佳实践来完成在配置中只修改一部分基础设施的操作。如果缓存和数据库在同一个配置里，就只能同时更新，而无法仅仅更新缓存。&lt;/p&gt;

&lt;p&gt;Terraform 推荐把单体式的配置分离为小粒度的配置。运维团队可能从一个 &lt;code&gt;production&lt;/code&gt; 配置开始，然后被鼓励分为 &lt;code&gt;production billing&lt;/code&gt;、&lt;code&gt;production auth&lt;/code&gt; 等小配置。这很难一蹴而就，所以随着时间的推移，需要进行大量的重构，并可能产生网状依赖的 Terraform 配置，其输入和输出也可能产生耦合。&lt;/p&gt;

&lt;p&gt;Crossplane 的资源模型被称为 XRM（Crossplane Resource Model），这个模型具备松耦合以及最终一致性的特征，因此提高了规模化协作的能力。在 Crossplane 中，基础设施中的每一块都是一个支持增删改查的 API 端点。Crossplane 的变更不需要依赖关系图，所以用单个数据库也能够管理整个生产环境。&lt;/p&gt;

&lt;h2 id=&#34;自助服务&#34;&gt;自助服务&lt;/h2&gt;

&lt;p&gt;现代化组织的基础设施管理模式，正在从中心化向自助化演进。运维团队（也称为平台团队）对基础设施进行抽象，研发团队可以根据需求进行消费。Terraform 通过 &lt;code&gt;Module&lt;/code&gt; 这样类似软件库的形式来支持这种进化，Terraform 和 Crossplane 一样，其资源都是外部 API 资源的忠实再现。模块对资源的配置基础上进行了简化的抽象，例如 &lt;a href=&#34;https://registry.terraform.io/modules/terraform-aws-modules/rds/aws/latest&#34; target=&#34;_blank&#34;&gt;RDS 模块&lt;/a&gt; 用八个（现在是九个了） Terraform 资源来表达 RDS 实例的概念。&lt;/p&gt;

&lt;p&gt;把应用团队当做 Terraform 配置的消费者意味着他们就是 Terraform 协作的主体。应用开发者被邀请参与组织基础设施的协作，像运维团队一样。平台团队邀请应用开发团队参与他们的工作流，而不仅是给他们提供服务。也就是说，应用团队必须学习新的、特定目标的工具集和语言——Terraform and the HashiCorp Configuration Language（HCL）。对于应用开发者来说，配置的抽象程度提高了，但是访问控制的抽象并没有随之提高。平台团队可以发布一个模块，让应用团队可以管理 RDS 实例，访问控制还是存在于云供应商的 API 级别，围绕着 &lt;code&gt;database subnet groups&lt;/code&gt; 和 &lt;code&gt;database parameter groups&lt;/code&gt; 进行。&lt;/p&gt;

&lt;p&gt;和 Terraform 模块等价的 Crossplane 概念是一个符合对象-XR。每个 XR 都是一个 API 端点。平台团队需要给每个 XR 定义 OpenAPI 结构并输出文档，并在 API 级别实现 RBAC。这样平台团队如果供应给应用开发团队数据库实例，开发团队就有权进行增删改查，而无需关注底层的 RDS 实例和 Subnet 等概念了。Crossplane 构建在 Kubernetes RBAC 基础之上，平台团队能够用轻松地同一个控制平面支持多个应用团队。每个团队都只具备自己需要的权限——有的可能只需要管理存储桶、其他的可能有权使用缓存和数据库。&lt;/p&gt;

&lt;p&gt;不仅如此，Crossplane 的 XR 能提供多种服务，Crossplane 用 Kubernetes 对象 &lt;code&gt;spec&lt;/code&gt; 和 &lt;code&gt;status&lt;/code&gt; 的方式，把 XR 的输入输出和它的实现进行解耦。如果应用程序团队被授权创建 PostgreSQL，他们可以轻松地从平台团队已经兼容的数据库中进行选择。这些服务类别可以表达生产、预发布和开发；AWS、Azure 以及 GCP；快或慢；以及各种条件的组合。&lt;/p&gt;

&lt;h2 id=&#34;集成和自动化&#34;&gt;集成和自动化&lt;/h2&gt;

&lt;p&gt;Terraform 的背后是很多 API，但其自身并没有 API。所以很多团队的自动化方式就是：向版本管理系统（例如 GIT）提交 Terraform 配置的办法融入到 CI/CD 管线之中。这种方式自然要优于从自己的笔记本上运行 Terraform。但这种做法在规模扩张的时候会出现问题。Terraform 是一个命令行工具，而不是一个控制平面，他是短寿的、一次性的进程；所以他只能在调用期间，对基础设施进行面向期待状态的调谐。不管从 CI/CD 还是笔记本上运行，Terraform 一般都是在工程师需要对基础设施进行更新时被执行的。&lt;/p&gt;

&lt;p&gt;Terraform 保守的按需执行的方式，可能会导致一个死锁。如前所述，应用 Terraform 配置的过程是全有或者全无的——如果在同一个配置中对缓存和数据库进行描述，那么无论更新哪个对象，都需要同时更新这两个配置。这样一来，如果有人绕开了 Terraform（直接变更基础设施），那么接下来运行 Terraform 计划的人会发现，Terraform 要试图撤销前面的变更。想象一下，一个工程师在半夜被叫醒，处理一个现场问题，他通过 AWS 控制台对生产环境的缓存配置进行了修改，并忘记通知给 Terraform。因此就有一种可能：基础设施的变化越频繁，应用 Terraform 配置的风险就越大。&lt;/p&gt;

&lt;p&gt;而在 Crossplane 来说，他构建的是一系列的长期运行的、一直在线的控制循环。他会持续地对基础设施进行观察和矫正，以使环境符合预期。这样就一定程度上阻止了绕过 Crossplane 的企图。当 Crossplane 接管资源之后，所有在 Crossplane 之外修改资源的尝试都会被自动地、持续地修正回预期状态。&lt;/p&gt;

&lt;p&gt;不提供 API 是企业应用 Terraform 的一大痛点。和 Terraform 进行集成是一个挑战——他的 操作语言是面向特定领域的 HCL 语言，而且使用命令行工具进行调用。Crossplane 开放了 REST API，这无疑是对自动化更加友好。不管是用 Shell 脚本、Python、或者 Erlang，都有途径和 REST API 进行集成——也就是说和 Crossplane 进行集成。&lt;/p&gt;

&lt;p&gt;Crossplane 不会暴露旧的 REST API。在 Kubernetes API 的基础上进行构建的 Crossplane API，让团队可以用 &lt;code&gt;kubectl&lt;/code&gt; 的方式对所有云或非云的基础设施进行编排，这样就和编排容器化应用的方式保持了一致。Crossplane 还能用 Kubernetes Secret 的方式来表达应用连接基础设施的凭据，简化集成过程。它可以和 ArgoCD、Gatekeeper 或者 Velero 进行协作，来进行 GitOps、策略支持以及备份等工作。构建 Kubernetes Operator，和 Crossplane 集成，有利于建设可靠的自动化过程。&lt;/p&gt;

&lt;h2 id=&#34;鱼与熊掌&#34;&gt;鱼与熊掌&lt;/h2&gt;

&lt;p&gt;Crossplane 和 Terraform 都能够编排基础设施。二者有一定的相似之处，但具体的编排方式却迥然不同。Terraform 用命令行界面来管理底层控制平面的 API；而 Crossplane 自己就是一个控制平面，能够在其他控制平面上建设抽象的编排能力。因为 Crossplane 让平台团队能够提供自己的控制平面，从而避免了 Terraform 面临的很多问题。&lt;/p&gt;

&lt;p&gt;读者可能会注意到，这两个项目是互补的——Terraform 是控制平面的界面，并且它的 Kubernetes Provider 能够对 Kubernetes 控制平面进行管理。这也就产生了 Terraform 和 Crossplane 进行协作的可能性。假设你的组织偏爱 HCL 而非 YAML，那么就可以使用 Terraform 来对 XR 及其组合进行定义，而应用团队则可以使用 Terraform 来对 Crossplane 对象的期待状态进行编排。&lt;/p&gt;

&lt;p&gt;我们认为 Crossplane 方案让平台团队为应用开发者赋能，使得开发者能够自助管理基础设施。如果有兴趣&lt;a href=&#34;https://crossplane.io/docs&#34; target=&#34;_blank&#34;&gt;开始尝试 Crossplane&lt;/a&gt;，或者有问题或者反馈，可以&lt;a href=&#34;https://slack.crossplane.io/&#34; target=&#34;_blank&#34;&gt;通过 Slack 联系我们&lt;/a&gt;。&lt;/p&gt;

&lt;h2 id=&#34;相关链接&#34;&gt;相关链接&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Crossplane 文档：&lt;code&gt;https://crossplane.io/docs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Slack：&lt;code&gt;https://slack.crossplane.io/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
