如何以云不可知的方式使用 Terraform

How to use Terraform in a cloud agnostic way

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

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

有人有这方面的例子吗?

虽然 Terraform 作为一种工具与云无关(因为它将支持任何暴露其 API 并且有足够的开发人员支持为其创建 "provider" 的东西),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}"
}

显然这会很快变得复杂,但这确实意味着您可以向其他人公开 "generic" 模块并允许他们使用您在事物上构建的抽象。你如何处理不同云之间没有特征对等的事情是一个完全不同的问题,可能不是最适合 Whosebug 的。

你不能那样做。

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

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

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

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

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

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

并添加:
main.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

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