Let us say you need to repeat a resource creation task (a set of resources) more than once. You may need to create those resources in two separate environments – dev and prod.

Or you may need to spin up an instance each in two separate regions (regional managed instance groups would only work across two zones in the SAME region).

Or, as another example, say you want to use code (modules) that already exists in github or on terraform’s public registry.

Creating  a Module for local use

In my f5module folder, I have all of the terraform (main.tf and variables.tf) to spin up F5 instances in a particular environment. What that module (basically, any folder in terraform is a module), requires is a parent vpc, a region and gui_port,  a couple of zones, a couple of static IPs and a NAT_IP. All these can be passed in as variables to the f5module, as shown below.

module "f5multiregional" {
  source ="./f5module"
  parent_vpc = var.parent_vpc
  region = var.region
  management_gui_port = var.management_gui_port
  zone1 = var.zone1
  zone2 = var.zone2
  staticIP_instance1 = google_compute_address.static1.address
  staticIP_instance2 = google_compute_address.static2.address
  subnet_id = google_compute_subnetwork.network-for-f5.id
  static_ip_nat = google_compute_address.staticnat.address
}

The actual module code (the f5module folder containing main.tf and variables.tf)

resource "google_compute_instance_template" "f5-template" {
  name         = "${var.environment}-f5-template"
  machine_type = "${var.instance_type}"

  network_interface {
    subnetwork = var.subnet_id
    access_config {
        nat_ip = var.static_ip_nat
    }
  }

  disk {
    source_image = "${var.image_name}" 
    auto_delete  = false
    disk_size_gb = 100
    boot         = true
  } 

    # Shows up as network tags
    # Must be a match of regex '(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)
    tags = [
        "name-${var.environment}-shared-proxy",
        "environment-${var.environment}",
        "owner-${var.owner}",
        "group-${var.group}",
        "costcenter-${var.costcenter}",
        "application-${var.application}"

    ]

  metadata = {
        Name           = "${var.environment}_proxy"
        environment    = "${var.environment}"
        owner          = "${var.owner}"
        group          = "${var.group}"
        costcenter     = "${var.costcenter}"
        application    = "${var.application}"
        ssh-keys       = "${var.admin_username}:${var.ssh_key_public}"
    }
  can_ip_forward = true
 }

locals {
    instance1_bootstrap = templatefile("${path.module}/f5config1.sh", {
    admin_username         = var.admin_username
    admin_password        = var.admin_password
    })

   instance2_bootstrap = templatefile("${path.module}/f5config2.sh",
    {
     admin_username          = var.admin_username
     admin_password        = var.admin_password
   })
}

resource "google_compute_instance_from_template" "f5-instance-1" {
  name = "${var.environment}-${var.instance1_name}"
  zone = var.zone1
 
  source_instance_template = google_compute_instance_template.f5-template.id

  scratch_disk {
    interface = "SCSI"
  }
  
  network_interface {
    subnetwork = var.subnet_id
    access_config {
        nat_ip = var.staticIP_instance1
    }
   }

  metadata = {
    startup-script = local.instance1_bootstrap != "" ? local.instance1_bootstrap : local.instance1_bootstrap
  } 

  service_account {
        scopes = ["userinfo-email", "compute-ro", "storage-ro"]
    }    

  can_ip_forward = true

}

resource "google_compute_instance_from_template" "f5-instance-2" {
  name = "${var.environment}-${var.instance2_name}"
  zone = var.zone2
 
  source_instance_template = google_compute_instance_template.f5-template.id

  scratch_disk {
    interface = "SCSI"
  }

  network_interface {
    subnetwork = var.subnet_id
      access_config {
        nat_ip = var.staticIP_instance2
    }
 }

  metadata = {
    startup-script = local.instance2_bootstrap != "" ? local.instance2_bootstrap : local.instance2_bootstrap
  } 
 
  service_account {
        scopes = ["userinfo-email", "compute-ro", "storage-ro"]
   }    
 
  can_ip_forward = true
}

locals {
  api_url = "https://compute.googleapis.com/compute/v1/"
  instance1url =  "${local.api_url}${google_compute_instance_from_template.f5-instance-1.id}"
  instance2url =  "${local.api_url}${google_compute_instance_from_template.f5-instance-2.id}"
}

resource "google_compute_http_health_check" "default" {
  name               = "f5healthcheck"
  request_path       = "/"
  check_interval_sec = 1
  timeout_sec        = 1
}

resource "google_compute_target_pool" "f5targetpool" {
  name = "instance-pool"

  instances = [
      local.instance1url,local.instance2url
  ]

  health_checks = [
    google_compute_http_health_check.default.name,
  ]
}

resource "google_compute_region_instance_group_manager" "f5-regional-group" {
  name = "f5-regional-instance-group"

  base_instance_name         = "f5"
  region                     = var.region
  distribution_policy_zones  = [var.zone1, var.zone2]

  version {
    instance_template = google_compute_instance_template.f5-template.id
  }

  target_pools = [google_compute_target_pool.f5targetpool.id]
  target_size  = 2

  named_port {
    name = "custom"
    port = 8888
  }

  auto_healing_policies {
    health_check      = google_compute_http_health_check.default.id
    initial_delay_sec = 300
  }
}

output "instance1_url" {
    value = local.instance1url
}

How else can Terraform Modules be leveraged?

There’s more to using terraform modules, but the use case above (using terraform modules locally), is a good way to get a basic understanding of terraform modules. Some other ways that modules can be leveraged include:

  1. Using terraform modules from the public registry
  2. Using Terraform module using GitHub
  3. Using a custom module
  4. Using Terraform’s module generator




Need an experienced Cloud Networking or a Cloud Data Protection Expert?  Anuj has successfully delivered over a dozen deployments on each of the public clouds (AWS/GCP/Azure) including several DevSecOps engagements.

Next Steps?

Need help with your Terraform or PowerShell or other automation effort? Set up a free consultation – Start the conversation today.