【翻译】如何在Terraform中开发一个自定义提供者

Saravan Gnanaguru最初发表在InfraCloud的博客上的客座文章

Terraform介绍和概述

Terraform是一种基础设施即代码的技术,它被用来创建不可改变的基础设施。它允许基础设施以一种简单的、人类可读的语言HCL(HashiCorp Configuration Language)来表达代码。它支持管理所有主要云供应商的资源。Terraform用于创建、管理和更新基础设施资源,如物理机、虚拟机、网络交换机、容器、Kubernetes等。几乎任何基础设施类型都可以在Terraform中表现为资源。

  • 使用Terraform的声明式.tf配置文件,将基础设施作为代码交付。
  • 计划和预测变化。Terraform为操作者提供了优雅的用户体验,使其能够安全、可预测地对基础设施进行修改。它读取配置文件,并提供更改的执行计划,可以审查其安全性,然后应用和配置。
  • 可扩展的供应商使Terraform能够管理广泛的资源,包括IaaS、PaaS、SaaS和硬件服务。
  • 创建可重复的基础设施。Terraform使类似基础设施的配置易于重复使用,有助于避免错误并节省时间。

这篇文章是为那些对Terraform及其使用有基本了解,并可能愿意开发自定义Terraform提供者的用户准备的。让我们开始吧!

什么是Terraform提供程序?

使用Terraform创建和维护资源依赖于被称为提供者的插件。每个提供者插件负责与云供应商、SaaS供应商和其他API进行交互。大多数供应商配置特定的基础设施平台(无论是云还是自我托管的)。提供商还可以提供本地的实用程序,以完成诸如为独特的资源名称生成随机数字的任务。

每个供应商都会增加一组资源类型和/或Terraform可以管理的数据源。每种资源类型都由提供者实现;没有提供者,Terraform就不能管理任何类型的基础设施。Terraform提供者不仅可以为云计算基础设施提供扩展性,而且还可以管理通过暴露的API调用创建的对象。

Terraform自定义提供者

以下是编写自定义Terraform提供者的一些可能的情况,例如。

  • 内部私有云,其功能是专有的或对开源社区无益。
  • 一个 "正在进行中 "的提供者,在向注册中心贡献之前在本地进行测试。
  • 现有提供商的扩展。

Terraform和提供商插件如何工作?

根据Terraform文档

Terraform核心

Terraform核心是一个用Go编程语言编写的静态编译的二进制文件。编译后的二进制文件是命令行工具(CLI)terraform,这是任何人使用Terraform的入口。

Terraform核心的主要职责是。

  • 基础设施即代码:读取和插值配置文件和模块
  • 资源状态管理
  • 资源图谱的构建
  • 计划的执行
  • 通过RPC与插件进行通信

Terraform插件

Terraform插件是用Go语言编写的,是由Terraform核心通过RPC调用的可执行二进制文件。

Terraform Provider Plug-in Design源于此。Terraform文档

每个插件都为特定的服务提供一个实现,例如。AWS,或供应者,如bash。Terraform配置中使用的所有供应商和供应者都被称为插件。Terraform核心提供了一个高层次的框架,抽象出了插件发现和RPC通信的细节,所以开发者不需要管理这些细节。

提供者插件的主要职责是。

  • 初始化任何用于进行API调用的内置库。
  • 与基础设施提供者进行认证。
  • 定义映射到特定服务的资源

供给者插件的主要职责是:。

  • 在创建后或销毁时对指定的资源执行命令或脚本。

请注意,我们的文章重点是如何开发供应者插件

Terraform CLI文件和供应者插件的安装

Terraform 0.13+使用.terraformrcCLI配置文件来处理提供者的安装行为。因此,我们需要在$HOME/.terraformrc路径下创建配置文件,并添加以下内容。

plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"
disable_checkpoint = true

有两种方法可以进行提供者的安装(从Terraform 0.13+开始)。

显式安装方法
CLI配置中的提供者_installation块允许覆盖Terraform的默认安装行为,因此你可以强制Terraform为你打算使用的部分或全部提供者使用本地镜像。在显式安装方法中,我们需要有一个提供者_installation块。

隐式本地镜像方法
如果CLI配置文件中没有provider_installation块,那么Terraform会产生一个隐式配置。

我们将使用隐式本地镜像方法来安装我们的自定义提供者。

Terraform init的默认行为,通常是试图从互联网上的Terraform注册表中下载提供者。由于我们模仿的是自定义提供者的情况,我们可以用隐式方法覆盖这一行为。使用隐式方法,Terraform将隐式地尝试在Linux系统的插件目录~/.terraform.d/plugins和Windows系统的%APPDATA%\terraform.d\plugins中找到提供者。

开发自定义提供程序需要什么条件?

  1. 只要有基本的Go开发知识就可以开始了。
  2. 服务提供者公开的API细节,用于管理资源。

如何安装和配置Terraform

请参考这里来安装Terraform

Windows。

  • 下载并提取Terraform的可执行文件
  • 在ENV PATH变量中添加Terraform可执行路径

在Linux系统中,提取并复制Terraform的可执行文件到/usr/bin路径中,以便在任何目录下执行它。

安装Go并设置开发环境

按照Go官方网站中提到的Go安装步骤,开始使用Go。

自定义提供者的源代码细节

进入$HOME/go/src路径并创建代码。

cd $HOME/go/src
mkdir tf_custom_provider 

自定义提供者所需的源文件是。

  • main.go
  • provider.go
  • resource_server.go

代码布局看起来像这样。

.
├── main.go
├── provider.go
├── resource_server.go

提供者的功能

我们将创建一个具有以下功能的提供者。由于这将是一个例子,我们将模拟Terraform资源的创建和删除功能。我们还将利用随机UUID生成器API,并将其作为创建功能的一部分加入,以显示调用API的能力。该API可以在以后进行修改,为云提供商、预置服务提供商或任何作为服务提供商的API提供实际的资源创建API。

main.go

Go的入口点函数是main.go

// main.go
包main

输入 (
        "github.com/hashicorp/terraform-plugin-sdk/plugin"
        "github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func main() {
        plugin.Serve(&plugin.ServeOpts{)
                ProviderFunc: func() terraform.ResourceProvider {
                        返回Provider()
                },
        })
}
provider.go

provider.go将有资源服务器的函数调用。

// provider.go
包main

输入 (
        "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func Provider() *schema.Provider {
        返回 &schema.Provider{
                ResourcesMap: map[string]*schema.Resource{
                     "example_server": resourceServer(),
                },
        }
}
resource_server.go

所有的资源创建都必须在resource_server.go中进行编码。这个文件将有资源功能声明和定义,如创建、删除等,它也会获得创建资源所需的输入参数。

作为本示例提供者的一部分,资源服务器具有以下功能。

  • 创建
  • 删除
// resource_server.go
包main

输入 (
        "net/http"
        "日志"
        "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceServer() *schema.Resource {
        返回 &schema.Resource{
                Create: resourceServerCreate,
                读取: resourceServerRead,
                更新: resourceServerUpdate,
                删除:resourceServerDelete。

                模式:map[string]*schema.Schema{
                        "uuid_count": &schema.Schema{
                                类型:schema.TypeString。
                                需要: true,
                        },
                },
        }
}

func resourceServerCreate(d *schema.ResourceData, m interface{}) error {
        uuid_count := d.Get("uuid_count"). (string)

        d.SetId(uuid_count)

       // https://www.uuidtools.com/api/generate/v1/count/uuid_count
        resp, err := http.Get("https://www.uuidtools.com/api/generate/v1/count/" + uuid_count)
        if err != nil {
                log.Fatal(err)
        }
        defer resp.Body.Close()

        返回 resourceServerRead(d, m)
}

func resourceServerRead(d *schema.ResourceData, m interface{}) error {
        返回 nil
}

func resourceServerUpdate(d *schema.ResourceData, m interface{}) error {
        返回 resourceServerRead(d, m)
}

func resourceServerDelete(d *schema.ResourceData, m interface{}) error {
        d.SetId("")
        返回nil
}

我们的示例代码为名为 "exampleprovider "的提供者实现了模拟资源创建。在实际执行中,必须将其改为各自云或企业内部服务器的提供者名称。大多数供应商都有API调用,用于资源操作,如创建/更新/删除等。因此,我们需要定义资源操作的逻辑,如使用自定义提供者的API调用来创建和删除,以应用Terraform模板。

resource_server.go中加入资源操作的逻辑后,我们的自定义提供者就可以开始测试了。

构建自定义提供者的代码

go mod init
转到fmt
转到mod tidy
去构建 -o terraform-provider-example

将提供者的可执行文件复制到插件目录的步骤

为了复制和使用我们创建的自定义提供者,我们需要在plugins目录下创建以下目录结构。

  • 基于Linux的系统 -~/.terraform.d/plugins/${host_name}/${namespace}/${type}/${version}/${target}
  • Windows系统%APPDATA%\terraform.d\plugins\${host_name}/${namespace}/${type}/${version}/${target}

其中。

  • host_name-> somehostname.com
  • namespace-> 自定义提供者名称空间
  • type-> 自定义提供者类型
  • version-> 提供者的语义版本(例如:1.0.0)。
  • target-> 目标操作系统

我们的定制提供程序应放在如下目录中。

~/.terraform.d/plugins/terraform-example.com/exampleprovider/example/1.0.0/linux_amd64/terraform-provider-example

因此,作为第一步,我们需要创建这个目录作为我们提供者安装的一部分。

mkdir -p ~/.terraform.d/plugins/terraform-example.com/exampleprovider/example/1.0.0/linux_amd64

然后,将terraform-provider-example二进制文件复制到该位置。

cp terraform-provider-example ~/.terraform.d/plugins/terraform-example.com/exampleprovider/example/1.0.0/linux_amd64

创建Terraform.tf文件

让我们通过提供资源输入,创建main.tf来测试该提供者。为了演示的目的,我们添加了服务器数量(uuid_count)作为一个输入参数。

main.tf

创建带有代码的main.tf文件,以创建自定义提供者资源。

资源 "example_server" "my-server-name" {
	uuid_count = "1"
}

version.tf

创建一个名为versions.tf的文件,并添加自定义提供者名称和版本的路径。

Terraform {
  所需供应商 {
    示例 = {
      版本 = "~> 1.0.0"
      来源 = "terraform-example.com/exampleprovider/example"
    }
  }
}

测试提供者和输出值

执行以下Terraform命令,以验证我们添加的自定义提供者的功能。

Terraform初始化

当我们运行terraform init命令时,Terraform核心会从本地路径获取提供者插件,因为我们已经在version.tf文件中配置了提供者。在Terraform初始化过程中,定制的提供者已经被缓存到~/.terraform.d/plugin-cache目录中,以便在下次运行时重新使用该提供者。

$ terraform init

初始化后端...

初始化提供者的插件...
- 寻找与"~> 1.0.0 "相匹配的terraform-example.com/exampleprovider/example版本...
- 使用共享缓存目录中的terraform-example.com/exampleprovider/example v1.0.0。

Terraform创建了一个锁文件.terraform.lock.hcl,以记录上面的提供者
的选择。在你的版本控制库中包括这个文件
这样,Terraform就可以保证在运行 "terraform init "时,默认做出同样的选择。
运行 "terraform init "时,可以保证做出同样的选择。

Terraform已经成功初始化了!

你现在可以开始使用Terraform。尝试运行 "terraform plan",查看
你的基础设施需要的任何变化。所有的Terraform命令
现在应该可以工作了。

如果你曾经为Terraform设置或改变模块或后台配置。
重新运行这个命令,重新初始化你的工作目录。如果你忘记了,其他
命令会检测到它,并在必要时提醒你这样做。

Terraform计划

Terraform plan命令,使用main.tf文件中定义的服务器定义。

$ terraform plan

Terraform使用选定的提供者,生成以下执行计划。资源行动用以下符号表示。
  + 创建

Terraform将执行以下行动。

 # example_server.my-server-name将被创建
 + 资源 "example_server" "my-server-name" {
      + id = (应用后已知)
      + uuid_count = "1"
    }

计划。1添加,0改变,0销毁。

Terraform应用

Terraform apply命令调用resourceServerCreate函数,我们已经在resource_server.go文件中定义了这个函数。

$ terraform apply -auto-approve=true

Terraform使用选定的提供者,生成以下执行计划。资源行动用以下符号表示。
  + 创建

Terraform将执行以下行动。

 # example_server.my-server-name将被创建
 + 资源 "example_server" "my-server-name" {
      + id = (应用后已知)
      + uuid_count = "1"
    }

计划。1添加,0改变,0销毁。
example_server.my-server-name:创建......。
example_server.my-server-name: 0秒后创建完成 [id=1]

应用完成!资源。1个添加,0个改变,0个销毁。

清理完毕

Terraform destroy

Terraform destroy命令调用resourceServerDelete函数,我们已经在resource_server.go文件中定义了这个函数。

$ terraform destroy -auto-approve=true
example_server.my-server-name:正在刷新状态...[id=1]。

Terraform使用所选的提供者来生成以下执行计划。资源动作用以下符号表示。
  - 销毁

Terraform将执行以下行动。

 # example_server.my-server-name将被销毁
 - 资源 "example_server" "my-server-name" {
      - id = "1" -> null
      - uuid_count = "1" -> null
    }

计划。0添加,0改变,1销毁。
example_server.my-server-name: 正在销毁...[id=1]
example_server.my-server-name:0秒后销毁完毕

销毁完成!资源。1个被销毁。

结论

在这篇技术博文中,我们涵盖了以下的主题。

  • Terraform提供者如何工作。
  • 什么是Terraform自定义提供者。
  • 创建和建立一个Terraform提供器的例子的步骤。
  • 使用自定义提供者的步骤。
  • 调用Terraform CLI命令时发生了什么。

本文的读者可以使用上面给出的示例代码,用自己的API修改API调用,以管理自己的资源。此外,这里还有GitHub repo的源代码链接。希望你喜欢这篇文章,如果你有任何疑问或反馈,让我们在LinkedIn上联系并开始对话。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值