加速 Terraform init

前言

Terraform 是开源的,用于资源编排管理的自动化工具。 Infrastructure as Code ,以代码的形式将所要管理的资源定义在模板中,通过解析并执行模板来自动化完成所定义资源的创建、变更和管理。

相信绝大多数云上用户对其已经不再陌生,并且越来越多的公司和开发者已经开始使用 Terraform 来编排管理他们的云资源基础设施。更多的 Terraform 使用,我们可以参考玩转阿里云 Terraform 系列文章

其中 Terraform 提供了很多 Providers 供用户使用,当然也包括阿里云 Provider。Terraform 通过 Provider 来完成对基础设施资源的管理。不同的基础设施提供商都需要提供一个 Provider 来实现对自家基础设施的统一管理。目前,Terraform 累计提供了超过 200 个 Providers。因此 Terraform 可以通过一致的流程以及 Provider 机制来帮助用户进行高效便利的多云管理。

我们编写 Terraform 模板,配置了 Provider,定义好编排配置后,第一步一定是执行 terraform init 命令,来初始化一些后续操作需要用到的设置和数据,包括自动下载我们使用到的 Provider。

但是对于国内用户来说,由于 Terraform Provider 并没有国内源,所以 terraform init 时下载 Provider 就成了耗时严重的环节,随便一个 Provder 动辄 3 分钟以上的下载时间,严重影响了我们的效率,更不要说一个完整的 Terraform 模板可能需要用到多个 Provider 了。

因此,我们需要考虑如何加速 terraform init,即加速 Provider 的下载。

目前阿里云 Cloud Shell 已经进行了 terraform init 的加速,原来动辄数分钟的 init 过程现在只需要几秒中。同时我们可以在 Cloud Shell 中直观的体验 Terrafrom 的教程:使用 Terraform 管理云资源

Provider Cache

默认情况下,terraform init 会将 Provider 下载到当前工作目录的子目录 .terraform/plugins/ 中,以便保证每个工作目录都是独立的。我们可以开始 Provider 的缓存,Provider 会优先读取缓存,缓存没有命中的才会进行下载,保证每个相同版本的 Provider 只会下载一次。

开启方式有两种,我们可以修改 Terraform 的配置文件,在配置文件 ~/.terraformrc 中增加 plugin_cache_dir 的设置。

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

或者通过环境变量的方式来进行设置。

export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"

需要注意的是,缓存目录必须存在,Terraform 不会为我们自动创建目录,因此不存在的话需要自行创建。同时,一旦 Provider 进行缓存,Terraform 不会自行删除它。随着 Provider 的升级,老的未使用的版本我们可能需要手动删除。

使用缓存可以极大的解决我们后续使用时的速度问题,但是一旦需要使用新的 Provider,或者升级 Provider,首次的下载时间依然很慢,不论是 Terraform 自动下载,还是我们手动下载然后放到缓存目录中。尤其是多人协作的云端环境中,提升执行速度的同时,还要兼顾 Provider 更新的及时性。

设置 Provider Host

另一种比较 Hack 的方式,是设置 Provider Host。首先我们需要了解 terraform init 时,下载 Provider 的流程。

加速 Terraform init

可以看到 Terraform 会通过请求 https://registry.terraform.io/v1/providers/-/${provider}/versions 获取 Provider 的版本信息,以 Aliyun Provider 为例,请求结果为:

{
  "id": "hashicorp/alicloud",
  "versions": [
    {
      "version": "1.17.0",
      "protocols": ["4"],
      "platforms": [
        {
          "os": "linux",
          "arch": "amd64"
        },
        ...
      ]
    },
    ...
  ]
}

如果我们指定的 Provider 版本存在(没有指定,则取最新的版本),Terraform 会请求 https://registry.terraform.io/v1/providers/hashicorp/${provider}/${version}/download/${os}/${arch} 获取该版本的信息。以64 位 linux 系统上的 Aliyun Provider 1.58.1 为例,请求结果为:

{
    "protocols": ["4.0","5.0"],
    "os": "linux",
    "arch": "amd64",
    "download_url": "https://releases.hashicorp.com/terraform-provider-alicloud/1.58.1/terraform-provider-alicloud_1.58.1_linux_amd64.zip",
    "shasums_url": "https://releases.hashicorp.com/terraform-provider-alicloud/1.58.1/terraform-provider-alicloud_1.58.1_SHA256SUMS",
    "shasums_signature_url": "https://releases.hashicorp.com/terraform-provider-alicloud/1.58.1/terraform-provider-alicloud_1.58.1_SHA256SUMS.sig",
    "shasum": "f1af67c5bc068960f1726fe43bb8c2bd485140274fbe4e036dc52d50a7da329f",
    "signing_keys": {
        "gpg_public_keys": [
            {
                "ascii_armor": "...",
                "source": "HashiCorp",
                "source_url": "https://www.hashicorp.com/security.html"
            }
    ]
  }
}

其中包含 Provider 和 shasum 的下载地址。Terraform 会通过返回的下载地址下载 Provider,同时通过 shasum 校验文件完整性。

因此,我们可以将从 registry.terraform.io 这个 Provider Host 获取 Provider 元信息的请求指向我们自己的 Provider Service,然后在 Terraform 获取指定版本 Provider 信息时,将 Provider 的下载地址 download_url 修改为我们自己维护的 Provider 下载源,配合 Provider Cache,保证任何时候,terraform init 都可以快速的执行。

Terraform v0.12 已经提供了修改 Provider Host 的方式,修改配置文件 ~/.terraformrc,增加配置:

host "registry.terraform.io" {
    services = {
      "modules.v1" = "http://your-mirror.example.com/v1/modules/",
      "providers.v1" = "http://your-mirror.example.com/v1/providers/"
    }
  }

如此,就可以将原本请求 registry.terraform.io 获取 Provider 元信息的请求,修改为请求我们自己的服务。

需要注意的是,modules.v1 需要同时显示定义,如果你不想修改它,则可以继续设置为官方的 https://registry.terraform.io/v1/modules/

我们可以通过阿里云的函数计算作为我们的自定义的 Provider Service,函数计算提供了 HTTP 触发器,让我们的函数服务对外提供 HTTP 服务。同时我们可以使用 OSS 作为我们自己的 Provider 镜像源,然后定时同步官方的 Provider 到我们的 OSS 中,保证 Provider 的持续更新。其中我们可以使用逻辑编排来轻松的编排我们的同步任务。

最后

目前阿里云 Cloud Shell 已经进行了 terraform init 的加速,原来动辄数分钟的 init 过程缩短到了几秒钟。同时你还可以通过教程学习如何使用 Terraform 管理云资源

上一篇:Android——Broadcast Receive 相关知识总结贴


下一篇:关于HTML5、Jquery、Phonegap跨域问题的研究