如何使用 terraform 创建文件并将变量作为文字包含?

How to create a file with terrafom and include variable as literal?

使用 terraform v0.12.9 并使用 template_file 数据源构建文件,我无法使用双美元符号 $$ 来处理输入 ${data_directory} 作为文字。

正在寻找以正确方式解决此问题的解决方案,或正在寻找有助于创建包含此内容的文件的任何其他建议或解决方法。

我尝试使用双美元符号(如下面的代码示例)将此 ${data_directory} 隔离为文件输出中的文字。

这是我试图用 terraform 创建后缀 main.cf 文件的代码:

variable "hostname" {
  default = "test"
}

variable "domain_name" {
  default = "test.com"
}

variable "fn_main_cf" {
  default = "main.cf"
}

data "template_file" "main_cf" {
  template = <<EOF
##
## Network settings
##
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
inet_interfaces = 127.0.0.1, ::1, 120.121.123.124, 2a03:b0a0:3:d0::5e79:4001
myhostname = ${var.hostname}.${var.domain_name}

###
### Outbound SMTP connections (Postfix as sender)
###
smtp_tls_session_cache_database = btree:$${data_directory}/smtp_scache
EOF
}

  data "template_cloudinit_config" "main_cf" {
    gzip          = false
    base64_encode = false

    part {
      filename     = "${var.fn_main_cf}"
      content_type = "text/cloud-config"
      content      = "${data.template_file.main_cf.rendered}"
    }
  }

  resource "null_resource" "main_cf" {
    triggers = {
      template = "${data.template_file.main_cf.rendered}"
    }

    provisioner "local-exec" {
      command = "echo \"${data.template_file.main_cf.rendered}\" > ~/projects/mail-server/files/etc/postfix/${var.fn_main_cf}"
    }

}

如您所见,有很多变量,所有这些都工作正常,但 ${data_directory} 不应被视为变量,而应被视为文字,并且应保持输出文件中的原样在磁盘上。

main.cf 创建的保存在磁盘上的文件的预期输出应如下所示:

##
## Network settings
##
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
inet_interfaces = 127.0.0.1, ::1, 120.121.123.124, 2a03:b0a0:3:d0::5e79:4001 
myhostname = test.test.com

###
### Outbound SMTP connections (Postfix as sender)
###
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

因此 ${data_directory} 不应被 terraform 视为 terraform 变量,而应被视为字符组、文字(常规文本输入)。

运行 terraform plan 带有双美元符号 $$ 的输出如下:

Error: failed to render : <template_file>:11,43-57: Unknown variable; There is no variable named "data_directory".

template_file 在 Terraform 中仍然可用,主要供 Terraform 0.11 用户使用。在 Terraform 0.12 中不需要使用 template_file,因为它已被其他两个功能所取代:

  • 对于单独文件中的模板,the built in templatefile function 可以直接在语言中呈现外部模板,而不需要单独的提供程序和数据源。
  • 对于内联模板(直接在配置中指定),您可以直接将它们写在需要的地方,或者通过 Local Values.
  • 将它们分解出来

local_file 资源也是在磁盘上创建本地文件的一种比使用 local-exec 配置器更好的方法。通过在此处使用 template_filelocal-exec,您迫使自己应对两个级别的额外转义:Terraform 模板转义以将文字模板转义到 template_file 数据源中,然后 shell 从你的供给器中逃脱。

这是一种更直接的方式来表示您的模板和文件:

variable "postfix_config_path" {
  # Note that for my example this is expected to be the full path
  # to the file, not just the filename. Terraform idiom is to be
  # explicit about this sort of thing, rather than relying on
  # environment variables like HOME.
  type = string
}

locals {
  postfix_config = <<-EOT
    ##
    ## Network settings
    ##
    mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
    inet_interfaces = 127.0.0.1, ::1, 120.121.123.124, 2a03:b0a0:3:d0::5e79:4001
    myhostname = ${var.hostname}.${var.domain_name}

    ###
    ### Outbound SMTP connections (Postfix as sender)
    ###
    smtp_tls_session_cache_database = btree:$${data_directory}/smtp_scache
  EOT
}

resource "local_file" "postfix_config" {
  filename = var.postfix_config_path
  content  = local.postfix_config
}

正如 local 提供程序文档所警告的那样,Terraform 并非真正设计用于直接管理本地计算机上的文件和其他资源。 local 供应商是为异常情况而存在的,这可能是其中一种情况,在这种情况下,上述是解决它的合理方法。

请注意,更标准的 Terraform 使用模式是使用 Terraform 启动新的虚拟机,该虚拟机将 运行 后缀并通过特定于供应商的 [=21] 传递必要的配置=] 或 metadata 参数。

如果后缀服务器与此 Terraform 配置分开管理,则另一种模式是安排 Terraform 将必要的数据写入共享配置存储(例如 AWS SSM Parameter Store 或 HashiCorp Consul),然后使用在 postfix 服务器上使用单独的软件来读取并更新 main.cf 文件。对于 HashiCorp Consul,该单独的软件可能是 consul-template。其他参数存储也有类似的软件,可让您将单个虚拟机的配置与整体基础架构的配置分离开来。