基础设施即代码初探-开发Terraform Provider管理私有云MySQL实例

基础设施即代码(Infrastructure as Code, IaC)已经成为云时代DevOps实践中不可或缺的一环。通过代码来管理和配置基础设施,我们可以像开发软件一样,用工程化的方法来对待基础设施。在IaC领域,Terraform无疑是最流行的工具之一。

1

ada48eed886903dc363cc68610fc00eb.gif

Terraform和Provider简介

Terraform是一个用于安全高效地构建、更改和版本控制基础设施的工具。它通过一种声明式的语言(HCL)来描述基础设施的期望状态,然后根据这些描述自动化地创建和管理资源。

本质来说,Terraform是一个状态管理工具,对其管理的资源执行CRUD操作,被其托管的资源很多时候是基于云的,但是也可以用其托管其他资源,理论上能通过CRUD表达的任意资源都可以通过其托管。

在 Terraform 中,Provider 是 Terraform 的核心组件之一,用于抽象化与特定云服务或其他基础设施资源的交互。它是一种插件,充当了 Terraform 和外部系统之间的桥梁,允许 Terraform 管理、创建、修改和删除外部资源。每个Provider负责一类特定的资源,例如AWS Provider允许我们管理EC2实例、S3存储桶等AWS资源。Terraform通过丰富的Provider生态,支持管理几乎所有主流的云资源。

Provider的主要功能
1.资源管理

定义可以创建、修改和删除的资源类型。

2.数据源查询

定义只读的数据源,用于从外部系统获取信息。

3.状态同步

Provider 通过 API 调用获取资源的当前状态,与 Terraform 的状态文件保持一致。

虽然Terraform内置了丰富的Provider支持,但在某些场景下,标准Provider可能无法满足业务需求。这时,开发一个自定义的Provider成为了解决问题的关键手段。

那么,什么情况下我们需要创建一个自定义的Provider呢?

  • 支持自定义资源:如果你的基础设施中包含了一些自定义资源或服务(例如内部开发的私有云平台、专有 API 或者公司特定的工具),而这些资源并未被官方提供的 Terraform Providers 支持,那么开发一个自定义 Provider 就可以将这些资源纳入基础设施即代码(IaC)的管理中。

  • 服务开放:如果你的服务未来要面向外部客户开放,一个自定义 Provider 可以作为基础设施自动化的重要组成部分,方便客户通过 Terraform 集成你的服务。

  • 扩展现有Provider:如果现有的Provider 并未满足你的需求(例如,缺少某些资源类型的支持,或者对资源的操作不够灵活),通过自定义 Provider 可以对其进行扩展。


2

f349f4d90add6fab4065e0d6fca5ce16.gif

开发自定义Provider

在开始进入这个主题之前,我们先了解下Provider的整个工作流程:

459f3838a44f69c0465eda83833cabcc.png

可以看到,Provider就是连接Terraform和具体服务API的桥梁。如果我们想要实现一个管理私有云MySQL的Provider,其实调用的也是我们私有云自己的API,只是Terraform和Provider帮助了使用Terraform的用户摆脱了自己对接私有云API的繁琐步骤。

由此,我们也可以知道,如果我们要开发一个Provider,其实本质上就是完成对Terraform Provider的接口适配。

目前,HashiCorp提供了两个用于开发 Terraform Provider 的SDK,Terraform Plugin FrameworkTerraform Plugin SDK ,Terraform Plugin Framework是 HashiCorp 官方推荐的新一代开发框架,设计更现代化,并且基于 Go Context 和 gRPC,强调扩展性和模块化,支持更细粒度的控制,提供更好的类型安全支持。所以本文将采用Terraform Plugin Framework来进行Provider的开发,也推荐所有新的Provider都采用官方的新框架。

1. 环境要求

1.Go 1.21+

2.Terraform v1.8+

3.自己的私有云API服务(或者任意你想对接的资源API都可以)

2. Provider的资源定义

任何Terraform Provider的主要目的都是为Terraform提供资源,资源主要有两种—resource(也可以称为托管资源)以及data sources(也可以称为数据源)。托管资源,通过实现创建、读取、更新和删除(CRUD)方法,支持完整的生命周期管理。而数据源则相对简单,仅实现了CRUD中的读取(Read)部分。当然,也有一种比较特殊的资源定义,也就是Provider本身。让我们用aws的配置来举例:

  1. Provider 定义

  • provider 块用来配置与具体服务的交互方式。

  • 常见的配置项包括认证信息、API 地址、默认区域等。

 
 
provider "aws" {
  region = "us-east-1"
  access_key = "your_access_key"
  secret_key = "your_secret_key"
}
  1. Resource 定义(以aws s3举例)

resource 块用于定义由 Provider 管理的具体资源,这些资源可以进行全部的CRUD操作。

 
 
resource "aws_s3_bucket" "example_bucket" {
  bucket = "my-example-bucket"
  acl    = "private"


  tags = {
    Name        = "My bucket"
    Environment = "Dev"
  }
}

3.Data Sources定义(以aws s3举例)

data 块主要用来定义一些外部服务的现有资源,而不是再去创建新资源。

 
 
data "aws_s3_bucket" "existing_bucket" {
  bucket = "existing-bucket-name"
}

通过以上关于资源的定义,大概可以理出一个Provider的开发顺序,首先进行provider块部分相关的开发,然后进行resource/data块相关的开发。

2. provider结构设计

首先,我们看下官方的SDK中对于provider的接口定义:

 
 
type Provider interface {
  // Metadata should return the metadata for the provider, such as
  // a type name and version data.
  //
  // Implementing the MetadataResponse.TypeName will populate the
  // datasource.MetadataRequest.ProviderTypeName and
  // resource.MetadataRequest.ProviderTypeName fields automatically.
  Metadata(context.Context, MetadataRequest, *MetadataResponse)


  // Schema should return the schema for this provider.
  Schema(context.Context, SchemaRequest, *SchemaResponse)


  // Configure is called at the beginning of the provider lifecycle, when
  // Terraform sends to the provider the values the user specified in the
  // provider configuration block. These are supplied in the
  // ConfigureProviderRequest argument.
  // Values from provider configuration are often used to initialise an
  // API client, which should be stored on the struct implementing the
  // Provider interface.
  Configure(context.Context, ConfigureRequest, *ConfigureResponse)


  // DataSources returns a slice of functions to instantiate each DataSource
  // implementation.
  //
  // The data source type name is determined by the DataSource implementing
  // the Metadata method. All data sources must have unique names.
  DataSources(context.Context) []func() datasource.DataSource


  // Resources returns a slice of functions to instantiate each Resource
  // implementation.
  //
  // The resource type name is determined by the Resource implementing
  // the Metadata method. All resources must have unique names.
  Resources(context.Context) []func() resource.Resource
}

可以看到,如果我们需要实现这个接口,需要实现Metadata,Schema,Configure,DataSources,Resources这几个方法。

Metadata 方法用于提供当前 Provider 的元数据信息,例如类型名称(TypeName)和版本等。这些信息可以用于识别 Provider,或者在需要与 Terraform 核心交互时使用。

Schema 方法用于定义 Provider 的配置结构。例如,用户在 Terraform 中配置 Provider 的时候,可能需要指定 API 的凭证或目标地址。这些配置信息通过此方法定义。

Configure 方法用于初始化 Provider 的运行环境。通常会解析用户配置的参数(例如凭证或其他必要的初始化信息),并生成一个客户端实例或其他相关的资源。

DataSources 方法返回 Provider 支持的所有数据源类型。每个数据源用于从外部系统(如 API)中读取数据并将其提供给 Terraform。

Resources 方法返回 Provider 支持的所有托管资源类型。每个资源代表 Terraform 可以管理的一个实体,例如云服务中的虚拟机、数据库实例等。

第一步,先想下我们的Schema怎么实现。我们已经知道,Schema方法用于定义 Provider 的配置结构,因为本文的例子是要开发一个管理私有云MySQL的Provider,所以我们对接的API服务就是智汇云的OpenAPI。通过智汇云的OpenAPI文档,我们已知,如果要与其进行交互,需要Endpoint,AccessKeyId,AccessKeySecret这些信息,所以我们的Schema其实就是这些信息的一个结构化。

这个接口的定义我们放在provider.go这个文件中实现,以下是这个文件的部分代码。

 
 
// Ensure the implementation satisfies the expected interfaces.
var (
  _ provider.Provider = &ZyunDbProvider{}
)


// New is a helper function to simplify provider server and testing implementation.
func New(version string) func() provider.Provider {
  return func() provider.Provider {
    return &ZyunDbProvider{
      version: version,
    }
  }
}


// ZyunDbProvider defines the provider implementation.
type ZyunDbProvider struct {
  // version is set to the provider version on release, "dev" when the
  // provider is built and ran locally, and "test" when running acceptance
  // testing.
  version string
}


// Metadata returns the provider type name.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值