2-terraform tutorial
2-terraform tutorial
========================
Agenda:
=========
What is Infrastructure as Code (IaC)?
What is Terraform?
What are the benefits of using Terraform?
Terraform key features
How to get started using Terraform?
Terraform installation and setup
Terraform providers
Resources
Terraform CLI commands
Terraform variables
State management
Remote backends
What is Infrastructure as Code (IaC)?
What is Terraform?
----------------------
Terraform => infrastructure provisions on the major cloud providers
Configuration mgt => update install the sw on the server, server is alreay
created by
provisioning - server create
What is Iac?
--------------
as Code (IaC) is a practice where infrastructure is managed and provisioned
using code
rather than manual processes.
Similar to application code, the infrastructure code is stored in a version
control systems (VCS),
that ensure infrastructure changes are trackable and scalable.
By defining infrastructure in descriptive, machine-readable files,
IaC enables automation, consistency, and repeatability while reducing human
error.
=> declarative approach allows users to define the desired state of their
infrastructure,
which Terraform then enforces.
This capability extends across various cloud providers and on-premises
environments,
offering flexibility and reducing the complexity of managing multi-cloud or
hybrid environments.
What are the benefits of using Terraform?
---------------------------------------------------
Traditionally, cloud infrastructure was managed manually without IaC
(Infrastructure as Code).
Benefit Description
-------------------
Consistency
Automation
Less risk
Modular and DRY
Declarative
Cloud agnostic
Ecosystem
Extendible
Agentless
terraform-token-busycoder
--------------------
----------------
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
installation step:
https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-
cli
tags = {
Name = "terraform-example"
}
}
terraform init
terraform plan
terraform apply
terraform destroy
terraform init:
we are telling terraform about provider, so that binary code related
to aws provider is configured to this machine-readable
terraform plan:
tell what changes going to happen on aws
terraform apply:
actually create infrastructure on aws
terraform destroy:
how terraform know which resouces to destroy?
terraform matain a file terraform-state.tf file what contain all information
of resouce ie created
using terraform
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p 8080 &
provider "aws" {
region = "ap-south-1"
}
resource "aws_instance" "example" {
ami = "ami-0f1ba6e558ee844a5"
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.instance.id]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p 8080 &
EOF
user_data_replace_on_change = true
tags = {
Name = "terraform-example"
}
}
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
terraform plan
terraform apply
terraform destroy
Terraform input variables are used to pass certain values from outside of the
configuration or module.
They are used to assign dynamic values to resource attributes.
The difference between local and input variables is that input variables
allow you to pass values before the code execution.
They are very useful in both cases. For example, you can build different
connection strings
you can print in the console for easy use in an app, or you can export things
that can be referenced in another configuration/in another module,
facilitating the creation of other resources.
--------------------------------------------------
Examples:
--------------------------------------------------
int i=66;
variable "number_example" {
description = "An example of a number variable in Terraform"
type = number
default = 42
}
variable "list_example" {
description = "An example of a list in Terraform"
type = list
default = ["a", "b", "c"]
}
variable "list_numeric_example" {
description = "An example of a numeric list in Terraform"
type = list(number)
default = [1, 2, 3]
}
variable "map_example" {
description = "An example of a map in Terraform"
type = map(string)
default = {
key1 = "value1"
key2 = "value2"
key3 = "value3"
}
}
variable "object_example" {
description = "An example of a structural type in Terraform"
type = object({
name = string
age = number
tags = list(string)
enabled = bool
})
default = {
name = "value1"
age = 42
tags = ["a", "b", "c"]
enabled = true
}
}
variable "security_group_name" {
description = "The name of the security group"
type = string
default = "terraform-example-instance"
}
--------------------------------------------------
variable "server_port" {
description = "The port the server will use for HTTP requests"
type = number
default = 8080
}
Example:
----------
Note : if not pass default value then terraform will ask the value while creating
plan:
--------------------------------------------------------------------------------
variable "server_port" {
description = "The port the server will use for HTTP requests"
type = number
}
vs
variable "server_port" {
description = "The port the server will use for HTTP requests"
type = number
default = 8080
}
-------------------------
main.tf
---------
variable "server_port" {
description = "The port the server will use for HTTP requests"
type = number
default = 8080
}
provider "aws" {
region = "ap-south-1"
}
user_data_replace_on_change = true
tags = {
Name = "terraform-example"
}
}
terraform plan
terraform apply
terraform destroy
vim variables.tf
-----------------
variable "server_port" {
description = "The port the server will use for HTTP requests"
type = number
default = 8080
}
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP address of the web server"
}
Example:
---------
main.tf
----------
variable "server_port" {
description = "The port the server will use for HTTP requests"
type = number
default = 8080
}
provider "aws" {
region = "ap-south-1"
}
user_data_replace_on_change = true
tags = {
Name = "terraform-example"
}
}
terraform plan
terraform apply
terraform destroy
cat terraform.tfstate
it contain information in json formate about all the resources created
mkdir test1
and run 6-a-bucket-DynamoTable.tf
mkdir test2
and run 6-b-RemoteBackend.tf
terraform plan
terraform apply
terraform destroy
dev
stage
prod
How to create new workspace?
----------------------------
terraform workspace allow you to store your terraform state in multiple
seperate , named workspace. terraform start with a single workspace
called "default"
Terraform workspace allow to run terraform workspace new and deploy an new
copy of exact same infrastructure
but storing the state in a seperate file
The state file of all the workspaces are stored in the same backend
workspace is not visible in the code on the terminal unless you run terraform
workspace command
What if i want to create more then resouce with the same configuration?
loop
main.tf
-------------------
provider "aws" {
region = "ap-south-1"
}
terraform init
terraform plan
main.tf
-----------
provider "aws" {
region = "ap-south-1"
}
resource "aws_iam_user" "example" {
count = length(var.user_names)
name = var.user_names[count.index]
}
variables.tf
-----------
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["devops", "test", "test1"]
}
outputs.tf
-----------
output "first_arn" {
value = aws_iam_user.example[0].arn
description = "The ARN for the first user"
}
output "all_arns" {
value = aws_iam_user.example[*].arn
description = "The ARNs for all users"
}
terraform init
terraform plan
----------------
check all user created as per requirments
terraform apply
terraform destroy
Terraform Taints:
-----------------
Terraform maintains a state file that contains the innformations regrarding
thie real world resouces managed by terrafrm IaC
When a resouce becomre misconfigured or corrupt it is desirable to replace
them with new instances , the taint command updates
the corrospoing resouces state as a "tainted" resouces so that in the next
apply
cycle, terraform replace that resouces
Example:
--------
mkdir demo2
cd demo2
main.tf
-----------
provider "aws" {
region = "ap-south-1"
}
resource "aws_instance" "devops" {
ami = "ami-0f1ba6e558ee844a5"
instance_type = "t2.micro"
tags = {
Name = "devops",
}
}
tags = {
Name = "busycoder",
}
}
-------------------
Usage:
terraform init
terraform apply
terraform taint aws_instance.devops
ls
cat terraform.tfstate | grep taint
Now apply command terraform will recreate new ec2 instance (that was tainted)
------------------------------------------------------------
terraform apply
main.tf
--------
provider "aws" {
region = "ap-south-1"
}
variable "username"{
type= list(string)
default = ["foo","bar","jar"]
}
tags = {
tag-key = "tag-value"
}
}
policy = <<EOT
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:ListAllMyBuckets"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
EOT
}
terraform init
terraform apply
-----------------
seven resouce will be created
terraform destroy
misc:
-------------
you need to write terraform code to create s3 bucket and dynamodb table
need to spefiy the remote backend configuration to your terraform code everytime
and run terraform init
Now in case if you want to delete S3 and dynamodb table you need to first remove
this configuration
from your code, rerun the terraform init command to tfstatefile locally to your
disk and finally run terraform destroy
so it is two way processes
main.tf
-------------
terraform {
required_version = ">= 1.0.0, < 2.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
provider "aws" {
region = "ap-south-1"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "ddevops-techstack21-busycoder1"
// This is only here so we can destroy the bucket as part of automated tests. You
should not copy this for production
// usage
force_destroy = true
# Enable versioning so you can see the full revision history of your
# state files
resource "aws_s3_bucket_versioning" "enabled" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
attribute {
name = "LockID"
type = "S"
}
}
----------
terraform init
terraform plan
terraform apply
terraform destroy
--------------
create a dir : backend
cd backend
and create the resouces
-----------------------
# backend.hcl
----------------------
bucket = "ddevops-techstack21-busycoder1"
region = "ap-south-1"
dynamodb_table = "ddevops-techstack21-busycoder1"
encrypt = true
---------
main.tf
--------
terraform {
backend "s3" {
key = "example/terraform.tfstate"
}
}
provider "aws" {
region = "ap-south-1"
}
tags = {
Name = "terraform-example"
}
}
------------------
terraform init -backend-config=backend.hcl
terraform plan
terraform apply
terraform destroy
Example: Build WebApp Cluster on AWS Cloud
--------------------------------------------
We will demonstrate how you can create scalable web app cluster on AWSCloud
using terraform.
Step 1:
1. define launch configuration, used by auto scaling group
Important ref:
--------------
terraform beginer guide
https://k21academy.com/terraform-iac/terraform-beginners-guide/