如何以与云无关的方式使用 Terraform

Posted

技术标签:

【中文标题】如何以与云无关的方式使用 Terraform【英文标题】:How to use Terraform in a cloud agnostic way 【发布时间】:2017-08-04 23:32:48 【问题描述】:

我看过很多关于如何使用 Terraform 启动 AWS 资源的示例。我还看到许多声称 Terraform 与云无关的说法。

我还没有看到一个示例,说明如何使用单个 tf 文件在 AWS 或 Azure 中启动具有一些子网、一些实例、一些 ELB 和一些数据库的 VPC。

谁有这方面的例子吗?

【问题讨论】:

【参考方案1】:

虽然 Terraform 作为一种工具与云无关(因为它将支持任何暴露其 API 并有足够的开发人员支持为其创建“提供者”),但 Terraform 本身根本不会抽象这一点,我会认真考虑这是否是一个好主意,除非你有一个非常好的用例。

如果您确实需要这样做,则需要在从模块用户抽象云层的事物之上构建一堆模块,并只允许他们将云提供商指定为变量(可能从外部控制脚本)。

作为抽象 DNS 的一个基本示例,您可能有类似这样的内容(未经测试):

modules/google/dns/record/main.tf

variable "count" = 

variable "domain_name_record" = 
variable "domain_name_zone" = 
variable "domain_name_target" = 

resource "google_dns_record_set" "frontend" 
  count = "$variable.count"
  name  = "$var.domain_name_record.$var.domain_name_zone"
  type  = "CNAME"
  ttl   = 300

  managed_zone = "$var.domain_name_zone"

  rrdatas = ["$var.domain_name_target"]

modules/aws/dns/record/main.tf

variable "count" = 

variable "domain_name_record" = 
variable "domain_name_zone" = 
variable "domain_name_target" = 

data "aws_route53_zone" "selected" 
  count = "$variable.count"
  name  = "$var.domain_name_zone"


resource "aws_route53_record" "www" 
  count   = "$variable.count"
  zone_id = "$data.aws_route53_zone.selected.zone_id"
  name    = "$var.domain_name_record.$data.aws_route53_zone.selected.name"
  type    = "CNAME"
  ttl     = "60"
  records = [$var.domain_name_target]

modules/generic/dns/record/main.tf

variable "cloud_provider" =  default = "aws" 

variable "domain_name_record" = 
variable "domain_name_zone" = 
variable "domain_name_target" = 

module "aws_dns_record" 
  source             = "../../aws/dns/record"
  count              = "$var.cloud_provider == "aws" ? 1 : 0"
  domain_name_record = "$var.domain_name_record"
  domain_name_zone   = "$var.domain_name_zone"
  domain_name_target = "$var.domain_name_target"


module "google_dns_record" 
  source             = "../../google/dns/record"
  count              = "$var.cloud_provider == "google" ? 1 : 0"
  domain_name_record = "$var.domain_name_record"
  domain_name_zone   = "$var.domain_name_zone"
  domain_name_target = "$var.domain_name_target"

显然这会很快变得复杂,但这确实意味着您可以将“通用”模块公开给其他人,并允许他们使用您在事物上构建的抽象。您如何处理不同云之间没有功能一致性的事情是一个完全独立的问题,可能不适合 ***。

【讨论】:

【参考方案2】:

@ydaetskcoR 我喜欢您对提供程序特定模块(遵循接口)的想法。但我建议的改变是可以直接从 main.tf 文件中调用它们,并在其中使用一个变量来确定模块源。

所以我会保留:modules/google/dns/record/main.tfmodules/aws/dns/record/main.tf

我不会使用 modules/generic/dns/record/main.tf

并添加:ma​​in.tf

variable "cloud_provider" =  default = "aws"   
module "dns"   
  source = "modules/$var.cloud_provider/dns/record/main.tf"  
  domain_name_record = "$var.domain_name_record"  
  domain_name_zone   = "$var.domain_name_zone"  
  domain_name_target = "$var.domain_name_target"  

很遗憾,Terraform 不支持可变模块源。 见:https://github.com/hashicorp/terraform/issues/1439

我正在考虑添加插件甚至更高级别的模板抽象的方法。

【讨论】:

【参考方案3】:

你不能这样做。

Terraform 可用于通过单个 terraform apply 命令在多个云提供商中创建资源。

但您需要为不同的云提供商配置单独的资源。

例如,您可以创建一个 terraform 配置文件并声明 aws_instanceazurerm_virtual_machine 资源以在 aws 和 azure 中创建资源。

【讨论】:

github.com/debovema/cloud-agnostic-terraform

以上是关于如何以与云无关的方式使用 Terraform的主要内容,如果未能解决你的问题,请参考以下文章

以与平台无关的方式将行添加到文件中

警告消息一直以与警告无关的块形式出现在 RStudio 笔记本中

是否有与实现无关的方式让 SQL DB 提供 UUID?

如何以与 np.where 相同的方式使用 Tensorflow.where?

如何创建一个可调整列表项高度的方形按钮?

如何以与@nuxt/apollo subscribeToMore 一起使用的方式设置我的 nuxt