dyasny
dyasny

Reputation: 327

Using multi-zone provisioning with Terraform/GCP

I am trying to provision a cluster with instances across multiple zones in GCP using Terraform. This is what the nodes variabe looks like:


variable "nodes" {
  type = list(object({
    machine_type = string
    nvme_count   = number
    node_count   = number
    zone         = string
    disk_size    = number
  }))
  default = [
    {
      zone = "us_east1-b"
      machine_type = "n1-standard-4"
      nvme_count = 3
      node_count = 3
      disk_size = 20
    },
    {
      zone = "us_central1-a"
      machine_type = "n1-standard-4"
      nvme_count = 3
      node_count = 3
      disk_size = 20
    }
  ]

}

This should mean that I want to ave 3 nodes in us-east1-b and 3 nodes in us-central1-a, with some additional parameters per zone.

This is how I tried to run this:

resource "google_compute_instance" "node-instance" {
  for_each = var.nodes
  name = "${var.cluster_name}-node-${each.value.zone}"
  machine_type = each.value.machine_type
  count = each.value.node_count
  zone = each.value.zone
  tags=["${var.cluster_name}-node"]
  boot_disk {
    initialize_params {
      size = each.value.disk_size
      image = data.google_compute_image.g_image.self_link
    }
  }

  metadata = {
    sshKeys = "${var.ssh_user}:${file(var.ssh_public_key)}"
  }

  network_interface {
    network = "${var.cluster_name}-vpc"
    access_config {

    }
  }
}

This does not work because apparently count and for_each conflict with each other. Is there a solution? I really don't want to hardcode a separate resource for each zone

Upvotes: 1

Views: 702

Answers (1)

Fedor  Petrov
Fedor Petrov

Reputation: 1050

There are several problems in your code.

First of all for_each accepts only set or map. It doesn't work with lists. You can try something like:

for_each = {for node in var.nodes:  node.zone => node}

but even this is not enough. There is little can be done with multidimensional objects on the resource level. To achieve what you want you may need to unroll the definition of your nodes or go one level up an use modules.

locals {
   nodes = flatten([ for node in var.nodes: 
                           [ for i in range(node.node_count): 
                               {
                               zone = node.zone
                               machine_type = node.machine_type
                               nvme_count = node.nvme_count
                               disk_size = node.disk_size
                               } 
                           ] 
                       ])
}

and then you use this list of nodes local.nodes together with count = length(local.nodes) or convert it to set or map and use it with for_each.

Upvotes: 2

Related Questions