Terraform on Exoscale

There are a number of projects that promise infrastructure as code. Hashicorp’s Terraform is particularly interesting as it is:

  • provider agnostic
  • all about infrastructure, rather than software configuration
  • easy to get started.

Recently we’ve been working on a new Exoscale provider for Terraform! It’s in the early stages but it’s worth taking out for a spin.

In this guide we’ll get familiar with Terraform and look at how to use it to provision services on Exoscale.

Quick introduction to Terraform

Terraform is a tool that lets you provision, change and version your infrastructure. That infrastructure could be virtual machines, DNS records, object storage and so on.

To describe the infrastructure that you want to deploy with Terraform you need to write human readable configuration files. They look something like this:

resource "exoscale_compute" "postgres" {
    name = "postgres-123"
    template = "Linux Ubuntu 16.04 LTS 64-bit"
    zone = "ch-dk-2"
    size = "Large"
    diskSize = 200
    keypair = "db-key"
    affinitygroups = ["postgres-cluster"]
    securitygroups = ["postgres-security"]
    userdata = ""
}

So, it’s easy to read, easy to write, easy to version and easy to collaborate on.

Let’s get started and fire up our first VM on Exoscale.

If you don’t already have an Exoscale account, you can create one in just a couple of minutes.

Terraform configuration files

Terraform works with two formats of configuration file: standard JSON (*.tf.json) and Hashicorp Configuration Language files (*.tf). We’ll work with .tf files as they allow comments and do away with some of the curly braces.

We could have multiple configuration files, each with many commands. We’ll start off simply, though, with a one file that holds our infrastructure configuration and another file for credentials that we don’t want to commit to version control.

Working with providers

Terraform works with many infrastructure providers through a system of plugins.

While it’s still pre-release, you’ll need to build the Exoscale provider from source. It’s written in Go, so make sure you have the Go installation for your operating system. Full instructions for building the plugin are available in the README.

Once you have the binary, put in your GOPATH and then Terraform will pick it up.

Authenticating with Exoscale

To tell Terraform that we’re using Exoscale, and also to authenticate with an account, we need just a few lines at the top of the configuration file:

provider "exoscale" {
    token = "${var.exoscale_api_key}"
    secret = "${var.exoscale_secret_key}"
}

Storing our credentials in variables

Rather than commit our Exoscale credentials to version control, Terraform lets us define variables.

So, let’s quickly open up a new variables.tf file; we can call it anything, so long as it ends in .tf as Terraform will load any .tf file.

Here we’ll define the two variables we used above:

variable "exoscale_api_key" {
    type = "string"
    default = "your-api-key-here"
}

variable "exoscale_secret_key" {
    type = "string"
    default =  "your-api-secret-her"
}

We’ll want to add the variables.tf file to our .gitignore. You can read more about variables in the Terraform docs.

What you can do on Exoscale with Terraform

The Exoscale Terraform provider lets you work with the major components of your Exoscale account, including:

  • virtual machines: spin up, modify and tear down VMs, configure security and anti-affinity groups
  • object storage: create and modify buckets, store and retrieve files
  • DNS: add, alter and remove DNS records.

We’ll start simply with a single virtual machine.

Terraform resources

In the Terraform world, the basic components of infrastructure are called resources. As we saw a moment ago, the resources available to you depends on what the provider offers.

Adding an Exoscale virtual machine

Let’s open our configuration file again and start typing below the provider information:

resource "exoscale_compute" "testing" 
{
    name = "testname"
    template = "Linux Ubuntu 16.04 LTS 64-bit"
    zone = "ch-dk-2"
    size = "Micro"
    diskSize = 10
    keypair = "YOUR-KEYPAIR-NAME"
    userdata = ""
}

The first line is for Terraform itself:

  • exoscale_compute: the resource type
  • testing: a label that we can use within Terraform.

Within the braces are the details we want to pass to Exoscale. As you can see, we’re launching a Micro instance with 10 GB of disk space running Ubuntu 16.04 in the DK2 availability zone.

Let’s try it.

Viewing and applying a plan

Terraform is idempotent, meaning that the outcome is the same each time we run a particular configuration. If we’ve applied a plan already and it is unchanged the second time we run it, then nothing should happen.

However, if we make changes to an existing resource then that could result in the original being destroyed and re-created.

To avoid any nasty mistakes, we should check what Terraform will do before we apply our configuration:

$ terraform plan

Our Terraform plan in a terminal window

Once we’re happy with the plan, we can set it into action:

$ terraform apply

Terraform appling our plan in a terminal window

Now we have a new Micro instance running in our Exoscale account.

The new instance in the Exoscale console

Adding object storage

Let’s add an object storage bucket:

resource "exoscale_s3bucket" "testbucket" {
    bucket = "atestforterraform"
    acl = "private"
}

Just as before, we can see what impact this would have if we applied it:

$ terraform plan

Terraform plan for adding an object storage bucket

As we’re not changing our virtual machine, that remains unaffected. So, let’s go ahead and apply the plan.

$ terraform apply

Terraform applying our plan to add an object storage bucket

Now we can see the bucket in our Exoscale console.

The new bucket in the Exoscale console

Storing a file in our object storage bucket

Each object we want to store is itself a resource. It’s worth remembering that we’re not using Terraform as an ongoing way to store and retrieve files from our object storage. Instead, we can use Terraform to initalise our buckets with files that we know we’ll need as part of the deployment.

Let’s put a text file in our atestforterraform bucket.

resource "exoscale_s3object" "testobj" {
    bucket = "atestforterraform"
    acl = "private"
    key = "a-test-file.txt"
    type = "text/plain"
    source = "some-text.txt"
}

Again, as we haven’t changed anything else terraform plan shows us that applying this will do nothing more than add the file.

Terraform plan to add a file to our object storage bucket

So, let’s go ahead and terraform apply that change.

Terraform applies the plan a file to our object storage bucket

And we can confirm that the file is in the bucket by looking for it in our Exoscale console.

The file now in our object storage bucket

Next steps

So, with just a few lines of configuration we’ve launched a virtual machine, created an object storage bucket and placed a file in that bucket.

Let us know how you’ve got on with the Exoscale Terraform provider. You can also file issues on the GitHub project.

Next time we’ll look at using Terraform to launch a cluster that could power a typical SaaS application.