DEV Community

matt from bitLeaf.io
matt from bitLeaf.io

Posted on • Originally published at bitleaf.io on

Creating a DigitalOcean Droplet with Terraform - Part 1 of 3

Creating a DigitalOcean Droplet with Terraform - Part 1 of 3

Let's say you want to quickly bring up 1 or 100 DigitalOcean droplets. Let's also have them nicely pre-configured with our ssh keys and latest software updates. Let's also throw docker onto them. This could be done manually for sure. You could also walk across the country versus flying. In our droplet example let me introduce you to Terraform.

Terraform is free and comes as a single executable you download onto your laptop/desktop. You provide it some configuration files and it goes out and creates whatever you just told it to. One configuration template file to create 1 to infinite number of objects.

Let's just get to the code. Here's what I want to do...

  • Create a droplet (OK, that was an obvious one)
  • In that droplet I want to auto configure it...
  • Add my ssh key so I can ssh in without username/password
  • Update any packages
  • Set it up for auto security updates
  • Install docker and docker-compose
  • Attach a volume to the droplet

We need two things from DigitalOcean...

We now want to store those two secret pieces of information. We don't want to put those in our Terraform configuration files due to the obvious security issue with that, especially if we check things into git. So, let's store those in environment variables on our local machines for now. In Mac/Linux we use 'export', for Windows we use 'set'. For Terraform to pick up on environment variables you need to prefix them with 'TF_VAR'.

export TF_VAR_do_token=<my token>
export TF_VAR_ssh_key_fingerprint=<fingerprint>
Setting environment variables for secrets.

Terraform wouldn't work very well if everything was hardcoded into the configuration files. So it lets you define variables. For example, here's how we define a variable in a Terraform config file.

variable "do_token" {
  description = "Digital Ocean Api Token"
}
Terraform variable defined in an environment variable.

As you might notice the 'do_token' matches the name of our environment variable we set above after the 'TF_VAR' prefix. Terraform will automatically pick that up from our environment variable and we can now use the 'do_token' variable in our configuration. The description is optional and just for your use.

You can also set defaults in your variables for ones that aren't set in your environment. For example, here's a variable that default's our droplet region to 'nyc3'.

variable "region" {
  description = "Digital Ocean Region"
  default = "nyc3"
}
Terraform variable with a default value.

We're going to setup our variables in a separate file called 'variables.tf'.

variable "do_token" {
  description = "DigitalOcean Api Token"
}
variable "ssh_key_fingerprint" {
  description = "Fingerprint of the public ssh key stored on DigitalOcean"
}

variable "region" {
  description = "DigitalOcean region"
  default = "nyc3"
}
variable "droplet_image" {
  description = "DigitalOcean droplet image name"
  default = "ubuntu-18-04-x64"
}
variable "droplet_size" {
  description = "Droplet size for server"
  default = "s-1vcpu-2gb"
}
variable private_networking {
  default = "false"
}
variable "ssh_public_key" {
  description = "Local public ssh key"
  default = "~/.ssh/id_rsa.pub"
}
variables.tf

You can see some of the defaults we set. Those slug names like 's-1vcpu-2gb' can be found on https://slugs.do-api.dev/.

Now onto the meat (or for you vegetarians, the veggie) of it. We have our secret keys to the DigitalOcean kingdom and our variables ready to go. Now we need the config that will actually do stuff. That stuff in our case is to create a droplet and a volume.

# Specify the Terraform provider to use
provider "digitalocean" {
  token = var.do_token
}

# Setup a DO volume
resource "digitalocean_volume" "bitleaf_volume_1" {
  region = "nyc3"
  name = "biteaf-volume-1"
  size = 5
  initial_filesystem_type = "ext4"
  description = "bitleaf volume 1"
}

# Setup a DO droplet
resource "digitalocean_droplet" "bitleaf_server_1" {
  image = var.droplet_image
  name = "bitleaf-server-1"
  region = var.region
  size = var.droplet_size
  private_networking = var.private_networking
  ssh_keys = [
    var.ssh_key_fingerprint
  ]
  # user_data = data.template_file.cloud-init-yaml.rendered
}

# Connect the volume to the droplet
resource "digitalocean_volume_attachment" "bitleaf_volume_1" {
  droplet_id = digitalocean_droplet.bitleaf_server_1.id
  volume_id = digitalocean_volume.bitleaf_volume_1.id
}

# Output the public IP address of the new droplet
 output "public_ip_server" {
  value = digitalocean_droplet.bitleaf_server_1.ipv4_address
}

droplet_volume.tf

A few things going on here. I commented the various sections of the Terraform config. Let's walk through them. I won't get into the weeds of them as all the various DigitalOcean Terraform options are documented on the DigitalOcean Terraform Provider page.

Provider block:

provider "digitalocean" {
  token = var.do_token
}
Provider block

In the provider block we specify oddly enough the particular Terraform provider we want to use from the list of Terraform providers. In our case we want to use 'digitalocean'. The DO provider is takes in a token (which is your API token). You can see the use of 'var.' to specify that we are using a variable. In this case we are using the 'do_token' variable from our 'variables.tf' file which in turn gets it from the local environment variable we set earlier.

Volume resource block:

resource "digitalocean_volume" "bitleaf_volume_1" {
  region = "nyc3"
  name = "biteaf-volume-1"
  size = 5
  initial_filesystem_type = "ext4"
  description = "bitleaf volume 1"
}
Volume resource block

In the volume resource block we are telling Terraform we want to create a DO Volume. The 'digitalocean_volume' is telling Terraform the type of resource we want to create. The 'bitleaf_volume_1' is just how we can access this resource in our configuration script. It's like the variable name for this resource in the configuration.

We'll go over what we set here, but you can see the full list of DigitalOcean Volume Terraform options. Most of what we set is somewhat self explanatory. We want a new DO Volume created in NYC3, we will call it bitleaf-volume-1. The volume will be 5gb in size and use the ext4 filesystem type.

Droplet resource block:

resource "digitalocean_droplet" "bitleaf_server_1" {
  image = var.droplet_image
  name = "bitleaf-server-1"
  region = var.region
  size = var.droplet_size
  private_networking = var.private_networking
  ssh_keys = [
    var.ssh_key_fingerprint
  ]
  # user_data = data.template_file.cloud-init-yaml.rendered
}
Droplet resource block

In this block we're telling Terraform we want a DO droplet created. We then set some of the available DigitalOcean Droplet Terraform options. Again we provide the Terraform resource name of 'digitalocean_droplet' to say we want a droplet created. You can see we are making use of some of the variables again from our variables.tf file. We are using the default values that we defined in that file for the image, region, size, etc. We are directly specifying the name of 'bitleaf-server-1'.

The 'user_data' piece is commented out right not. We'll get to that in Part 3 of these posts.

Volume Attachment resource block:

resource "digitalocean_volume_attachment" "bitleaf_volume_1" {
  droplet_id = digitalocean_droplet.bitleaf_server_1.id
  volume_id = digitalocean_volume.bitleaf_volume_1.id
}
Volume Attachment resource block

The Volume Attachment resource block is a little different. With the Volume and Droplet blocks we were actually creating an object (a Volume and a Droplet). With this particular resource we are telling DO that we want to attach our new Volume to our new Droplet. We get the 'droplet_id' to attach to by telling Terraform to get the id of our 'bitleaf_server_1' droplet resource. Similarly, we tell Terraform the 'volume_id' by getting the id of the 'bitleaf_volume_1' volume resource.

So this is really nice. We can have a volume auto created and also auto attached to our droplet.

Output block:

 output "public_ip_server" {
  value = digitalocean_droplet.bitleaf_server_1.ipv4_address
}
Output block

Finally, we have a new type of block, in this case an output block. You can probably guess that this will indeed output stuff. In our case we are telling Terraform to output the public IP address from our new droplet to the screen. Here's the full list of available Terraform Droplet source information.

Now the moment has arrived. We've created our Terraform configuration. We have our DigitalOcean secrets all set. Head on over to Part 2 of Creating a DigitalOcean Droplet with Terraform to run this thing.

Top comments (0)