Nico
Nico
Creator of this small website
Sep 27, 2020 2 min read

Cloud-init on GCE and terraform

thumbnail for this post

Cloud-init is a great way to initialize machines on cloud providers and it’s pretty straightforwardly supported everywhere.

Here is my personal take on how I use it to manage my instances on GCE and particularly how I init chef nodes onto them using terraform

Using the following code :

module "my_cloud_init" {
  source = "git@xxx:yyy/my-cloud-init-module.git"
  chef_role = "my-role"
  chef_environment = "my-env"
}

resource "google_compute_instance" "my_instance" {
  name = "example-cloud-init"
  machine_type = "n1-standard-1"
  
  // omitted to keep things short

  metadata = {
    user-data = module.my_cloud_init.user_data
  }

  // omitted again
}

of course you will have noticed that once again, the magic happens using the instance metadata. here is the code of the module to generate the cloud-init instructions

variable "locale" {
  description = "The locale to use"
  default = "en_US.UTF-8"
}

variable "chef_role" {
  description = "The chef role for this node"
  default = "basic"
}

variable "chef_environment" {
  description = "The chef environment for this node"
  default = "dev-ew1"
}

data "template_file" "cloud_init" {
  template = "${file("${path.module}/cloud-init.yaml.tpl")}"

  vars = {
    locale = var.locale
    chef_role = var.chef_role
    chef_environment = var.chef_environment
  }
}

output "user_data" {
  value = data.template_file.cloud_init.rendered
}

and the cloud-init.yaml.tpl file :

#cloud-config

manage_etc_hosts: false
locale: ${locale}
timezone: UTC
runcmd:
  - mkdir -p /etc/chef
  # make sure this bucket has the correct and strict enough ACLs !!
  # Also the instance service account must be able to read it of course
  - gsutil cp -r "gs://my-bootstrap_bucket/path/*" /etc/chef
  # first run must remove this file ! never keep it on your nodes
  - chmod 0400 /etc/chef/org-validator.pem
  # first run is on role basic. All nodes must execute it without any problem by default.
  - chef-client -E ${chef_environment} -r "role[basic]"
  - hostname=$(hostname -f)
  # switch to the role for this very node
  - knife node run_list -c /etc/chef/client.rb --config-option node_name=$${hostname} set $${hostname} "role[${chef_role}]"
  - chef-client