Infrastructure as code is taking over in cloud infrastructure management. It ensures automated provisioning which lessens the time taken to create multiple virtual machines. With infrastructure as code, we use configuration files having code that corresponds to the specifications of the provider being used. Terraform is therefore a tool that you can use manage your infrastructure using codes written in configuration files. With such configuration files, you can deploy any number of virtual machines also easily make replacements in case a VM crashes. In this guide today, we are going to look at how to deploy Virtual Machines in Openstack using terraform. I am going to be using Ubuntu 20.04 where Terraform will be installed.

Step 1: Install Terraform on Linux

The first step is to install Terraform on your working environment. Since I am using Ubuntu 20.04, the below command should install Terraform on my system:

TRELEASE=0.14.7
wget https://releases.hashicorp.com/terraform/${TRELEASE}/terraform_${TRELEASE}_linux_amd64.zip

For any other Operating System, grab the corresponding version of Terraform ffrom the official download site, https://www.terraform.io/downloads.html.

Once downloaded, extract the archived file and move the binary files to a directory included in your system PATH.

unzip terraform_${TRELEASE}_linux_amd64.zip
sudo mv terraform /usr/local/bin/

Step 2: Create Terraform Working directory

We need to create a directory where all our Terraform files will be stored. We will initialize Terraform in this directory

mkdir Terraform
cd Terraform

Step 3: Initialize Terraform for OpenStack

Now create a file to define your provider. Note that Terraform reads from files ending with .tf. You can create a file called providers.tf

vim provider.tf

Since our provider is openstack, add the below content to your file:

terraform {
required_version = ">= 0.14.0"
  required_providers {
    openstack = {
      source  = "terraform-provider-openstack/openstack"
      version = "~> 1.35.0"
    }
  }
}

Save the file and initialize terraform.

terraform init

Sample output

Initializing the backend...
Initializing provider plugins...
- Finding terraform-provider-openstack/openstack versions matching "~> 1.35.0"...
- Installing terraform-provider-openstack/openstack v1.35.0...
- Installed terraform-provider-openstack/openstack v1.35.0 (self-signed, key ID 4F80527A391BEFD2)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Step 4: Create VMs with Terraform on Opestack

Now that we have our working directory and have initialized Terraform, we will go ahead to see how to manage one virtual machine on Openstack with Terraform. Follow the steps as below:

Provide ssh key

We need to provide a public key that we will use to access the created virtual machines. Here I am going to create a file called main.tf with the below content:

resource "openstack_compute_keypair_v2" "my-cloud-key" {
  name       = "my-key"
  public_key = "ssh-rsa AAAAB3Nz…….
}

Where:

openstack_compute_keypair_v2 – is the type of the resoure

my-cloud-key – is the name of the specific resource

Replace the value for public_key with your own key.

Define provider access credentials

We need to be able to connect to our Openstack infrastructure. Define access url, access username, password and any other required specifications. You can define them as variables or include them in your .tf files. In my providers.tf file, I added the content as below:

provider "openstack" {
  user_name = "username"
  password  = "password"
  auth_url  = "http://<ip>/v2"
  user_domain_name = "Default"
  project_domain_name = "Default"
}

Here, you need to replace all the values above with the ones corresponding to your environment.

Creating a single VM

To be able to create a VM with terraform, I added the below content in my providers.tf file

resource "openstack_compute_instance_v2" "my_instance" {
  name      = "my_instance"
  image_id  = "your_image_id"
  flavor_name = "flavor_name"
  key_pair  = "my-key"

  network {
    uuid = "your_network_uuid"
    name = "public"
  }
}

openstack_compute_instance_v2 – is the type of resource

my_instance – is the name of the resource

Run terraform plan

Running ‘terraforn plan’ is not necessary but it is meant to show you the changes that will be applied before they are actually applied.

$ terraform plan
openstack_compute_keypair_v2.my-cloud-key: Refreshing state... [id=my-key]
openstack_compute_instance_v2.my_instance: Refreshing state... [id=2ccae904-0257-4cdc-9964-b01e0feafd1d]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # openstack_compute_instance_v2.my_instance will be created
  + resource "openstack_compute_instance_v2" "my_instance" {
      + access_ip_v4        = (known after apply)
      + access_ip_v6        = (known after apply)
      + all_metadata        = (known after apply)
      + all_tags            = (known after apply)
      + availability_zone   = (known after apply)
      + flavor_id           = (known after apply)
      + flavor_name         = "m1.small"
      + force_delete        = false
      + id                  = (known after apply)
      + image_id            = "0b89b169-0ddb-46df-94cd-748692421574"
      + image_name          = (known after apply)
      + key_pair            = "my-key"
      + name                = "my_instance"
      + power_state         = "active"
      + region              = (known after apply)
      + security_groups     = (known after apply)
      + stop_before_destroy = false

      + network {
          + access_network = false
          + fixed_ip_v4    = (known after apply)
          + fixed_ip_v6    = (known after apply)
          + floating_ip    = (known after apply)
          + mac            = (known after apply)
          + name           = "public"
          + port           = (known after apply)
          + uuid           = "ad3eddbb-fc0f-4450-a427-3f050ea2f0e1"
        }
 }

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

------------------------------------------------------------------------

Run Terraform Apply

The last step is to apply your configuration on the Openstack environment. Simply run ‘terafform apply

$ terraform apply
openstack_compute_keypair_v2.my-cloud-key: Refreshing state... [id=my-key]
openstack_compute_instance_v2.my_instance: Refreshing state... [id=2ccae904-0257-4cdc-9964-b01e0feafd1d]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # openstack_compute_instance_v2.my_instance will be created
  + resource "openstack_compute_instance_v2" "my_instance" {
      + access_ip_v4        = (known after apply)
      + access_ip_v6        = (known after apply)
      + all_metadata        = (known after apply)
      + all_tags            = (known after apply)
      + availability_zone   = (known after apply)
      + flavor_id           = (known after apply)
      + flavor_name         = "m1.small"
      + force_delete        = false
      + id                  = (known after apply)
      + image_id            = "0b89b169-0ddb-46df-94cd-748692421574"
      + image_name          = (known after apply)
      + key_pair            = "my-key"
      + name                = "my_instance"
      + power_state         = "active"
      + region              = (known after apply)
      + security_groups     = (known after apply)
      + stop_before_destroy = false

      + network {
          + access_network = false
          + fixed_ip_v4    = (known after apply)
          + fixed_ip_v6    = (known after apply)
          + floating_ip    = (known after apply)
          + mac            = (known after apply)
          + name           = "public"
          + port           = (known after apply)
          + uuid           = "ad3eddbb-fc0f-4450-a427-3f050ea2f0e1"
        }
    }

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

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

  Enter a value: 

Enter ‘yes’ when prompted. And configuration application will continue and your VM will be created.

openstack_compute_instance_v2.my_instance: Creating...
openstack_compute_instance_v2.my_instance: Still creating... [10s elapsed]
openstack_compute_instance_v2.my_instance: Creation complete after 15s [id=10e581e1-68f8-4b89-943d-9bd3a4c5bbf1]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Your VM should be created now. To confirm, login to your Openstack web UI or run ‘terraform show’ on your terminal which shows you the VM specifications including the IP address.

$ terraform show
# openstack_compute_instance_v2.my_instance:
resource "openstack_compute_instance_v2" "my_instance" {
    access_ip_v4        = "192.168.50.2"
    all_metadata        = {}
    all_tags            = []
    availability_zone   = "external"
    flavor_id           = "2"
    flavor_name         = "m1.small"
    force_delete        = false
    id                  = "2ccae904-0257-4cdc-9964-b01e0feafd1d"
    image_id            = "0b89b169-0ddb-46df-94cd-748692421574"
    image_name          = "Debian-10.7.0"
    key_pair            = "my-key"
    name                = "my_instance"
    power_state         = "active"
    security_groups     = [
        "default",
    ]
    stop_before_destroy = false
    tags                = []

    network {
        access_network = false
  fixed_ip_v4    = "192.168.50.2"
        mac            = "fe:36:3h:af:4g:59"
        name           = "public"
        uuid           = "ad3eddbb-fc0f-4450-a427-3f050ea2f0e1"
    }
}

# openstack_compute_keypair_v2.my-cloud-key:
resource "openstack_compute_keypair_v2" "my-cloud-key" {
    fingerprint = "ec:6a:87:91:7f:3e:6a:87:76:4d:ba:00:f3:g1:ae:32"
    id          = "my-key"
    name        = "my-key"
    public_key  = "ssh-rsa AAAAB3NzaC1yc -----
}

You have successfully created your first virtual machine on Openstack using Terraform.

Adding more Virtual Machines

If you need to add more virtual machines with the same specs, simply provide the number of Vms needed and you can choose to increment the naming to the number of Vms you need.Example below:

resource "openstack_compute_instance_v2" "exec" {
  name            = "exec-${count.index}"
  image_name      = "denbi-centos7-j10-2e08aa4bfa33-master"
  flavor_name     = "m1.tiny"
  key_pair        = "${openstack_compute_keypair_v2.my-cloud-key.name}"
  security_groups = ["default"]
  count           = 2

  network {
    name = "public"
  }
}

Then run ‘terraform apply

At thispoint, you have successfully installed Terraform on Ubuntu 20.04 and deployed your first virtual machine. Note that this tutorial does not include everything required for you to become an expert in Terraform but meant to give a quick start guide in your journey in Infrastructure as code and cloud automation. I hope the guide will be of help to you. Check more automation-related guides below: