Run the following to configure aws creds:
aws configure
-
AWS Access Key ID:
-
AWS Secret Access Key:
-
Default region name: us-east-2
-
Default output format: JSON
Run the following to initialize terraform:
terraform init
Terraform files are files with the .tf
extension.
Terraform generates .tfstate
and .tfstate.backup
files when running terraform apply
, which may contain secrets, and so should NEVER be uploaded to repositories. They should be added to .gitignore
file. Instead, .tfstate
files should be stored in an S3 bucket so the team can reference the same state for infrastructure management. This allows locking state so parallel executions don't coincide. This also enables sharing output vlaues with other Terraform configuration or code.
The following snippet is an example of telling terraform where to store the .tfstate
file. Note, the bucket must first exist in order for this configuration to be valid.
terraform {
backend "s3" {
region = "us-east-1"
key = "terraformstatefile"
bucket = "supersecrets3bucket"
}
}
Terraform also generates .terraform/
directories, which also should NEVER be uploaded to repositories, so they should also be added to .gitignore
files.
Terraform has variables. It is best practice to separate the variables into a separate file, variables.tf
from the main code body, main.tf
.
Terraform references the folder it is in when using terraform apply
, with no way of specifying a specific .tf
file to run. This means every piece of IaC written should be organized into separate folders, or, in Terraform jargon, modules. For instance, the following will not allow us to run terraform apply
for specific pieces of infrastructure, ie .tf
files:
folder/
|- infra1.tf
|- infra2.tf
|- variables.tf
|- terraform.tfstate
|- .terraform.lock.hcl
The more desirable way to organize .tf
files is by modules, like so:
folder/
|- infra1/
|- main.tf
|- variables.tf
|- terraform.tfstate
|- .terraform.lock.hcl
|- infra2/
|- main.tf
|- variables.tf
|- terraform.tfstate
|- .terraform.lock.hcl
terraform init
- Prepare your working directory for other commandsterraform validate
- Check whether the configuration is validterraform plan
- Show changes required by the current configurationterraform apply
- Create or update infrastructureterraform destroy
- Destroy previously-created infrastructureterraform graph
- Generate a Graphviz graph of the steps in an operation. eg:terraform graph > test1_graph.dot
dot -Tsvg test1_graph.dot > test1_graph.svg
terraform.tfstate
files are stored locally by defualt, but can be stored remotely in something like S3. It maps real-world resources to Terraform configuration and tracks resource dependency metadata. Prior to any modification operation, Terraform refreshes the state file.
terraform state
has the following subcommands:list
- List resources in the statemv
- Move an item in the statepull
- Pull current state and output to stdoutpush
- Update remote state from a local state filereplace-provider
- Replace provider in the staterm
- Remove instances from the state- Useful if you want to preserve a resource
show
- Show a resource in the state- Useful to get specifics of a resource managed by Terraform
Terraform has the following primitive types:
- number
replicas = 3
- string
name = "cluster2"
- bool
backup = true
Terraform has complex types which can be divided into 2 subtypes:
- collection: complex types which allow multiple values of one primitive type to be grouped together
- structural: complex types which allow multiple values of different primitive types to be grouped together.
Terraform has the following complex types:
- list (collections)
variable "mylist" { type = list(string) default = ["string1", "string2"] }
- tuple (collections, structural)
```terraform
variable "mylist" {
type = list(string)
default = ("string1", "string2")
}
- map (collections)
- set (collections, structural)
- object (structural)
variable "instructor" { type = object({ name = string age = number }) }
Here is a reference of built-ins.
Consider the following block. What would the Name be?
variable "project-name" {
type = string
default = "prod"
}
resource "aws_vpc" "my-vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = join("-",["terraform", var.project-name])
}
}
The Name
variable would have the value of "terraform-prod".
Terraform functions can be explored in terraform console
Dynamic blocks allow us to dynamically construct repeatable nested configuration blocks inside Terraform. They iterate over complex variable types and output a nested block for each element in the complex variable.
resource "aws_security_group" "my-sg" {
name = 'my-aws-security-group'
vpc_id = aws_vpc.my-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["1.2.3.4/32"]
}
ingress {
... # ingress rules
}
}
vs
resource "aws_security_group" "my-sg" {
name = 'my-aws-security-group'
vpc_id = aws_vpc.my-vpc.id
dynamic "ingress" {
for_each var.rules
content {
from_port = ingress.value["port"]
to_port = ingress.value["port"]
protocol = ingress.value["proto"]
cidr_blocks = ingress.value["cidrs"]
}
}
}