Getting started with Terraform and Machines

By Dov Alperin GitHub Twitter

Fly Machines are Firecracker VMs with a fast REST API that can boot instances in about 300ms, in any region supported by Fly.io.

Terraform is one of the most popular infrastructure as code tools used by many companies and organizations to manage their infrastructure.

terraform-provider-fly is a Terraform provider that enables Terraform to manage Fly.io resources such as apps, volumes, certificates, ips, machines, and so on.

In this guide we'll use Terraform to deploy a very simple demo app from a Docker image onto two Fly Machines VMs.

Prerequisites

Go ahead and download Terraform if you haven't yet.

Set API Key

export FLY_API_TOKEN=$(fly auth token)

This gets your Fly.io token into an environment variable Terraform can use to authenticate us.

Open WireGuard Tunnel

In its own terminal (or in the background; the point is that we want to keep this running) run

flyctl machines api-proxy

This will proxy a local port over user-mode WireGuard to the internal Machines API endpoint, so Terraform on your machine can access it.

Set Up the Terraform Project

Let's make a directory for this project and set up a Terraform file for us to work in.

mkdir fly-tf-example && cd fly-tf-example

In this directory, create the Terraform file main.tf. In it, specify that you want to use the Fly.io provider:

# main.tf
terraform {
  required_providers {
    fly = {
      source = "fly-apps/fly"
      version = "0.0.16"
    }
  }
}

Now kick off your Terraform project:

 terraform init

This will download the Fly.io provider and get it ready to use.

Create Resources

In your main.tf, use the fly_app resource to create a new app and the fly_ip resource to make it publicly accessible.

resource "fly_app" "exampleApp" {
  name = "flyiac" #Replace this with your own app name
  org  = "personal"
}

resource "fly_ip" "exampleIp" {
  app        = "flyiac" #Replace this with your own app name
  type       = "v4"
  depends_on = [fly_app.exampleApp]
}

resource "fly_ip" "exampleIpv6" {
  app        = "flyiac" #Replace this with your own app name
  type       = "v6"
  depends_on = [fly_app.exampleApp]
}

To tell Terraform to actually create these resources, use

terraform apply

Terraform will show you what it plans on doing: in this case, creating one app and two IPs, and prompt to see if you want to continue. If everything looks right, type in yes and hit enter. In just a few seconds you should see the successful output:

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

At this point you have an app configured on the Fly.io platform, but no VMs deployed.

Create Machines

This example creates machines running in ewr (Secaucus, NJ) and lax (Los Angeles, CA).

resource "fly_machine" "exampleMachine" {
  for_each = toset(["ewr", "lax"])
  app    = "flyiac" #Replace this with your own app name
  region = each.value
  name   = "flyiac-${each.value}"
  image  = "flyio/iac-tutorial:latest"
  services = [
    {
      ports = [
        {
          port     = 443
          handlers = ["tls", "http"]
        },
        {
          port     = 80
          handlers = ["http"]
        }
      ]
      "protocol" : "tcp",
      "internal_port" : 80
    },
  ]
  cpus = 1
  memorymb = 256
  depends_on = [fly_app.exampleApp]
}

Once again run terraform apply and confirm with yes. You'll get confirmation once your machines have been created!

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

To test it out go to https://<yourappname>.fly.dev. In this example, the appname is flyiac so it would be https://flyiac.fly.dev. Once the page has loaded, play around with the buttons to try loading your machines in both regions!

Destroy Resources

When you are done, run terraform destroy to delete all the resources you created for this tutorial.