Please enable Javascript to view the contents

如何使用 Terraform Provider 提供 Iac 级别的应用

 ·  ☕ 3 分钟

1. Terraform Vs Kubernetes

基础架构即代码(Iac) 基于不可变的基础架构,使用编排工具将基础架构文本化,允许像管理代码一样管理基础设施。

2018 年,我在从事 SaaS 开发,使用 Kubernetes 平台进行部署,这一年 Terraform 很火。2019 年,我开始从事 Kubernetes 的二次开发,才听说 Terraform 。现在网上 Terraform 相关的文档增量已经很少,更多是 Kubernetes 。

为什么我开始关注 Terraform ?因为测试 Kubernetes 经常需要创建大量集群。手工在 IaaS 的 GUI 创建 VM ,登陆部署是最低效的方式。我也尝试过使用 Jenkins 流水线部署 Kubernetes ,这得维护一台可靠的服务器。最后就关注到了 Terraform 。

Terraform 承载的是平台,而 Kubernetes 承载的是应用。

存储平台、监控平台、PaaS 平台、依赖于 Kubernetes 的平台、DevOps 平台等,需要考虑使用 VM 进行部署,减少架构上的复杂度,而用户服务的负载可以直接使用 Kubernetes 进行部署。目前,使用和运维 Kubernetes 的门槛并没有很低,强行 All in Kubernetes 而运维能力没有跟上,会导致更棘手的问题。以前服务只是慢,现在服务打不开 。

2. Terraform 的运行机制

编排工具的核心是定义一种 DSL 语言,用户使用 Outer DSL 语言描述流程,而编排工具实现 Inner DSL 对其解析,转换为具体执行动作。如下图:

Terraform 的 Outer DSL 是提供给用户编写的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
provider "cloud" {                                                                                                                                                      
    secret_id  = ""
    secret_key = ""
    region     = ""
}

data "cloud_image" "myimage" {
  os_name = "centos"
  ...
}

resource "cloud_instance" "my_app" {
  instance_name = "app1"
  ...
}

Terraform 的 Inner DSL 是开发者使用 Golang 实现的,由两部分组成,Core 和 Plugins 。Core 通过 RPC 与 Plugins 进行通信。

Plugins 插件负责领域实现,提供 Provider 。Core 负责解析 Outer DSL 、管理资源、管理构建、执行 plan。如下图:

3. 如何发布 Provider

Provider 主要是对领域的封装,直白点就是实现对 IaaS API 的封装。基于 Terraform 提供的 schema.Provider 实现鉴权、基于 schema.Resource 实现对 IaaS 资源的 CRUD 即可。

https://registry.terraform.io/ 提供了类似 DockerHub 的托管功能,在页面上可以找到相关基础设施的 Provider 和 Modules 。Provider 通常就是 IaaS ,Modules 就是基于 Provider 的一个组件、应用等。

  • 首先需要将 Provider 发布到 Github Release 。

主要分为如下几个步骤:

  1. 安装 goreleaser ,配置 .goreleaser.yml

直接拷贝 terraform-provider-scaffolding 中的 .goreleaser.yml 文件到项目根目录下。goreleaser 用于项目的发布,可以同时编译多个系统版本,并发布到 GitHub 上。

  1. 配置 GPG_FINGERPRINT

没有配置 GPG 的可以参考这篇文档,GPG 验证提交 。查看环境中的 GPG 全部秘钥:

1
2
3
gpg --list-keys

xxx(YOUR_GPG_ID)

设置环境变量:

1
export GPG_FINGERPRINT=xxx(YOUR_GPG_ID)

GPG_FINGERPRINT 指向了你所使用的某条 GPG 秘钥,也是下面需要在注册页面上输入的内容。

  1. 设置 GITHUB_TOKEN

打开 Github 的个人 配置页面 页面,勾选 public_repo 权限,生成 Token 之后:

1
export GITHUB_TOKEN=xxx
  1. 仓库打标签
1
git tag v1.2.6
  1. 发布 Release 版本
1
goreleaser release --rm-dist

最后在 Github 页面上看到是这样的效果:

如果使用 Github Action 自动进行发布,可以增加一个文件 `` :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
name: goreleaser

on:
  push:
    tags:
      - 'v*'

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/[email protected]
        with:
          fetch-depth: 0
      -
        name: Set up Go
        uses: actions/[email protected]
        with:
          go-version: 1.14
      -
        name: Import GPG key
        id: import_gpg
        uses: crazy-max/[email protected]
        env:
          GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
      -
        name: Run GoReleaser
        uses: goreleaser/[email protected]
        with:
          version: latest
          args: release --rm-dist
        env:
          GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
          GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}

RELEASE_TOKEN 就是上面的 GITHUB_TOKEN 值,而 GPG_PRIVATE_KEY 为下面命令的输出值:

1
2
3
gpg --list-keys

xxx(YOUR_GPG_ID)
gpg --export-secret-keys --armor  xxx(YOUR_GPG_ID)
  • 然后准备好 GPG 秘钥,在 https://registry.terraform.io/ 页面上,使用 Github 账户登陆,选择 Provider 仓库,发布一个 Provider 。发布之后的效果如下:

4. 如何使用 Provider Iac 应用

在目录下新增三个文件,var.tf 、platform.tf 、install.sh 。内容大致如下:

var.tf , 定义 provider 和全局变量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
terraform {
  required_providers {
    qingcloud = {
      source = "shaowenchen/qingcloud"
      version = "1.2.6"
    }
  }
}
variable "access_key" {
  default = "yourID"
}

variable "secret_key" {
  default = "yourSecret"
}

variable "zone" {
  default = "pek3a"
}

provider "qingcloud" {
  access_key = "${var.access_key}"
  secret_key = "${var.secret_key}"
  zone = "${var.zone}"
}

platform.tf ,定义 IaaS 相关的资源。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
resource "qingcloud_eip" ...
resource "qingcloud_security_group" ...
resource "qingcloud_security_group_rule" ...
resource "qingcloud_keypair" ...
resource "qingcloud_instance" ...
resource "null_resource" "install_platform" {
  provisioner "file" {
    destination = "./install.sh"
    source      = "./install.sh"

    connection {
      type        = "ssh"
      user        = "root"
      host        = "${qingcloud_eip.init.addr}"
      private_key = "${file("~/.ssh/id_rsa")}"
      port        = "22"
    }
  }
  provisioner "remote-exec" {
    inline = [
      "sh install.sh"
    ]
    connection {
      type        = "ssh"
      user        = "root"
      host        = "${qingcloud_eip.init.addr}"
      private_key = "${file("~/.ssh/id_rsa")}"
      port        = "22"
    }
  }

install.sh ,在指定的 IaaS 上安装平台应用。也可以将其封装成 module ,会更加清晰。

1
2
#!/usr/bin/env bash
# install your application

这些基础设施相关的配置文件,都需要使用 Git 进行存储和管理。每次需要创建时,只需要克隆下来,进入目录:

1
2
terraform init
terraform apply

即可创建对应的平台应用。而执行 terraform destroy 即可销毁创建的全部资源。

5. 参考


微信公众号
作者
微信公众号