在本地实现一个最简单的 Terraform Provider

前言

Terraform 是一种开源工具,用于安全高效地预览,配置和管理云基础架构和资源。在笔者看来,Terraform 最大的优势在于"万物统一",所有的资源都能够通过编写 HCL 配置文件统一纳管。

Terraform 官方提供了一个框架,而具体的实现由各家厂商接入的 Provider 决定,这就大幅降低了推广成本。如下图所示,当用户执行 terraform cli 命令的时候,与 terraform provider 交互,terraform provider 再去调用云上 OpenAPI。换言之,Terraform 是个插座,各个 Provider 是插在插座上的插头,只要满足插口的规范就能接入进去。

本文关注点在于带着读者快速实现一个最简单的 Provider(无需部署,无需编写 chart 包,也无需上传到仓库),保证读者能够在本地 run 起来,并做适当的代码解释。毕竟笔者一直认为对于初学者而言,建立自信心是很重要的。而对于 Terraform 的高级用法、核心原理,笔者会后后续的文章中提到。

快速实现 Provider

开发环境

yaml 复制代码
Golang: 1.19
系统:Mac OS
开发工具:GoLand
Terraform:1.5.7

快速 Run 起来

代码(无脑复制)

首先进入到 main.go,调用 terraform 官方 sdk,启动监听服务。

Golang 复制代码
package main

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

func main() {
   plugin.Serve(&plugin.ServeOpts{
      ProviderFunc: func() terraform.ResourceProvider {
         return Provider()
      },
   })
}

其次,实现 provider.go 逻辑,定义资源 example_server。

Golang 复制代码
package main

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

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

最后,编写 resource_server.go,实现增删改查的逻辑。

Golang 复制代码
package main

import (
   "fmt"

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

func resourceServer() *schema.Resource {
   return &schema.Resource{
      Create: resourceServerCreate,
      Read:   resourceServerRead,
      Update: resourceServerUpdate,
      Delete: resourceServerDelete,

      Schema: map[string]*schema.Schema{
         "name": &schema.Schema{
            Type:     schema.TypeString,
            Required: true,
         },
      },
   }
}

func resourceServerCreate(d *schema.ResourceData, m interface{}) error {
   name := d.Get("name").(string)
   d.SetId(name)
   println(fmt.Sprintf("start to create resource %s.", name))
   return resourceServerRead(d, m)
}

func resourceServerRead(d *schema.ResourceData, m interface{}) error {
   name := d.Get("name").(string)
   println(fmt.Sprintf("start to read resource %s.", name))
   return nil
}

func resourceServerUpdate(d *schema.ResourceData, m interface{}) error {
   name := d.Get("name").(string)
   println(fmt.Sprintf("start to update resource %s.", name))
   return resourceServerRead(d, m)
}

func resourceServerDelete(d *schema.ResourceData, m interface{}) error {
   name := d.Get("name").(string)
   println(fmt.Sprintf("start to delete resource %s.", name))
   return nil
}

到这儿后,代码部分已经结束了。代码结构如下。

go 复制代码
- main.go
  provider.go
  resource_server.go

本地跑起来

代码完成后,来看下怎么在本地 run 起来。 首先打包成二进制。

shell 复制代码
go mod init
go mod tidy
go build -o terraform-provider-example

将二进制文件复制到指定路径,因为本地是 mac,所以路径为 darwin_arm64。

shell 复制代码
cp terraform-provider-example ~/.terraform.d/plugins/terraform-example.com/exampleprovider/example/1.0.0/darwin_arm64/

编写 main.tf

HCL 复制代码
terraform {
  required_providers {
    example = {
      version = "~> 1.0.0"
      source  = "terraform-example.com/exampleprovider/example"
    }
  }
}

resource "example_server" "my-server-name" {
  name = "2"
}

执行 terraform init、terraform plan 和 terraform apply。

简单解释下代码

上文已经给出了快速在本地 run 起来的方法,如果没有 run 起来,欢迎评论。

那么本章就来简单解释下代码,具体的 terraform 原理后续文章会补上。

首先,来看 provider.go 文件,里面 ResourcesMap 定义了资源类型,比如这里的 example_server。用户在使用的时候需要在 tf 文件里面将类型定义为 example_server。

Golang 复制代码
ResourcesMap: map[string]*schema.Resource{
   "example_server": resourceServer(),
}

其次,再来看下 resource_server.go。这里实现了增删改查的主逻辑,并且定义了 Schema,也就是字段名称。

Golang 复制代码
func resourceServer() *schema.Resource {
   return &schema.Resource{
      Create: resourceServerCreate,
      Read:   resourceServerRead,
      Update: resourceServerUpdate,
      Delete: resourceServerDelete,

      Schema: map[string]*schema.Schema{
         "name": &schema.Schema{
            Type:     schema.TypeString,
            Required: true,
         },
      },
   }
}

这样在后续逻辑中可以获取用户输入的 "name"。

Golang 复制代码
name := d.Get("name").(string)

同样在创建函数输出了 id 字段,会显示在最终 state 中。

Golang 复制代码
d.SetId(name)

结语

好啦,快速入门实现 terraform provider 到此为止了,遇到问题欢迎在评论区讨论。

相关推荐
科学熊5 分钟前
kubekey安装工具快速安装k8s集群
云原生·容器·kubernetes
半桔15 分钟前
【高并发架构】从 0 到亿,从单机部署到 K8s 编排:高并发架构的 8 级演进之路
linux·云原生·容器·架构·kubernetes
柠檬汁Dev1 天前
如何用云原生开发,把新项目启动从1天缩短到3分钟
云原生
汪碧康1 天前
【k8s-1.34.2安装部署】二.kubernets软件、证书、配置、脚本等文件准备
云原生·容器·kubernetes·xkube·k8s管理平台·k8s安装部署·k8s dashboard
ldj20201 天前
docker-compose对比k8s
云原生·容器·kubernetes
啊勇的编程论坛1 天前
DeepSeek + Kubernetes 全栈运维赋能指南:智能化云原生运维新时代
运维·云原生·容器·kubernetes·云运维
摆烂z1 天前
k8s环境脚本
云原生·容器·kubernetes
没有bug.的程序员1 天前
Sentinel 流控原理深度解析:从SlotChain到热点参数限流的设计哲学
jvm·微服务·云原生·eureka·sentinel·服务发现
阿里云云原生1 天前
RUM 助力 iOS 应用稳定性:从异常捕获到堆栈还原的全流程分析
人工智能·阿里云·ios·云原生·rum
VermiliEiz1 天前
二进制文件方式部署k8s(3)
云原生·容器·kubernetes·containerd