Deploying Linux VM on the vCenter with Terraform

Some time ago, I’ve posted tutorial how to deploy linux virtal machine using Ansible. If you missed it, check this link: Deploying Linux VM using Ansible
In this post, I’will show you another kind of this deployment. Now, we use Terraform as automation tool to create new server from template on the vCenter. This is a simple tutorial how to automate repeatable tasks.

What is Terraform?

Terraform is a open-soruce Infrastructure as code (IaC) tool offered by HashiCorp. Can be used for building, modifying and versioning infrastructure. Terraform can be hosted in the major public clouds (AWS, Google, Azure) and in the private cloud, such as VMware vSphere or OpenStack.
With this tool, you can manage services across multiple infrastructures, clouds and vendors.

Requriements:

  1. Linux server – in this tutorial I use Ubuntu 20.04. You can choose CentOS or another distribution. Windows and Mac OS systems are supported too.
  2. Existing virtual machine template in the vCenter.
  3. Service user in the vCenter (optional step).
  4. Terraform

I’ve tested this procedure on vCenter 7.0.3.00100 (7.0 U3a) with ESXi 7.0.2 (7.0 U2d).

Create service user

It’s not obligatory step. To keep your work under control and be more secure, let’s create terraform service user with Administrator role. You can use administrator@vsphere.local account too. But, it’s a good habit to create separate accounts for different systems.

At first, create service user.

  1. Login to the vCenter with administrator privileges account. On the left pane, choose 3 horizontal stripes. From the menu, choose Administration tab.

2. Choose User and Groups. From Domain drop-down list find vsphere.local domain.

3. Click ADD button. Type Username and Password for the service user.

4. The user terraform@vsphere.local has been created.

Attach terraform@vsphere.local user with Administrator role to the vCenter.

  1. Choose vCenter object from Hosts and Clusters view. Than, change tab to the Permissions and click ADD.

2. In the new window, make sure to choose vsphere.local Domain. Find user terraform in User/Group line. Locate and choose Administrator Role. Check Propagate to children and press OK.

3. Service user terraform@vsphere.local with Administrator role has been attached to the vCenter. Now, let’s use this user in the deployment process.

Terraform CLI installation

Depending on you system, installation process could be a little bit different from this tutorial.

  1. Go to https://www.terraform.io/downloads and choose Ubuntu/Debian tab.

2. Run these 3 commands and wait unitil installation completed.

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install terraform

3. Now, let’s check installed Terraform version.

terraform --version

VM deployment

To start deployment we need to create three files.

  • vsphere.tf -> This is a main file with all instructions and configurations values, which Terraform needs to apply in the deployment.
  • variables.tf -> This file contains variables used in the vsphere.tf file.
  • terraform.tftvars -> This file contains values of variables provided in the variables.tf file.

For clone process, I have ubuntu20-04-temp (2 vCPU, 2 GB RAM, 25 GB disk). This is earlier prepared VM template with Ubuntu 20.04.


1. At first, create deployment catalog to store Terraform files. Go to this directory.
For each project, create separated catalog.

mateusz@terraform:~$ mkdir terraform-deployment-01
mateusz@terraform:~$ cd terraform-deployment-01

2. Create first file: vsphere.tf

mateusz@terraform:~/terraform-deployment-01$ touch vsphere.tf

3. Create second file: variables.tf

mateusz@terraform:~/terraform-deployment-01$ touch variables.tf

4. Create third file: terraform.tfvars

mateusz@terraform:~/terraform-deployment-01$ touch terraform.tfvars

5. Edit vsphere.tf file.
In contrast to Ansible (YAML files), Terraform uses different syntax – HCL. The structure of the configuration file is a different.

#VMware vSphere Provider
provider "vsphere" {  
  #Set of variables used to connect to the vCenter
    vsphere_server = var.vsphere_server 
    user           = var.vsphere_user
    password       = var.vsphere_password
  
#If you have a self-signed cert
    allow_unverified_ssl = true
  }
  
#Name of the Datacenter in the vCenter
  data "vsphere_datacenter" "dc" {
    name = "HQ"
  }
#Name of the Cluster in the vCenter
  data "vsphere_compute_cluster" "cluster" {
    name          = "Cluster"
    datacenter_id = data.vsphere_datacenter.dc.id
  }
#Name of the Datastore in the vCenter, where VM will be deployed
  data "vsphere_datastore" "datastore" {
    name          = "VMware-iSCSI-01"
    datacenter_id = data.vsphere_datacenter.dc.id
  }
#Name of the Portgroup in the vCenter, to which VM will be attached
  data "vsphere_network" "network" {
    name          = "VLAN-111"
    datacenter_id = data.vsphere_datacenter.dc.id
  }
#Name of the Templete in the vCenter, which will be used to the deployment
  data "vsphere_virtual_machine" "ubuntu20-04" {
    name          = "ubuntu20-04-temp"
    datacenter_id = data.vsphere_datacenter.dc.id
  }
  
#Set VM parameteres
  resource "vsphere_virtual_machine" "ubu-testing" {
    name = "ubu-test"
    num_cpus = 2
    memory   = 4096
    guest_id = "ubuntu64Guest"
    resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
    datastore_id     = data.vsphere_datastore.datastore.id

    network_interface {
      network_id = data.vsphere_network.network.id
    }
  
  
    disk {
      label            = "disk0"
      thin_provisioned = true
      size             = 50
    }
  
  
    clone {
      template_uuid = data.vsphere_virtual_machine.ubuntu20-04.id
#Linux_options are required section, while deploying Linux virtual machines
      customize {
          linux_options {
              host_name = "ubu-test"
              domain = "infra.local"
          }
          network_interface {
              ipv4_address = "10.111.10.215"
              ipv4_netmask = "24"
          }
#There are a global parameters and need to be outside linux_options section. If you put IP Gateway or DNS in the linux_options, these will not be added
          ipv4_gateway = "10.111.10.1"
          dns_server_list = ["192.168.1.121", "192.168.1.1"]
          dns_suffix_list = ["infra.local"]
      }

      
    }
  }
#Outup section will display vsphere_virtual_machine.ubu-testing Name and IP Address
output "VM_Name" {
  value = vsphere_virtual_machine.ubu-testing.name
}

output "VM_IP_Address" {
  value = vsphere_virtual_machine.ubu-testing.guest_ip_addresses
}

To get Terraform ability to communicate and work with VMware vSphere, we need to use VMware vSphere Provider. This provider can be used to manage a set of VMware object in the infrastructure. Note that, VMware vSphere Provider is not supported on a free ESXi license.
Here is a link to the documentation:
https://registry.terraform.io/providers/hashicorp/vsphere/latest/docs

6. Edit variables.tf file.

#set of VM variables to authenticate to the vCenter
variable "vsphere_server" {
  description = "vSphere server"
  type        = string
}

variable "vsphere_user" {
  description = "vSphere username"
  type        = string
}

variable "vsphere_password" {
  description = "vSphere password"
  type        = string
  sensitive   = true
}

7. Edit terraform.tfvars file.

#set of VM values of variables
vsphere_server     = "vcenter.infra.local"
vsphere_user       = "terraform@vsphere.local"
vsphere_password   = "SecretPassword1!"

Execute Terraform deployment

  1. Initialize Terraform workspace (working directory). This command should be used everytime, after writing a new Terraform configuration.
terraform init

2. Apply configuration to start Terraform deployment. This process executes the actions propsed in a Terraform plan.
terraform plan -> creates an execution plan to preview propsed chagnes
–auto-update -> this parameter automatically accept terraform plan
If you skip –auto-update parameter, Terraform ask you to manually accept propsed terraform plan.
In the beggining, there is a list with Terraform changes. This points will be applied according to configuration files.

terraform apply --auto-approve

3. In the meantime let’s have a look to the vCenter. In the Recent Tasks section, there are few new tasks has been initialated by terraform@vsphere.local user.

4. In the terminal window, at the bottom you can see deployment process. When execution successfully complete, there is a status: ‘Apply complete! Resources: 1 added, 0 changed, 0 destroyed’

5. New VM has been created in the vCenter with a name: ubuntu-test. DNS name is ubuntu-test and IP Address is 10.111.10.215.

6. Testing communication between another server in different subnet and ubu-test virtual machine.

mateusz@vm1:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:50:56:93:df:f1 brd ff:ff:ff:ff:ff:ff
    inet 10.50.66.149/24 brd 10.50.66.255 scope global ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:fe93:dff1/64 scope link
       valid_lft forever preferred_lft forever
mateusz@vm1:~$ ping 10.111.10.215
PING 10.111.10.215 (10.111.10.215) 56(84) bytes of data.
64 bytes from 10.111.10.215: icmp_seq=1 ttl=63 time=0.495 ms
64 bytes from 10.111.10.215: icmp_seq=2 ttl=63 time=0.842 ms
64 bytes from 10.111.10.215: icmp_seq=3 ttl=63 time=0.653 ms
64 bytes from 10.111.10.215: icmp_seq=4 ttl=63 time=0.499 ms
^C
--- 10.111.10.215 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3027ms
rtt min/avg/max/mdev = 0.495/0.622/0.842/0.141 ms
mateusz@vm1:~$

7. To delete deployment type command below. Like with terraform apply command, you can add –auto-approve to automatically accept terraform plan.

terraform destroy --auto-approve

Summary

That’s it, we performed deployment of the virtual machine using Terraform.

Terraform is a great provisioning tool. For example, it’s a good choice if you think about orchestrating cloud services. Whereas, Ansible deals better with bare metal or virtual infrastructure platforms. Between this 2 systems there are more differences. All it depends what is your goal and what you need to achive.

3 Comments

  1. Hello Mateusz,

    thanks for the great detail, just I am new on Terraform and vSphere.
    may I ask for a help if want the VM stay on power-off when deploying and manually we bring it on.

    I put power_state=off but keeps give me error.

    thanks for your help!
    Sara

  2. This was instrumental in helping my team learn terraform for vsphere. Thanks for sharing!

Leave a Reply

Your email address will not be published. Required fields are marked *

Search
Author

Hi, I’m Mateusz Romaniuk and welcome to my blog dedicated to virtualization technology. I’m a VMware/Tanzu Administrator in T-Mobile Poland. My mainly responsibilities are to manage and develop virtual enterprise infrastructure.

Contact
Certifications