Terraform Apply

As touched on in the last post, building images is a critical part of immutable infrastructure. Trying to ship a single image that could satisfy all possible users isn’t a practical goal, so the decision was made to change out the makefile at the heart of the ResinStack for a more composeable approach.

When removing the makefile, decisions had to be made about what to replace it with. There were a few options that could have won out, lets take a look at what those were:

In the end, Terraform was selected as the system of choice for building images. Terraform has several advantages over anything listed above, lets look at just a few:

So what does this look like in practice? Lets take a look at an example where we build a system image that can be PXE booted that contains Nomad, Consul, and Vault:

module "aio_server" {
  source  = "resinstack/resinstack/linuxkit"
  version = "0.1.0"

  system_version_metadata   = "2cf1db0f0d2c9916b4894318bd76f1c97d8c8f7b"
  system_metadata_providers = ["metaldata"]

  enable_console = true
  enable_sshd    = true
  enable_ntpd    = true

  consul_server = true
  consul_acl    = "deny"

  nomad_server  = true
  nomad_client  = true
  enable_docker = true
  nomad_acl     = true

  vault_server      = true
  vault_tls_disable = true

  output_to = "${path.root}/out"
  base_name = "aio"
  build_pxe = true
}

The above snippet is all it takes. You can put this in a file, call terraform init and terraform apply and assuming that you have docker and linuxkit available on your host, you’ll get a set of files that you can load on a TFTP server and feed to a PXE boot script.

This is all good and well for a standard image, but what if we want to add custom services? Prometheus is a popular monitoring tool, lets add the node_exporter:

data "linuxkit_image" "node_exporter" {
  name = "node_exporter"
  image = "linuxkit/node_exporter:v0.8"
}

module "aio_server" {
  source  = "resinstack/resinstack/linuxkit"
  version = "0.1.0"

  system_version_metadata   = "2cf1db0f0d2c9916b4894318bd76f1c97d8c8f7b"
  system_metadata_providers = ["metaldata"]

  enable_console = true
  enable_sshd    = true
  enable_ntpd    = true

  consul_server = true
  consul_acl    = "deny"

  nomad_server  = true
  nomad_client  = true
  enable_docker = true
  nomad_acl     = true

  vault_server      = true
  vault_tls_disable = true

  custom_services = [data.linuxkit_image.node_exporter.id]

  output_to = "${path.root}/out"
  base_name = "aio"
  build_pxe = true

It really is that simple! Anything that you can contain in a docker image can be added to the build, but keep in mind that these images are immutable, and if you want to change their contents you’ll need to rebuild them and somehow get your machines to use the new images.

The terraform module is available today from the registry and is suitable for production use, but as with all upgrades you are strongly encouraged to review the changes and to ensure your environment will not be adversely affected.