Post

Getting Started with Terraform & Digitalocean

Getting Started with Terraform & Digitalocean

Installing Terraform

Follow Installation Instructions here.

Terraform

Create a directory where you want to store the terraform configuration files. Create a file named main.tf. This is where we store all the configurations.

Adding providers block

1
2
3
4
5
6
7
8
terraform {
  required_providers {
    digitalocean = {
      source = "digitalocean/digitalocean"
      version = "2.36.0"
    }
  }
}

As of this writing, digitalocean’s terraform provider is of version 2.36.0.

Initialize

To Initialize the terraform and install the azure plugin, you should run

1
terraform init

Output should be similar to this

1
2
3
4
5
6
7
8
$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding digitalocean/digitalocean versions matching "2.36.0"...
- Installing digitalocean/digitalocean v2.36.0...
- Installed digitalocean/digitalocean v2.36.0 (signed by a HashiCorp partner, key ID F82037E524B9C0E8)

Generating DigitalOcean API Token

Terraform needs API Token to communicate with DigitalOcean and to deploy the infrastructure. Generate the API token by going to DigitalOcean » API » Tokens/Keys.

Please copy new personal access token now. It won’t be shown again for security.

Authentication

Authentication can be done either with environment variables or terraform variables.

Windows PowerShell

Open Powershell and run the following to add new environment variable.

1
$ENV:DIGITALOCEAN_ACCESS_TOKEN: 'token'

To set the token as environment variable Persistently

1
[System.Environment]::SetEnvironmentVariable('DIGITALOCEAN_ACCESS_TOKEN','token')

Bash

1
export DIGITALOCEAN_ACCESS_TOKEN='token'

To set the token as environment variable Persistently

1
echo 'export DIGITALOCEAN_ACCESS_TOKEN='token'' >> ~/.profile

Replace token with the actual token.

Using Terraform variables

Create var.tf and add following

1
2
3
4
5
variable "do_token" {
  type         =  string
  description  =  "Digital Ocean API Token"
  sensitive    =  true
}

And add following to main.tf

1
2
3
provider "digitalocean" {
  token =  var.do_token
}

Create a Droplet

To create a droplet, create a new file droplet.tf and add following

1
2
3
4
5
6
resource "digitalocean_droplet" "terraform_droplet" {
  image  = "ubuntu-22-04-x64"
  name   = "web-1"
  region = "nyc2"
  size   = "s-1vcpu-1gb"
}

Here I’m using Ubuntu 22.04 LTS image and using basic size with 1vCPU and 1GB of RAM on deploying it in the nyc2. You can choose whatever you like.

To add ssh key to the account add following to either separate ssh.tf or droplet.tf

1
2
3
4
resource "digitalocean_ssh_key" "ssh_default" {
  name      = "terraform ssh"
  public_key= file("~/.ssh/id_rsa.pub")
}

and attach newly added ssh key to the droplet. updated droplet.tf should look like this

1
2
3
4
5
6
7
resource "digitalocean_droplet" "terraform_droplet" {
  image   = "ubuntu-22-04-x64"
  name    = "terraform"
  region  = "blr1"
  size    = "s-1vcpu-1gb"
  ssh_keys= [digitalocean_ssh_key.ssh_default.fingerprint]
}

if the given key is already added to you account, terraform throws the error. in that case, remove ssh block and just add MD5 fingerprint of the public key to the droplet block.

To get the `MD5 fingerprint of the key run

1
ssh-keygen -lf  ~/.ssh/id_rsa.pub -E MD5

Updated droplet.tf should look like this

1
2
3
4
5
6
7
resource "digitalocean_droplet" "terraform_droplet" {
  image   = "ubuntu-22-04-x64"
  name    = "terraform"
  region  = "blr1"
  size    = "s-1vcpu-1gb"
  ssh_keys= ["a0:b1:c2:3d:4e:5f:g6:h7:i8:9j:0k:1l:2m:n3:o4:p5"]
}

cloud init

To pass user data run commands such as adding users, adding groups or install any tools on droplet on first launch, specify user data file init.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#cloud-config

users:
  - default
  - name: terraform
    gecos: terraform
    shell: /bin/bash
    primary_group: terraform
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: users, admin, sudo
    lock_passwd: false
    ssh_authorized_keys:
        - pubkey
runcmd:
  - apt update
  - apt upgrade -y
  - apt install curl -y

Updated droplet.tf should look something like this

1
2
3
4
5
6
7
8
resource "digitalocean_droplet" "terraform_droplet" {
  image = "ubuntu-22-04-x64"
  name  = "terraform"
  region= "blr1"
  size  = "s-1vcpu-1gb"
  user_data= file("init.yml")
  ssh_keys=` [digitalocean_ssh_key.ssh_default.fingerprint]
}

Outputs

After deploying the droplet, we might need it’s ip address to proceed. To capture that, we need to create a variable and pass deployed droplet ip to that variable.

Create outputs.tf and add following

1
2
3
4
output "ip_address" {
  value= digitalocean_droplet.terraform_droplet.ipv4_address
  description= "The public IP address of your droplet."
}

Deploy

To validate code run terraform validate. If everything is valid and no syntactical errors are there, output should be like

1
2
$ terraform validate
Success! The configuration is valid.

To dry run the everything and to see what are the changes, run

1
terraform plan

If terraform variable were used to define authentication token

1
terraform plan -var="do_token=token"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
terraform plan

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the

following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.terraform_droplet will be created
  + resource "digitalocean_droplet" "terraform_droplet" {
      + backups             : false
      + created_at          : (known after apply)
      + disk                : (known after apply)
      + graceful_shutdown   : false
      + id                  : (known after apply)
      + image               : "ubuntu-22-04-x64"
      + ipv4_address        : (known after apply)
      + ipv4_address_private: (known after apply)
      + ipv6                : false
      + ipv6_address        : (known after apply)
      + locked              : (known after apply)
      + memory              : (known after apply)
      + monitoring          : false
      + name                : "terraform"
      + price_hourly        : (known after apply)
      + price_monthly       : (known after apply)
      + private_networking  : (known after apply)
      + region              : "blr1"
      + resize_disk         : true
      + size                : "s-1vcpu-1gb"
      + status              : (known after apply)
      + urn                 : (known after apply)
      + user_data           : "0743846df7e7237339701a0bd8d31d35945590cb"
      + vcpus               : (known after apply)
      + volume_ids          : (known after apply)
      + vpc_uuid            : (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + ip_address: (known after apply)

you run "terraform apply" now.

To deploy the droplet run

1
terraform deploy

If terraform variable were used to define authentication token

1
terraform deploy -var="do_token=token"

Answer yes to the prompt to deploy

1
2
3
4
5
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

Once completed, outputs the ip and status

1
2
3
4
5
6
7
8
9
10
11
12
terraform deploy
.
.
.
.
digitalocean_droplet.terraform_droplet: Creation complete after 1m29s [id=123456789]

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

Outputs:

ip_address: "123.456.798.10"

Destroy

To destroy the infrastructure, run

1
terraform destroy

Answer the prompt with yes to destroy

1
2
3
4
5
Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

Conclusion

Everything used here is in publicly available repo on GitHub here

Check the official documentation here. Feel free to comment here or drop an email. Au Revoir.

This post is licensed under MIT by the author.