Terraform and vSphere - mk3

This article focuses on improving upon our mk2 VM deployment project.



Introduction

In our previous article, we improved on our mk1 deployment and developed it into a production-ready deployment.

Today I will be looking at how we can package our mk2 deployment into a consumable module. For the complete code example, please see the GitHub link here: vsphere-vm-mk3 repository

Modules

A significant timesaver when working with TF code is using modules in your code wherever feasible. When we started revising our mk1 vSphere project, we split our components into separate files such as variables.tf and outputs.tf. Doing so was valuable from a file visibility perspective, but what if we wanted to add in an additional step of provisioning a DNS record? We could probably add other files and name them accordingly, like variables_dns.tf, and so forth, which could quickly become cumbersome and difficult to manage.

What if you wanted to share your deployment project with another team so they could add your work into their workflow?

What if you wanted to try and reuse code effectively?

These are some of the types of questions and scenarios that TF Modules effectively address.

Terraform modules are basically just a collection of tf files in a directory. In fact, you’ve already been running the root module (the directory where you run terraform commands from). Essentially what we going to do is take the root module (the .tf files of our mk2 vSphere deployment) and place those files in a unique sub-directory. Here’s an example of how you can place the mk2 files for the mk3 deployment:

mk2. folder layout


1
2
3
4
5
6
.
├── main.tf
├── variables.tf
├── outputs.tf
├── versions.tf
└── terraform.tfvars

mk3. folder layout


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
.
├── deployment.tf
├── root_variables.tf
├── terraform.tfvars
└── modules
 └── vsphere-vm-mk3
  ├── README.md
  ├── LICENSE
  ├── main.tf
  ├── variables.tf
  ├── outputs.tf
  └── versions.tf

There are some noteworthy changes to the file and folder structure in the new mk3 folder example. We created a modules folder in our root directory for starters. This is going to contain the modules we produce internally.

The modules folder name and path can be customized. The relative path to the modules folder from the root module is specified in our deployment workflow.

After creating a new modules directory, I created a sub-directory called vsphere-vm-mk3.

Next we make a copy of the variables.tf called root_variables.tf, move the files initially created in our mk2 example except the terraform.tfvars file.

This should leave us with a copy of our variables and our terraform.fvars file in our main directory.


deployment.tf

The deployment.tf file will contain the code responsible for locating and calling our modules. You can think of the deployment.tf as our orchestration file. I’ve included an example below:.

 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
#### deployment.tf contents ####

module "vsphere-vm-mk3" {
  source = "./modules/vsphere-vm-mk3"

  vsphere_user                 = var.vsphere_user
  vsphere_password             = var.vsphere_password
  vsphere_server               = var.vsphere_server
  vsphere_allow_unverified_ssl = var.vsphere_allow_unverified_ssl
  vsphere_datacenter           = var.vsphere_datacenter
  vsphere_datastore            = var.vsphere_datastore
  vsphere_compute_cluster      = var.vsphere_compute_cluster
  vsphere_network              = var.vsphere_network
  vsphere_template             = var.vsphere_template
  vm_name                      = var.vm_name
  vm_domain_name               = var.vm_domain_name
  vm_num_cpus                  = var.vm_num_cpus
  vm_memory                    = var.vm_memory
  vm_ipv4_address              = var.vm_ipv4_address
  vm_ipv4_netmask              = var.vm_ipv4_netmask
  vm_ipv4_gateway              = var.vm_ipv4_gateway
  vm_dns_server_list           = var.vm_dns_server_list
  vm_dns_suffix_list           = var.vm_dns_suffix_list

}
output "vm_ip_address" {
  value = module.vsphere-vm-mk3.vm_ip_address
}
output "vm_hostname" {
  value = module.vsphere-vm-mk3.vm_hostname
}

In the example above, we create the module block, define our module source, and add inputs and outputs. Because we kept a copy of our initial variables.tf file, we can reuse our declared variables for our terraform.tfvars.

We also define an outputs section within our deployment.tf file to access the module-specific outputs. We do this using the following method of ‘module.<MODULE NAME>.<OUTPUT NAME

DON’T FURGIT INIT :)

If you are following along in your own lab, don’t forget to run terraform init after creating your module code block. This will initialize the module for terraform to use.


Supplemental Files

I mentioned the supplemental files README.md, and LICENSE earlier in this post, and I’ll go into more detail on them here.

Readme

A great practice to get into the habit of is creating a readme file for any project or code you plan to spend time on. For one, it’s a great way to help get your mind back on what you worked on if you end up taking a break from it. It’s also a must-have if you plan to share your module with others or publish it to the Hashicorp registry.

terraform-docs is a tool that can generate useful documentation for your readme.

Licensing

If you’ve worked in software development before, this one is probably a no-brainer.

However, you may not have known that a license file was a necessary component of your code if you are like me. A license file tells people how they can use your code and is essential in a module that will be shared. This is an excellent resource for understanding open source licensing: opensource.guide


Closing Thoughts

This has been a quick primer on creating and using local modules. There is a TON more to learn about modules, child modules, nested modules, etc., and I will be sure to try covering those topics in the future. I highly recommend reviewing the documentation Hashicorp has put together in the following links:

Thanks for reading! I hope this has been helpful.