Terraform Notes
Terraform Notes
notes
FOR DEVOPS ENGINEERS
Train With
Shubham
Terraform Short Notes
Introduction
Challenges in IT Infrastructure
Train With
Shubham
Terraform
Terraform is HashiCorp's infrastructure as a code tool. It lets you define
resources and infrastructure in human-readable, declarative configuration files
and manages your infrastructure's lifecycle. Using Terraform has several
advantages over manually managing your infrastructure:
Terraform can manage infrastructure on multiple cloud platforms.
The human-readable configuration language helps you write infrastructure
code quickly.
Terraform's state allows you to track resource changes throughout your
deployments.
You can commit your configurations to version control to safely collaborate on
infrastructure.
Installation
Linux
sudo apt-get update && sudo apt-get install -y gnupg software-
properties-common
wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
gpg --no-default-keyring \
--keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
--fingerprint
Train With
Shubham
HCL
Hashicorp Configuration Language, This low-level syntax of the Terraform
language is defined in terms of a syntax called HCL, which is also used by
configuration languages in other applications, and in particular other
HashiCorp products. It is not necessary to know all of the details of HCL
syntax in order to use Terraform, just knowing the basics, should be enough.
The Terraform language syntax is built around two key syntax constructs:
arguments and blocks.
Blocks and Arguments
A block is a container for other content and An argument assigns a value to a
particular name:
filename = "/home/ubuntu/abc123.txt"
The identifier before the equals sign is the argument name, and the
expression after the equals sign is the argument's value.
Train With
Shubham
Resource block: block name used to mention the type of the block. The
resource block expects two labels, which are local_file and “pet” in the
example above. A particular block type may have any number of required
labels, or it may require none.
output "rand-str" {
value = random_string.rand-str[*].result
}
Execution of Infrastructure
Init -> plan -> apply
terraform init
This command will scan your tf files in that folder and install all the required
automation things.
Train With
Shubham
terraform plan
This command will create an execution plan for terraforming, the things
that will be installed, the names, and the properties added.
terraform apply
Terraform block
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 2.21.0"
}
}
}
Provider
The provider block configures the specified provider, in this case, docker.
A provider is a plugin that Terraform uses to create and manage your
resources.
provider "docker" {}
Train With
Shubham
Resource
Use resource blocks to define components of your infrastructure. A
resource might be a physical or virtual component such as a Docker
container, or it can be a logical resource such as a Heroku application.
Resource blocks have two strings before the block: the resource type and
the resource name. In this example, the first resource type is
docker_image and the name is Nginx.
Train With
Shubham
More Terraform commands:
terraform fmt
terraform validate
terraform show
terraform state list
Terraform Variables
We can create a variables.tf file which will hold all the variables.
variable "filename" {
default = "/home/ubuntu/terrform-tutorials/terraform-variables/demo-
var.txt"
}
variable "content" {
default = "This is coming from a variable which was updated"
}
variable "file_contents" {
type = map
default = {
"statement1" = "this is cool"
"statement2" = "this is cooler"
}
}
Train With
Shubham
List
Train With
Shubham
Set
Object
variable "devops" {
type = object({
name = string
items = list(number)
})
default = {
name = "shubham"
items = [1,2,3,4]
}
}
Train With
Shubham
Outputs
output "devops-op" {
value = var.devops.name
}
output "devops-items" {
value = var.devops.items
}
Train With
Shubham
Terraform State
Whenever we do terraform init, the plugins are installed
Whenever we do a terraform plan, the execution plan is generated
Whenever we do terraform apply, the execution is done and state is
maintained
If we don’t have state we can still run the above commands, but state
is useful to keep a record of why and how infrastructure was created at
the first place.
State is like a blueprint of the Real-world Infrastructure with some
unique IDs and attributes.
Train With
Shubham
Terraform with AWS
Provisioning on AWS is quite easy and straightforward with Terraform.
Prerequisites
AWS CLI installed (Done)
The AWS Command Line Interface (AWS CLI) is a unified tool to manage
your AWS services. With just one tool to download and configure, you can
control multiple AWS services from the command line and automate them
through scripts.
In order to connect your AWS account and Terraform, you need the access
keys and secret access keys exported to your machine.
Train With
Shubham
Install required providers
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
Add the region where you want your instances to be
provider "aws" {
region = "us-east-1"
}
output "instance_pub_ip" {
value = aws_instance.aws_ec2_test[*].public_ip
}
Train With
Shubham
AWS S3
For s3, the bucket name should be unique
tags = {
Name = "trainwithshubham-bucket"
Environment = "Dev"
}
}
Train With
Shubham
States
Terraform uses state to keep track of the infrastructure it manages. To
use Terraform effectively, you must keep your state accurate and secure.
For small infrastructures, terraform can query your providers and sync
the latest attributes from all your resources. This is the default
behaviour of Terraform: for every plan and application, terraform will
sync all resources in your state.
State Locking
State locking happens automatically on all operations that could write
state. You won’t see any message that it is happening. If state locking
fails, terraform will not continue. You can disable state locking in most
commands with the -lock flag but it is not recommended.
Train With
Shubham
Terraform has a force-unlock command to manually unlock the state if
unlocking failed.
Syntax
Sensitive Data
Terraform state can contain sensitive data, e.g. database password, etc.
When using a remote state, the state is only ever held in memory when
used by Terraform.
The S3 backend supports encryption at rest when the encrypt option is
enabled. IAM policies and logging can be used to identify any invalid
access. Requests for the state go over a TLS connection.
Note
Setting an output value in the root module as sensitive prevents
Terraform from showing its value in the list of outputs at the end of
terraform apply. However, output values are still recorded in the state
and so will be visible to anyone who is able to access the state data.
output "db_password" {
value = aws_db_instance.db.password
description = "The password for logging
in to the database."
sensitive = true
}
Train With
Shubham
Backend Management
A backend in Terraform determines how state is loaded and how an
operation such as apply is executed
Terraform must initialize any configured backend before use.
Local
By default, terraform uses the “local” backend. After running first
terraform apply the terraform.tfstate file created in the same directory
of main.tf
terraform.tfstate file contains JSON data.
The local backend stores state on the local filesystem, locks the state
using system APIs, and performs operations locally
terraform {
backend "local" {
path = "relative/path/to/terraform.tfstate"
}
}
Remote
When working with Terraform in a team, the use of a local file makes
Terraform usage complicated because each user must make sure they
always have the latest state data before running Terraform and make sure
that nobody else runs Terraform at the same time.
With a remote state, terraform writes the state data to a remote data
store, which can then be shared between all members of a team.
terraform {
backend "remote" {}
}
Modules
A module is a simple directory that contains other .tf files. Using
modules we can make the code reusable. Modules are local or remote.
variable "image_id" {
type = string
}resource "aws_instance" "myec2" {
ami = var.image_id
instance_type = "t2.micro"
}
output "instance_ip_addr" {
value = aws_instance.myec2.private_ip
}
module "dbserver" {
source = "./db"
image_id = "ami-0528a5175983e7f28"
}
Train With
Shubham
Module outputs are very similar to module inputs, an example in a
module output:
output "privateip" {
value = aws_instance.myec2.private_ip
}
Debugging in Terraform
Terraform has detailed logs that can be enabled by setting the TF_LOG
environment variable to any value.
You can set TF_LOG to one of the log levels TRACE, DEBUG, INFO, WARN
or ERROR to change the verbosity of the logs.
export TF_LOG=TRACE
To persist logged output, you can set TF_LOG_PATH
TF_LOG_PATH=./terraform.log
Terraform Functions
The Terraform language includes a number of built-in functions that you
can use to transform and combine values
max(5, 12, 9)
12
The Terraform language does not support user-defined functions, and so
only the functions built into the language are available for use
Train With
Shubham
into the language are available for use
Some other example built-in functions
element retrieves a single element from a list
element(["a", "b", "c"], 1)
b
lookup retrieves the value of a single element from a map, given its key
lookup({a="ay", b="bee"}, "c", "what?")
what?
Train With
Shubham
Provisioners
Provisioners can be used to model specific actions on the local machine or
on a remote machine to prepare servers or other infrastructure objects for
service. Provisioners are inside the resource block. Note: Provisioners
should only be used as a last resort. For most common situations there
are better alternatives.
file Provisioner
The file provisioner is used to copy files or directories from the machine
executing Terraform to the newly created resource.
local-exec Provisioner
The local-exec provisioner requires no other configuration, but most other
provisioners must connect to the remote system using SSH or WinRM.
Train With
Shubham
remote-exec Provisioner
The remote-exec provisioner invokes a script on a remote resource after
it is created. This can be used to run a configuration management tool,
bootstrap into a cluster, etc.
Creation-time Provisioners
By default, provisioners run when the resource they are defined within is
created. Creation-time provisioners are only run during creation, not
during updating or any other lifecycle. They are meant to perform
bootstrapping of a system. If a creation-time provisioner fails, the
resource is marked as tainted. A tainted resource will be planned for
destruction and recreation upon the next terraform apply.
Destroy-time Provisioners
if when = “destroy” is specified, the provisioner will run when the
resource it is defined within is destroyed.
Train With
Shubham
Terraform with AWS
Setup an AWS user for use with Terraform
We now need to create an AWS user that we can use with Terraform. We
are going to create an account which has administrator permissions.
1. Log into your AWS account and you have access and go to the IAM
section, you can do this by searching for IAM in the search box on the
main AWS page and then clicking on the link
2. 2 Select Users from the left-hand menu
3. Select Add User at the top
4. Type in any username you like
5. For access type select Programmatic access only
6. Click Next
7. On the set permissions screen select.
Train With
Shubham
You need to create a file and with the following text, replacing the two
placeholders with the access key id and secret access key you got from
AWS when you created your admin user.
1 [default]
2 aws_access_key_id = <access_key_id_here>
3 aws_secret_access_key = <secret_access_key_here>
Lastly save the file to the path given in the table below based on your
OS:
Meta-Arguments in Terraform
Count
for_each
depends_on
Count
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = "us-east-1"
}
tags = {
Name = "Server ${count.index}"
}
}
for_each
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
provider "aws" {
region = "us-east-1"
}
locals {
ami_ids = toset([
"ami-0b0dcb5067f052a63",
"ami-08c40ec9ead489470",
])
}
ami = each.key
instance_type = "t2.micro"
tags = {
Name = "Server ${each.key}"
}
} Train With
Shubham
Multiple key value iteration
locals {
ami_ids = {
"linux" :"ami-0b0dcb5067f052a63",
"ubuntu": "ami-08c40ec9ead489470",
}
}
ami = each.value
instance_type = "t2.micro"
tags = {
Name = "Server ${each.key}"
}
}
Train With
Shubham
Thank You Dosto
Train With
Shubham
Train With
Shubham