The next step to learn the Terraform is to get the knowledge on Terraform configuration files and it is one of the important parts you should know before using the terraform. Because this will also give you the complete insight of how Terraform works and how you can utilize the complete feature and functionality of the Terraform. So, As part of the Complete Terraform Tutorial, we will see in detail about the Terraform configuration file.
Table of Contents
So Far!
This is Part -2 of the Complete Terraform Tutorial Series. Before taking this, We recommend you to take a look at the Part -1
Complete Terraform Tutorial Part – 2 – Terraform Introduction
Introduction and Sample Infrastructure creation with AWS to understand the basic flow.
Where we are!
When you want to create the infrastructure with the Terraform, the Terraform Configuration file (HCL) should be executed with the help of Terraform CLI or other executors. The most popular and convenient way is Terraform CLI. So, this article will mainly focus on the Terraform Configuration language of the configuration Files.
Terraform Configuration Language.
As we discussed in the previous part, Terraform will read the configuration file (.tf
) and execute the actions according to that. This Configuration file is written in Terraform’s own language called HashiCorp Configuration Language (HCL) which is easily readable for Human and Machine as well and hence it is called Declarative Language. So, first, we will see the basic elements and structure of the Terraform Configuration Language.
Syntax
First of all, we will discuss the syntax and arguments that are going to be used in the Terraform Configuration file. The following are the basic arguments and syntax that we are going to use in HCL.
# Output variables - this is a commented linecomment output "ec2_instance_id" { # "ec2_instance_id" is Identifier value = instance.ec2.id # "value" is Argument name and "instance.ec2.id" is Argument Value. } resource "aws_instance" "proxy" { ami = "ami-c3b64ac23" instance_type = "t2.nano" }
In above snippet, line number 1 is the commented line. starting and ending of braces “{ ... }
” are called blocks. Line number 4 is called Argument. and “ec2_instance_id
“/”aws_instance
” is called Identifiers.
Resources
Just like any other configuration management platform, Basic element of the terraform is an Resource. It will define the infrastructure object like AWS, AZURE or Kubernetes.
resource "aws_instance" "proxy" { ami = "ami-c3b64ac23" instance_type = "t2.nano" }
In the above snippet, “resource
” is the keyword that defines the resource type as “aws_instance
” and then “proxy
” is the local name of the resource so that we can call this resource block as “proxy
” on the overall configuration file. Then, in between braces “{ ... }
“, we call configuration arguments. like, “ami
” declaring the Amazon Machine Image ID and “instance_type
” is the type of the AWS instance type.
Modules
Modules are collection of one or more resources that will help performing a complete cycle of operations. Basically, Modules can have child modules and that can call each other. So, in a single configuration file, we can call many modules with multiple resources to provisioning or automating the configuration part.
module "app-server" { source = "./app-slaves" servers = 5 }
The snippet defined above is the “module
” block and has “app-server
” as the name of the module. and within the braces “{ ... }
“, we have “source
” that will point the path of the configuration file of the resources. This may either be the local path or remote path from terraform library. “servers
” is the argument for the number of instances that are going to be engaged for the operation.
Providers
As we discussed, Terraform is an Infrastructure Provisional tool. Hence we have to let the Terraform know who is going to provide whichever Resources to build your infrastructure. So, “Provider
” is a block name that defines which infrastructure provides and some parameters of the same.
provider "aws" { version = "~> 2.0" region = "us-east-1" }
In this above snippet, we have defined provider as “aws
” and inside the braces “{ ... }
“, we define “version
” which defines which version of API that can be used by the Terraform. Then, “region
” is the keyword that will define which region the terraform can perform operations.
Variables
Just like any other configuration management system, Terraform is in need of variables that can set some values at anytime of the terraform operation. we have three different variables in the terraform. they are:
Input Variables are mentioned as “variables
” and followed by braces “{ ... }
“.
#Input variables: variable "vm_ports" { type = list(object({ internal = number external = number protocol = string })) default = [ { internal = 80 external = 443 protocol = "http" } ] }
In the above snippet, “vm_ports
” is the variable name and it is declared as list type and hence it is mentioned as “list(object({}))
“. Then it is also having the default values in “default
” section.
Output Variables are like returned variables from after execution of the module. Output variable can be declared as “output
“.
# Output variables output "ec2_instance_id" { value = instance.ec2.id }
So, the above snippet will have the block called “output
” and the name of the variable is “ec2_instance_id
” and this will get the value of executed module. For this case, after the EC2instance creation, it will return the ID of the created EC2 instance and that can be used further to configure the particular created EC2 instance.
Local Variables are basically the variables that are made available within the modules and these are mentioned as “locals
“.
# Local Variables locals { operation_name = "app-server" instance_id = ec2_instance_id }
So, the above snippet shows the list of local variables called “operation_name
” and the “instance_id
“. Just note closely that we have connected the output variable name “ec2_instance_id
” in the “instance_id” and hence it is going to be a dynamic local variable.
Data Source
the data source can be used to feed the Terraform configuration with the set of data from outside the Terraform or from other Terraform Configuration files. These data source block can be defined as “data
” and followed by braces “{ ... }
“.
# Data source. data "aws_ami" "server_ami" { most_recent = true filter { name = "name" values = ["server-*"] } } #resorce that is using data source. resource "aws_instance" "server" { ami = "${data.aws_ami.server_ami.id}" instance_type = "t2.nano" }
So the snippet shows the data block. which will get AWS AMI from the repository or somewhere where the AMIs are listed and prefixed with “server-
“. Then the same data source can be used by the resource mentioned in the snippet as “data.aws_ami.server_ami.id
“.
Built-in Functions
One of the fantastic feature of terraform is built-in functions that perform some logical calculation or some operations.
Terraform Settings
This is basically configuring the terraform itself. Like, mentioning the version of providers’ version or backend. The settings of the Terraform can also be declared as block and the name of the block is “terraform
“.
terraform { backend "akamai" { # (akamai backend settings...) } required_providers { aws = ">= 2.2.0" } }
Basically, the Terraform block will have the some arguments that are applied for the entire Terraform configuration. So the above snippet have back-end setting for “akamai
” and “required_providers
” will have the minimum needed version of API that is going to be used in the terraform configuration. In this example, aws >= 2.2.0.
Overriding the Terraform Files
When you define the same variable in the different Terraform files, we have to override it in order to avoid the Terraform Error. We just have to create an override file called _override.tf
or override.tf
. Assume we have two files called main.tf
and override.tf
. and main.tf
will have the following code.
# main.tf resource "aws_instance" "server" { ami = "ami-ba3c24af" instance_type = "t2.nano" }
Then the other file override.tf
will have the following snippet.
# override.tf resource "aws_instance" "server" { ami = "ami-44aacc3322" }
In the both files, we have ami argument but with different value. But the terraform will take the value from the override file and consolidate the file with following snippet.
# Terrafom Consolidated file resource "aws_instance" "server" { ami = "ami-44aacc3322" instance_type = "t2.nano" }
This merging will happen in following blocks.
All togather, have a look at the following terraform file, which is having almost all the component and syntax mentioned above.
# Specify the provider and access details provider "aws" { region = "${var.aws_region}" } # Create a VPC to launch our instances into resource "aws_vpc" "default" { cidr_block = "10.0.0.0/18" } # Output variable output "address" { value = "${aws_elb.web.dns_name}" } # Example variable variable "key_name" { description = "Desired name of AWS key pair" } variable "aws_region" { description = "AWS region to launch servers." default = "us-west-1" } # Ubuntu Precise 12.04 LTS (x64) variable "aws_amis" { default = { eu-west-1 = "ami-cb03e0f1e" us-east-1 = "ami-1d4969a6" us-west-1 = "ami-b1f61d4" us-west-2 = "ami-d4969880" } } # Built-in function resource "aws_key_pair" "auth" { key_name = "${var.key_name}" public_key = "${file(var.public_key_path)}" }
The above code snippet covers almost all the concepts mentioned above. But don’t expect that it will work as it is. This is just written to give an example.
Conclusion
So, in this article, we have discussed how to write the Terraform Configuration File is written and the various component and syntax of the same. This is the second part of the series of Terraform tutorials. Next, we will discuss on Terraform CLI. Stay tuned and subscribe DigitalVarys for more articles and study materials on DevOps, Agile, DevSecOps, and App Development.
Experienced DevSecOps Practitioner, Tech Blogger, Expertise in Designing Solutions in Public and Private Cloud. Opensource Community Contributor.
Pingback: Terraform Modules - Complete Terraform Tutorial - Part- 5 - Digital Varys
Pingback: Complete Terraform Tutorial Part – 4 – Terraform State - Digital Varys