帶你掌握利用Terraform不同資料來源擴充套件應用場景

2023-07-17 12:00:29

本文分享自華為雲社群《利用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

cke_325.png

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列印為標準輸出,如下所示:

cke_326.png

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

cke_327.png

4.4 其他

  • terraform扮演執行器,可以執行shell/js/golang/python等各語言程式碼,但需要在執行環境中具備對應語言的直譯器。

五 總結

利用data 的http/external可以非常方便的是心啊呼叫外部介面獲取資料。但官方對於External Data Source的定位是"逃生視窗",因此在考慮使用該方案時,為最後手段。

參考連結

 

點選關注,第一時間瞭解華為雲新鮮技術~