Posted on 31.5.2019

Terraform best practices for beginners

Terraform is one of our favourite infrastructure management tools, and when it comes to configuring infrastructure as code, there’s none quite like it. With the extensive list of features, modules, and extensions, there is a lot of information to digest. Therefore, to give you a head start, we’ve compiled a quick list of Terraform best practices.

Terraform logo

If you’d prefer to skip the documentation and jump right into the action, make sure to check out our quick start guide to Terraform on UpCloud. Otherwise, here are a few good practices for Terraform beginners.

Use variable files

Variables on Terraform are a great way to pack your configuration with easily readable data. As with any programming language, variables take different forms based on the information you want them to store. Yet with cloud provider-specific parameters, these can get difficult to manage. Hence, instead of filling up your Terraform configuration file with variable definitions, put them in their own variable file. Consolidating variables allows you to easily share configurations while still being able to change values when needed. For additional customisability, Terraform provides a couple of ways to include variable files in your configuration.

To allow Terraform to automatically load the variables, the file should be named terraform.tfvars or *.auto.tfvars and placed in the same directory as your Terraform configuration file. Variable files that are loaded automatically will be done so in alphabetical order.

Alternatively, you can include the variable file using the command-line parameter -var-file and then specify a path to a variable file.

terraform apply -var-file="testing.tfvars"

If a value is defined more than once, they are either merged together like maps or overwritten as with any other variable type. For example, if you have a default deployment configuration with set parameters, you can customise the values by creating a second variable file that includes only the values you wish to define differently. The last loaded value by a certain name will be used.

Use the self variable

The general variables are useful in multiple ways but lack one feature, knowing the future! Joking aside, self variables are a special kind of values specific to your resources that are populated at creation. This allows you to use even parameters that are calculated during deployment and otherwise impossible to know beforehand. For example, self.ipv4_address can be used to define an SSH connection after the initial deployment although the IP address is not known until it gets assigned.

By following the syntax of self.ATTRIBUTE, you can reference any data related to the resource that is listed during the planning command. However, note that the self.ATTRIBUTE syntax is only allowed and valid within provisioners.

Use strings for booleans and boolean comparisons

Terraform supports a number of different type of variables including strings for text and booleans for true or false values. Ideally, each would be used as intended to create a consistent set of variables. However, it’s recommended for the time being to specify boolean values as string variables "true" and "false". This is to avoid some caveats in how Terraform converts the values at runtime.

Careful use of boolean variables should not cause issues with the variable processing but depending on where you specify the values, the behaviour can differ. Boolean variables in .tfvars variable files are converted to “0” and “1” values. On the other hand, variables specified via the -var command-line flag will be literal strings “true” and “false”. Therefore, care should be taken when using “0” or “1” explicitly.

A future version of Terraform is expected to fully support first-class boolean types. It should hopefully make the behaviour of booleans consistent and work as you would expect. You can read more about the current behaviour at the documentation of Terraform variables.

Take advantage of built-in functions

Terraform comes with a boatload of built-in functions that can be used for anything from math operations to file manipulation. For example, you can utilize the built-in function interpolation to read your private SSH key file file("~/.ssh/terraform_rsa").This allows you to create an SSH connection securely without saving the key itself anywhere in the configuration.

Another very useful function is lookup(map, key, [default]). It performs a dynamic search to find a value based on the selected key from a map variable. The key can also be a variable itself allowing one variable to dictate the value of another. For example, you could select the appropriate storage size based on your server plan even using nested lookups like in the example below.

storage = lookup(var.storages,lookup(var.plans,var.config,"1xCPU-1GB"),"25")
variable storages {
   type = map
   default = {
      "1xCPU-1GB" = "25"
      "1xCPU-2GB" = "50"
      "2xCPU-4GB" = "100"
   }
}

variable plans {
   type = map
   default = {
      "5USD"  = "1xCPU-1GB"
      "10USD" = "1xCPU-2GB"
      "20USD" = "2xCPU-4GB"
   }
}

variable config {
   default = "5USD"
}

If the key does not exist in the map, the interpolation will fail. To avoid issues, you should specify a third argument, a default string value that is returned if the key could not be found. Do note though that this function only works on flat maps and will return an error for maps that include nested lists or maps.

Auto format Terraform files

Anyone who has even a little experience in programming is likely to know the importance of formatting for readability. A big part of clean formatting revolves around line spacing, code block indentations, and bracket usage. All of these are relatively simple to follow but fixing code at later stages will take far more effort. Luckily, Terraform includes a simple to use a tool called fmt that will take care of formatting.

Check your configuration formatting and make them neat by running the following command.

terraform fmt -diff

The formatting command rewrites Terraform configuration files in a canonical format and style. It applies the Terraform language style conventions as well as other minor adjustments to improve readability. By default, the command checks all Terraform files within the working directory, but can also be run recursively in subdirectories. Check the command help text to learn more.

terraform fmt --help

Occasionally running the Terraform formatting tool will help you maintain consistency throughout your Terraform configuration. In addition, any files automatically generated by Terraform will also follow the same styling rules used by terraform fmt to further assist in keeping your infrastructure configuration neat and tidy.

Stay up to date

Terraform is in active development and gets occasional feature and functionality upgrades, especially with the major releases. Thanks to the fast-paced development, upgrading from one version to the next may require small changes on your end. It’s recommended to keep updating to latest Terraform versions as they become available because making large leaps in Terraform versions might require multiple changes at once due to version upgrades. Luckily, each release includes some additional functionality to help with the upgrade.

Check for updates by running the version command.

terraform -v
Terraform v0.13.6

Your version of Terraform is out of date! The latest version
is 0.14.5. You can update by downloading from www.terraform.io/downloads.html

Thanks to how Terraform installation is distributed in a single file, getting the latest version is simple. Upgrade your Terraform by downloading the newest version and extracting it to a directory found in your PATH variable. Terraform also provides upgrade guides to help with the transition.

wget https://releases.hashicorp.com/terraform/0.14.5/terraform_0.14.5_linux_amd64.zip
sudo unzip terraform_0.14.5_linux_amd64.zip -d /usr/local/bin

As your Terraform infrastructure grows, you might want to consider employing tfenv to version your Terraform configurations. The tfenv tool is one of the additional Terraform utilities and helps you manage Terraform versions for different configurations. You can find out more at the tfenv GitHub page.

Use modules in moderation

Modules in their simplest are containers for multiple resources that are often used together. The very basis of your infrastructure is built on the so-called root module which includes all of your resources as defined in the .tf files in your top-level Terraform directory.

Additional modules can bring in some useful features like preconfigured load balancers or Kubernetes clusters. However, the more modules you add to your infrastructure, the more complex your configuration gets.

With the added complexity also comes slower code execution and increased difficulty for debugging. Take advantages of the many available modules as you like but keep in mind the downsides. Modules represent a balancing act for the administrators and it’s recommended to use them in moderation.

Organise your workspaces

Using Terraform to build your environment can be empowering and the thought of single command deployment is tempting. Nevertheless, you should not use a single Terraform workspace to manage everything. Instead, split your environment into smaller easier to manage workspaces. For example, development, staging, and production should all have their own workspaces. This way each workspace is easier to maintain and delegate.

Another trick to keeping your workspaces organised is adopting a consistent naming convention. For example, you could name your workspaces by their component and environment. Hierarchical naming scheme will help you maintain your infrastructure and keeping it easily understandable.

Manage workspaces in teams

One of the great things about Terraform is how easily it can be adopted by environments of any size. It can scale from a small single-person project to an enterprise-level infrastructure managed by multiple teams.

If you are working on a Terraform infrastructure together with others, splitting the code into smaller segments will help you share the workload. Each piece of your infrastructure can be managed as an individual Terraform configuration with limited scope and delegated ownership by a specific team.

Back up your system state

Last but definitely not least, make backups of your system state.

The state file is used by Terraform to keep track of resources and metadata while improving performance for larger infrastructures. By default, the state of your environment is stored locally in your Terraform workspace directory in a file called terraform.tfstate along with a backup file called terraform.tfstate.backup.

These state files are important for maintaining relevant information about the resources in your infrastructure. Without them, Terraform will not know which resources have already been deployed and how to reach them. Therefore, it’s essential to keep a backup of your state file for any maintained environment.

Terraform provides a convenient way of storing your state file remotely using remote_state. It allows you to retrieve state data to use along with your root-level outputs for one or more Terraform configurations as input data for another.

Summary

We hope you’ve found some informative value in these tips and tricks. While not an all exhaustive list of instructions, they should prove helpful and provide new inspiration for better infrastructure as code. By following established practices, you can maintain sanity in configuration and write clean readable code.

A big part of Terraform is to improve workflow for infrastructure provisioning. Setting yourself on the right path straight from the beginning will help you to create a solid foundation of Terraform best practices that allow you to build upon in the future!

Get started with Terraform today!

Janne Ruostemaa

Editor-in-Chief

From side project to professional tool: The story behind UpCloud’s Terraform Provider

Dive into the story behind UpCloud’s Terraform Provider with Ville Vesilehto, Lead Product Manager at UpCloud. Grab a coffee and get reading! As someone who’s been involved with the UpCloud Terraform Provider from its inception to its current state, I want to share the journey of how a weekend project evolved into an essential tool […]

People

UpCloud Insights

UpCloud becomes verified Terraform provider along with major update

Terraform is a popular open-source software tool created by HashiCorp. Terraform allows users to define infrastructure-as-code using a simple, human-readable language. It enables you to take full control of your cloud infrastructure using declarative configuration files to manage services and resources. The UpCloud Terraform provider module integrates our infrastructure with Terraform and has been available […]

Announcements

Open Source

Product Updates

UpCloud’s development roadmap: What to look forward to in 2021

The year has turned, and UpCloud welcomes you to 2021, ready again to show you what the best cloud infrastructure can offer for your business. The last year has proven the capabilities of our brand, products and most importantly, the strength of our teams. We’ve been happy to see many new users coming and staying […]

Announcements

Vision and culture

Back to top