Introducing Terraform and the vCloud Provider
It's been a while since I have put virtual pen to virtual paper, but I think now is time to get back into it. I feel it is important to share what you have had the opportunity to learn, and something I am passionate about is helping my fellow engineers work smarter by using automation to improve their work.
I recently had the privilege of assisting with organising, running and presenting at my local VMUG, where I presented briefly on Terraform and how you can benefit from this tool as a regular systems engineer.
In this series, I am going to cover how to use Terraform to demostrate infrastructure as code (IaC) focusing on managing on premises vSphere and vCloud Director environments.
Before we begin, a little about who I am. I am a Technical Architect working for a MSP in the IaaS space. I started automating client environments when PowerShell became a thing, and infrastructure as code feels like a logical continuation of this. I will confess I am no expert in Terraform, so this series is as much about my learning as I hope it beneficial to you.
Why infrastructure as code?
I am a huge advocate of infrastructure as code (IaC), and I have read many blog posts and attended sessions on the subject. However, I have often found the application and examples difficult to apply to managing on premises infrastructure, or traditional virtual machines that many of my customers tend to manage.
IaC principals can help regular systems engineers too. Even if we only use Terraform to provision an environment, then manage via traditional means, we get a number of benefits. As this blog series progresses I will delve into some of the benefits.
Introducing Terraform
Terraform is a provisioning tool. It is part of a growing suite of tools in the infrastructure as code space. Hashicorp describe Terraform this way :
Terraform is the Infrastructure as Code offering from HashiCorp. It is a tool for building, changing, and managing infrastructure in a safe, repeatable way.
Unlike configuration management tools (Puppet, Chef), Terraform lets us start with nothing but the terraform binaries and a configuration file and end up with a complete deployed environment. I was drawn to Terraforms simplicity, it focuses on just one aspect of systems lifecycle management. Compared to other tools in this space, there are a few other factors that make Terraform worth a look for vSphere administrators.
Agent-less - Terraform does not need anything deployed to be able start provisioning, you can event manage existing infrastructure. This reduces the effort required to get to a working and viable implementation.
Simple - Hashicorp Configuration Language (HCL) is reasonably easy to read and grasp, and you can start with statically declared resources before moving on to including variables and conditionals. For basic deployments, this reduces the barrier to entry.
Supported - Much of the environment I manage is vSphere infrastructure. Terraform providers are being actively developed for VMware products, and Vmware reference Terraform in blog post and articles. I understand many of the provider developers are actually VMware staff.
Terraform and vCloud Director
Vmware vCloud Director (VCD) forms part of our IaaS platform offering. It is a capable product and actively being developed and expanded. While VCD is popular with service providers, many of the tools in the IaC space have limited or no support for it. Terraform has significant support for both provider and tenant tasks, and the list grows with each release.
Installing Terraform
I won't go into specifics, because there are plenty of posts that cover getting started. Terraform works on Windows and Linux platforms. I personally use the Linux binaries in Windows Subsystem for Linux. You can follow Hashicorps installation instructions here.
Our first configuration
We will start with a cut down example, deploying a single, simple VM. I will try to stick to the same examples as the official Terraform guides so that the concepts are easy to transfer. Terraform uses text files with the extension .tf. When executing, Terraform reads configuration from all .tf files in the current folder. We will start by creating a file called vcloud_vm.tf.
Firstly we need to define a provider. Terrafrom providers act as the interface between the resource API and our code. Common providers for deploying virtual machines are Azure or AWS. In our case we will be targeting a service provider tenancy with VMware vCloud Director.
provider "vcd" {
user = "username"
password = "password"
org = "Your Organisation"
vdc = "Your Virtual Datacenter"
url = "https://provider.cloud/api"
#This last option allows untrusted or selfsigned certificates
#Don't do this in the 'real world'
allow_unverified_ssl = true
}
The provider requires a number of parameters, most of which should be reasonably self explanatory. I'm not a fan of hard coding usernames and passwords, but for this example we will keep things simple.
After the provider, we describe our virtual machine. Again, because this is a basic example, we will be providing the bare minimum to get us up and running.
Terraform users 'resources' to define the infrastructure we will be provisioning. All configuration is provisioned by resources.
resource "vcd_vapp" "vapp" {
name = "terraform_vapp01"
}
resource "vcd_vapp_vm" "vm1" {
vapp_name = "terraform_vapp01"
name = "terraform_vm01"
catalog_name = "Shared Public"
template_name = "centos-7x"
memory = 2048
cpus = 2
network{
type = "none"
ip_allocation_mode = "NONE"
}
depends_on = ["vcd_vapp.vapp"]
}
We have two resouces in this example. For anyone familiar with vCloud Director will recognise the vApp, which we require before we can deploy a VM. This is handled by the vcd_vapp resource. The vcd_vapp_vm resource defines the deployment of a VM from a VM template called 'centos-7x', with two CPUS and 2GB of RAM. This VM does not connect to a network to make this example as straight forward as possible. The VM resource 'depends on' the vApp being created first. This is a powerful feature of Terraform, enabling us to deploy infrastructure and define any dependencies, rather than having to deploy in stages.
Once we are ready to go, we can jump to the command line. Before we can invoke our configuration, we need to 'initialise' this configuration. Terraform will scan through the .tf files and attempt to install the discovered providers. You should only need to do this step once.
[root@local]# terraform init Initializing the backend... Initializing provider plugins... - Checking for available provider plugins... - Downloading plugin for provider "vcd" (terraform-providers/vcd) 2.5.0... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.vcd: version = "~> 2.5" 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.
Next, we run Terraform apply. I must mention Terraform plan, which validates the configuration and will output what 'would' happen had we run Terraform apply, but for simple configuration I find skipping straight to the apply step.
[root@local]# terraform apply
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:
# vcd_network_routed.net will be created
+ resource "vcd_network_routed" "net" {
+ dns1 = "8.8.8.8"
+ dns2 = "8.8.4.4"
+ edge_gateway = "Test-Gateway"
+ gateway = "192.168.27.1"
+ href = (known after apply)
+ id = (known after apply)
+ name = "terraform_net"
+ netmask = "255.255.255.0"
+ org = "ACME"
+ shared = false
+ vdc = "VDC3"
+ dhcp_pool {
+ end_address = "192.168.27.50"
+ max_lease_time = 7200
+ start_address = "192.168.27.2"
}
+ static_ip_pool {
+ end_address = "192.168.27.100"
+ start_address = "192.168.27.51"
}
}
# vcd_vapp.vapp will be created
+ resource "vcd_vapp" "vapp" {
+ accept_all_eulas = true
+ href = (known after apply)
+ id = (known after apply)
+ ip = (known after apply)
+ name = "terraform_vapp"
+ power_on = true
+ status = (known after apply)
+ status_text = (known after apply)
}
# vcd_vapp_vm.vapp will be created
+ resource "vcd_vapp_vm" "vapp" {
+ accept_all_eulas = true
+ catalog_name = "Shared Public"
+ computer_name = (known after apply)
+ cpus = 2
+ expose_hardware_virtualization = false
+ href = (known after apply)
+ id = (known after apply)
+ ip = (known after apply)
+ mac = (known after apply)
+ memory = 1024
+ name = "terraform_vm01"
+ power_on = true
+ template_name = "centos-7x"
+ vapp_name = "terraform_vapp"
+ network {
+ ip = "192.168.27.101"
+ ip_allocation_mode = "MANUAL"
+ mac = (known after apply)
+ name = "terraform_net"
+ type = "org"
}
}
Plan: 3 to add, 0 to change, 0 to destroy.
Terraform apply validates our configuration, then reaches out to our environment to determine current state and compare our configuration against it. We get a list of what changes Terraform will make, and the opportunity to proceed.
Entering yes at the prompt will start the process. In our case, we will get an output detailing the progress of deploying the VM and it's dependencies. If everything has gone to plan, we should complete with a newly deployed and running virtual machine.
Hopefully, in this simple example you have a taste of what can be achieved with Terraform, and a taste for managing your infrastructure as code. In future posts, I'll be expanding our example to include more of Terraforms capabilities and demonstrate how we can manage whole environments.