本文分享自华为云社区《利用Terraform不同数据源扩展应用场景》,作者: kaliarch 。
一 背景
在生产环境中使用Terraform进行基础设施编排,通常又一些信息是通过其他外部系统传入,该场数据源为一个接口,需要Terraform具备调用远程接口能力,获取数据进行目标资源编排,处理各种云厂商提供的provider接口data数据类型外,terraform社区还具备http provider,利用此可以进行调用第三方外部系统接口,实现自助外部接口获取编排。
除了Terraform直接通过调用http provider接口获取数据外,还可以使用执行本地Shell/Python脚本,脚本内部实现调用外部接口获取数据,再将数据进行传入到Terraform进行使用。
二 原理
2.1 数据源概念
数据源允许获取和计算数据,以便在代码中使用。源可以位于另一个Terraform配置中或外部。与资源相反,数据源不由Terraform管理。
2.2 数据源优势
- 减少模块之间的耦合,并使用您的基础设施作为事实的来源。
- 通过减少变量的数量来隐藏Terraform最终用户的复杂性
2.3 扩展数据源方式
2.3.1 http
terraform下载http provider,其内部为一个go编写的http客户端,可以实现调用外部接口。
https://registry.terraform.io/providers/hashicorp/http/latest/docs
2.3.2 脚本方式
terraform扮演执行器,利用external provider进行执行各脚本语言,实现执行脚本内容达到预定目标。
三 http数据源
3.1 测试场景
使用Terraform编写编排文件,获取github个人资料信息。
3.2 代码
- 目录结构
├── main.tf // 主文件 ├── outputs.tf // 输出文件 └── variables.tf // 变量文件
- 代码内容
# main.tf data "http" "get_method" { url = "https://api.github.com/users/${var.gitName}" request_headers = { Accept = "application/json" } } data "http" "post_method" { url = "https://checkpoint-api.hashicorp.com/v1/check/terraform" method = "POST" # Optional request body request_body = "request body" } # variables.tf variable "gitName" { type = string default = "redhatxl" } # outputs.tf output "resp" { value = { get = data.http.get_method.body post = data.http.post_method.body } }
3.3 测试
# init $ terraform init # plan $ terraform plan # 将输出文件到处到json文件中 $ terraform show --json github.out | > redhatxl.json # apply应用 $ terraform apply
3.4 其他
3.4.1 POST请求
data "http" "example_post" { url = "https://checkpoint-api.hashicorp.com/v1/check/terraform" method = "POST" # Optional request body request_body = "request body" }
3.4.2 后置条件
data "http" "example" { url = "https://checkpoint-api.hashicorp.com/v1/check/terraform" # Optional request headers request_headers = { Accept = "application/json" } lifecycle { postcondition { condition = contains([201, 204], self.status_code) error_message = "Status code invalid" } } }
3.4.3 前置条件
data "http" "example" { url = "https://checkpoint-api.hashicorp.com/v1/check/terraform" # Optional request headers request_headers = { Accept = "application/json" } } resource "random_uuid" "example" { lifecycle { precondition { condition = contains([201, 204], data.http.example.status_code) error_message = "Status code invalid" } } }
3.4.4 使用Provisioner
data "http" "example" { url = "https://checkpoint-api.hashicorp.com/v1/check/terraform" # Optional request headers request_headers = { Accept = "application/json" } } resource "null_resource" "example" { # On success, this will attempt to execute the true command in the # shell environment running terraform. # On failure, this will attempt to execute the false command in the # shell environment running terraform. provisioner "local-exec" { command = contains([201, 204], data.http.example.status_code) } }
四 脚本执行
“外部数据源允许实现特定协议(定义如下)的外部程序充当数据源,公开任意数据以供Terraform配置中的其他地方使用。”
有时,我的terraform模块依赖于不是由terraform提供者管理的数据,而是由我的存储库中的构建步骤或脚本管理的数据。外部数据源是一个接口,用于在运行terraform的机器上本地运行命令,并提供该程序的控制台输出作为数据源。
这是一种允许本地脚本充当数据源的机制。要成为有效的数据源,本地脚本只需将JSON打印为标准输出,如下所示:
4.1 测试场景
使用Terraform编写编排文件,获取github个人资料信息。
4.2 代码
├── main.tf ├── outputs.tf ├── scripts │ └── py │ └── fetch_githubinfo.py └── variables.tf
- main.tf
data "external" "githubinfo" { program = ["python", "${path.module}/scripts/py/fetch_githubinfo.py"] query = { gitName = var.gitName } } locals { resp = data.external.githubinfo.result }
- variables.tf
variable "gitName" { type = string }
- outputs.tf
output "resp" { value = { get = local.resp } }
- fetch_githubinfo.py
#!/usr/bin/env python3 # coding: utf-8 import json from terraform_external_data import terraform_external_data import requests import json @terraform_external_data def fetch(query): # Terraform requires the values you return be strings, # so terraform_external_data will error if they aren't. gitName = query['gitName'] response = requests.get(f'https://api.github.com/users/{gitName}') output_json = response.json() return {str(key): str(value) for key, value in output_json.items()} if __name__ == "__main__": fetch()
4.3 测试
执行terraform init/terraform apply
4.4 其他
- terraform扮演执行器,可以执行shell/js/golang/python等各语言代码,但需要在执行环境中具备对应语言的解释器。
五 总结
利用data 的http/external可以非常方便的是心啊调用外部接口获取数据。但官方对于External Data Source的定位是"逃生窗口",因此在考虑使用该方案时,为最后手段。
参考链接