List 如何通过Terraform 0.12中的列表(对象)为每个对象创建
我需要部署一个GCP计算实例列表。如何通过如下对象列表中的“vms”为每个_循环:List 如何通过Terraform 0.12中的列表(对象)为每个对象创建,list,loops,object,foreach,terraform,List,Loops,Object,Foreach,Terraform,我需要部署一个GCP计算实例列表。如何通过如下对象列表中的“vms”为每个_循环: "gcp_zone": "us-central1-a", "image_name": "centos-cloud/centos-7", "vms": [ { "hostname": "test1-srfe",
"gcp_zone": "us-central1-a",
"image_name": "centos-cloud/centos-7",
"vms": [
{
"hostname": "test1-srfe",
"cpu": 1,
"ram": 4,
"hdd": 15,
"log_drive": 300,
"template": "Template-New",
"service_types": [
"sql",
"db01",
"db02"
]
},
{
"hostname": "test1-second",
"cpu": 1,
"ram": 4,
"hdd": 15,
"template": "APPs-Template",
"service_types": [
"configs"
]
}
]
}
为每个块使用
,这是非常新的,并且没有太多文档。一些最好的信息来自他们的公告博客:
另外,请确保查看其文档中的“动态块”部分:
根据您的示例的外观,您需要为创建的每个实例设置一组值,以便创建一个映射图:
下面是我使用Terraform 0.12.12创建的示例:
variable "hostnames" {
default = {
"one" = {
"name" = "one",
"machine" = "n1-standard-1",
"os" = "projects/coreos-cloud/global/images/coreos-stable-2247-5-0-v20191016",
"zone" = "us-central1-a"
},
"two" = {
"name" = "two",
"machine" = "n1-standard-2",
"os" = "projects/centos-cloud/global/images/centos-8-v20191018",
"zone" = "us-central1-b"
}
}
}
resource "google_compute_instance" "default" {
for_each = var.hostnames
name = each.value.name
machine_type = each.value.machine
zone = each.value.zone
boot_disk {
initialize_params {
image = each.value.os
}
}
scratch_disk {
}
network_interface {
network = "default"
}
}
地形平面图输出:
Terraform will perform the following actions:
# google_compute_instance.default["one"] will be created
+ resource "google_compute_instance" "default" {
+ can_ip_forward = false
+ cpu_platform = (known after apply)
+ deletion_protection = false
+ guest_accelerator = (known after apply)
+ id = (known after apply)
+ instance_id = (known after apply)
+ label_fingerprint = (known after apply)
+ machine_type = "n1-standard-1"
+ metadata_fingerprint = (known after apply)
+ name = "one"
+ project = (known after apply)
+ self_link = (known after apply)
+ tags_fingerprint = (known after apply)
+ zone = "us-central1-a"
+ boot_disk {
+ auto_delete = true
+ device_name = (known after apply)
+ disk_encryption_key_sha256 = (known after apply)
+ kms_key_self_link = (known after apply)
+ mode = "READ_WRITE"
+ source = (known after apply)
+ initialize_params {
+ image = "projects/coreos-cloud/global/images/coreos-stable-2247-5-0-v20191016"
+ labels = (known after apply)
+ size = (known after apply)
+ type = (known after apply)
}
}
+ network_interface {
+ address = (known after apply)
+ name = (known after apply)
+ network = "default"
+ network_ip = (known after apply)
+ subnetwork = (known after apply)
+ subnetwork_project = (known after apply)
}
+ scheduling {
+ automatic_restart = (known after apply)
+ on_host_maintenance = (known after apply)
+ preemptible = (known after apply)
+ node_affinities {
+ key = (known after apply)
+ operator = (known after apply)
+ values = (known after apply)
}
}
+ scratch_disk {
+ interface = "SCSI"
}
}
# google_compute_instance.default["two"] will be created
+ resource "google_compute_instance" "default" {
+ can_ip_forward = false
+ cpu_platform = (known after apply)
+ deletion_protection = false
+ guest_accelerator = (known after apply)
+ id = (known after apply)
+ instance_id = (known after apply)
+ label_fingerprint = (known after apply)
+ machine_type = "n1-standard-2"
+ metadata_fingerprint = (known after apply)
+ name = "two"
+ project = (known after apply)
+ self_link = (known after apply)
+ tags_fingerprint = (known after apply)
+ zone = "us-central1-b"
+ boot_disk {
+ auto_delete = true
+ device_name = (known after apply)
+ disk_encryption_key_sha256 = (known after apply)
+ kms_key_self_link = (known after apply)
+ mode = "READ_WRITE"
+ source = (known after apply)
+ initialize_params {
+ image = "projects/centos-cloud/global/images/centos-8-v20191018"
+ labels = (known after apply)
+ size = (known after apply)
+ type = (known after apply)
}
}
+ network_interface {
+ address = (known after apply)
+ name = (known after apply)
+ network = "default"
+ network_ip = (known after apply)
+ subnetwork = (known after apply)
+ subnetwork_project = (known after apply)
}
+ scheduling {
+ automatic_restart = (known after apply)
+ on_host_maintenance = (known after apply)
+ preemptible = (known after apply)
+ node_affinities {
+ key = (known after apply)
+ operator = (known after apply)
+ values = (known after apply)
}
}
+ scratch_disk {
+ interface = "SCSI"
}
}
Plan: 2 to add, 0 to change, 0 to destroy.
好像我找到了该做的事。如果传递的不是地图的地图,而是地图列表,则可以使用此类代码
resource "google_compute_instance" "node" {
for_each = {for vm in var.vms: vm.hostname => vm}
name = "${each.value.hostname}"
machine_type = "custom-${each.value.cpu}-${each.value.ram*1024}"
zone = "${var.gcp_zone}"
boot_disk {
initialize_params {
image = "${var.image_name}"
size = "${each.value.hdd}"
}
}
network_interface {
network = "${var.network}"
}
metadata = {
env_id = "${var.env_id}"
service_types = "${join(",",each.value.service_types)}"
}
}
它将创建实际数量的实例,当您删除三个实例中的中间一个(如果您创建三个:)时,terraform将删除我们要求的内容。从terraform 0.12中,您可以使用for_和如下模块:
for_each = toset(keys({for i, r in var.vms: i => r}))
cpu = var.vms[each.value]["cpu"]
variable "vms" {
type = list(object({
hostname = string
cpu = number
ram = number
hdd = number
log_drive = number
template = string
service_types = list(string)
}))
default = [
{
cpu: 1
...
}
]
}
modules/google\u compute\u instance/variables.tf
modules/google\u compute\u instance/main.tf
servers.tf
当然,您可以根据需要添加任意数量的变量并在模块中使用它们。您可以执行以下操作:
for_each = toset(keys({for i, r in var.vms: i => r}))
cpu = var.vms[each.value]["cpu"]
variable "vms" {
type = list(object({
hostname = string
cpu = number
ram = number
hdd = number
log_drive = number
template = string
service_types = list(string)
}))
default = [
{
cpu: 1
...
}
]
}
假设您有以下情况:
for_each = toset(keys({for i, r in var.vms: i => r}))
cpu = var.vms[each.value]["cpu"]
variable "vms" {
type = list(object({
hostname = string
cpu = number
ram = number
hdd = number
log_drive = number
template = string
service_types = list(string)
}))
default = [
{
cpu: 1
...
}
]
}
我经常处理Terraform中的字符串列表和对象列表。这总是让我头疼。因此,我确定了两种最常见的模式,即字符串列表和对象列表。对于字符串列表,您可以始终使用toset()
并使用对每个字符串进行循环。使用对象列表时,需要将其转换为键为唯一值的贴图。对于唯一值,可以在列表中的所有对象中使用索引、哈希或唯一值
字符串列表:
locals {
ip_addresses = ["10.0.0.1", "10.0.0.2"]
}
resource "example" "example" {
for_each = toset(local.ip_addresses)
ip_address = each.key
}
locals {
virtual_machines = [
{
ip_address = "10.0.0.1"
name = "vm-1"
},
{
ip_address = "10.0.0.1"
name = "vm-1"
}
]
}
resource "example" "example" {
for_each = {
for index, vm in local.virtual_machines:
index => vm
# OR: vm.name => vm (not always unique if names are the same)
# OR: sha1(vm.name) vm => (not always unique if names are the same)
# NOT: uuid() => vm (gets recreated everytime)
}
name = each.value.name
ip_address = each.value.ip_address
}
对象列表:
locals {
ip_addresses = ["10.0.0.1", "10.0.0.2"]
}
resource "example" "example" {
for_each = toset(local.ip_addresses)
ip_address = each.key
}
locals {
virtual_machines = [
{
ip_address = "10.0.0.1"
name = "vm-1"
},
{
ip_address = "10.0.0.1"
name = "vm-1"
}
]
}
resource "example" "example" {
for_each = {
for index, vm in local.virtual_machines:
index => vm
# OR: vm.name => vm (not always unique if names are the same)
# OR: sha1(vm.name) vm => (not always unique if names are the same)
# NOT: uuid() => vm (gets recreated everytime)
}
name = each.value.name
ip_address = each.value.ip_address
}
Terraform使用声明性语言,因此没有if
、for
或while
语句。但是,在某些情况下,由于count
属性,您可以在一定程度上模拟这些。阅读这篇关于如何使用Terraform再现条件或循环的优秀文章:从Terraform 0.12.6开始,资源可以为每个块使用。值得一提的是,if/else条件现在已经在Terraform中出现了几个版本:所以我需要将list转换为map,因为我理解了它,它将list的索引更改为key,这将是map。这很好,但每次都动态提供变量。公共变量可以作为变量单独添加,并作为var.variable重新使用。无论如何,唯一的一个必须单独声明。你是一个英雄。最后我找到了一个合适的例子,从头到尾,效果很好。列表(对象))将转换为一个贴图,该贴图可用作每个值的对应元素。只需选择唯一的密钥(例如主机名)