Terraform Introduction
Nathan Luong | April 15, 2024 |13
What
- A tool for building, changing, and versioning infrastructure safely and efficiently
- Enables applications software best practices to infrastructure
- Compatible with many clouds and services
Installation
brew install terraform
- Install aws-cli
- Create an IAM role and user for the Terraform script to run
Terraform Architecture
Common Patterns
- Used with Ansible to manage configuration, while Terraform doing the Provisioning
- Used with Server Templating Tool
- Used with Orchestration Tools, like Kubernetes, to provision kubernetes clusters
Terraform Commands
High Level
terraform init
: Init the backendterraform plan
: Query AWS, compare the current state of AWS with the terraform fileterraform apply
: Provisioning the changesterraform destroy
: Destroy the ongoing AWS infrastructure
More In depth
terraform init
- Creates a
.terraform
directory inside of the current working directory - It downloads the cloud provider onto the local file system and their metadata
- It downloads other Terraform Modules
terraform plan
- Compare desired state with the actual state
- Create a terraform plan that can get the infrastructure from the desired state to the actual state
- Derived the AWS API calls necessary from the Terraform plans.
terraform apply
- Apply the Terraform plans (API Calls) onto the existing infra and apply infra changes
State File
- Terraform's representation of the world
- JSON file containing information about every resource and data object
- The file can be stored locally or remotely. In an enterprise setting, its common to store remotely
⚠️
Warning
- The state file contains sensitive informations, including passwords, DB access, ...
- It is important to hide, encrypt, or have limited access to the file
Managing State Files
Local Backend
- Simple to get started
- Sensitive values in plain text
- Un-collaborative
- Manual
Remote Backend
- Use Terraform Cloud, or self-managed with S3
- Sensitive Data Encrypted
- Collaboration possible
- Automation possible (Github Actions)
- Increased Complexity
Remote Backend Terraform Cloud
- Free up to 5 users
terraform{
backend "remote"{
organization = "devops-directive"
workspace {
name = "terraform-course"
}
}
}
Remote Backend with AWS S3 and DynamoDB
terraform {
backend 's3' {
bucket = "devops-directive-tf-state"
key = "tf-infra/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-locking"
encrypt = true
}
}
Variables in HCL
Input Variables (var.<name>
)
Used as input arguments for functions
variable "instance_type" {
description = "ec2 instance type"
type = string
default = "t2.micro"
}
Local Variables (local.<name>
)
Used as a repetitive variable within a scope
locals {
service_name = "My Service"
owner = "DevOps Directive"
}
Output Variables (output.<name>
)
Take the value of a returned function call
output "istance_ip_addr"{
value = aws_instance.instance.public_ip
}
AWS Examples
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "example" {
ami = "ami-011899242bb902164" # Ubuntu 20.04 LTS // us-east-1
instance_type = "t2.micro"
}
Simple Architecture
terraform{
backend "s3"{
bucket = "devops-directive-tf-state"
key = "03-basics/webapp/terraform.tfstate"
region = "us-east-1"
dynamodb_table = " terraform-state-locking"
encrypt = true
}
required_providers {
aws = {
source = "harshicorp/aws"
version = "~> 3.0" #????
}
}
}
provider "aws"{
region = "us-east-1"
}
resource "aws_instance" "instance_1" {
ami = "ami-..."
instance_type = "t2.micro"
security_groups = [aws_security_group.instance.name]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World 1" > index.html
python3 -m http.server 8080 &
EOF
}
resource "aws_instance" "instance_1" {
ami = "ami-..."
instance_type = "t2.micro"
security_groups = [aws_security_group.instance.name]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World 1" > index.html
python3 -m http.server 8080 &
EOF
}
resource "aws_instance" "instance_2" {
ami = "ami-..."
instance_type = "t2.micro"
security_groups = [aws_security_group.instance.name]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World 2" > index.html
python3 -m http.server 8080 &
EOF
}
...