Terraform guide 6 - Terraform 0.12
Terraform: Terraform 0.12
Setup and disclaimer
Install Terraform 0.12
1
2
3
4
5
6cd /tmp
sudo curl -O https://releases.hashicorp.com/terraform/0.12.2/terraform_0.12.2_linux_amd64.zip
sudo unzip terraform_0.12.2_linux_amd64.zip
sudo cp terraform /usr/bin/terraform12
# check up
terraform12 versionSetup a Terraform 0.12 directory
1
2
3
4
5
6
7
8
9
10
11
12mkdir /home/your_user/terraform/t12
cd /home/your_user/terraform/t12
cp -r /home/your_user/terraform/basics .
cd basics
rm -r .terraform
# test
terraform12 init
# also copy AWS/storage
cd /home/your_user/terraform/t12
cp -r ../AWS/storage .
cd storageEdit
main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#---------storage/main.tf---------
# Create a random id
resource "random_id" "tf_bucket_id" {
byte_length = 2
}
# Create the bucket
resource "aws_s3_bucket" "tf_code" {
bucket = "${var.project_name}-${random_id.tf_bucket_id.dec}"
acl = "private"
force_destroy = true
tags = {
Name = "tf_bucket"
}
}Work with Terraform
- Terraform 12
1
2
3
4
5
6
7
8
9
10
11
12# setup AWS keys
export AWS_ACCESS_KEY_ID="[ACCESS_KEY]"
export AWS_SECRET_ACCESS_KEY="[SECRET_KEY]]"
export AWS_DEFAULT_REGION="us-east-1"
terraform12 init
# deploy
terraform12 apply -var project_name=la-terraform -auto-approve
# clean up
terraform12 destroy -var project_name=la-terraform -auto-approve
ls -la
rm -r .terraform terraform.tfstate* - Older version
1
2
3terraform init
terraform apply -var project_name=la-terraform -auto-approve
terraform destroy -var project_name=la-terraform -auto-approve
- Terraform 12
Working with resources
- environment:
/home/your_user/terraform/t12/storage
- example with storage
- Edit
main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# Create a random id
resource "random_id" "tf_bucket_id" {
byte_length = 2
}
# Create the bucket
resource "aws_s3_bucket" "tf_code" {
bucket = format("la-terraform-%d", random_id.tf_bucket_id.dec)
acl = "private"
force_destroy = true
tags = {
Name = "tf_bucket"
}
} - Work with Terraform
1
2
3
4
5
6
7
8
9# Setup AWS access key
export AWS_ACCESS_KEY_ID="[ACCESS_KEY]"
export AWS_SECRET_ACCESS_KEY="[SECRET_KEY]]"
export AWS_DEFAULT_REGION="us-east-1"
terraform12 init
terraform12 apply -auto-approve
# clean up
terraform12 destroy -auto-approve
- Edit
Input variables
Refactor the previous storage module by adding in variables
- Edit
variables.tf
1
2
3variable "project_name" {
type = string
} - Edit
main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14# Create a random id
resource "random_id" "tf_bucket_id" {
byte_length = 2
}
# Create the bucket
resource "aws_s3_bucket" "tf_code" {
bucket = format("%s-%d", var.project_name, random_id.tf_bucket_id.dec)
acl = "private"
force_destroy = true
tags = {
Name = "tf_bucket"
}
} - Work with Terraform
1
2
3
4
5
6
7
8
9# setup AWS access key
export AWS_ACCESS_KEY_ID="[ACCESS_KEY]"
export AWS_SECRET_ACCESS_KEY="[SECRET_KEY]]"
export AWS_DEFAULT_REGION="us-east-1"
terraform12 plan -var project_name=la-terraform
terraform12 apply -var project_name=la-terraform -auto-approve
# clean up
terraform12 destroy -var project_name=la-terraform -auto-approve
Output values
Refactor the previous storage module by adding outputs of the S3 bucket name and project_name variable.
- Edit
outputs.tf
1
2
3
4
5
6
7output "bucketname" {
value = aws_s3_bucket.tf_code.id
}
output "project_name" {
value = var.project_name
} - Work with Terraform
1
2
3
4
5terraform12 init
terraform12 apply -var project_name=la-terraform -auto-approve
# clean up
terraform destroy -var project_name=la-terraform -auto-approve
Expressions
Dynamic nested blocks ‘for-each’
- environment:
~/terraform/t12/loops
- Edit
main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38variable "vpc_cidr" {
default = "10.123.0.0/16"
}
variable "accessip" {
default = "0.0.0.0/0"
}
variable "service_ports" {
default = ["22", "22"]
}
resource "aws_vpc" "tf_vpc" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "tf_vpc"
}
}
resource "aws_security_group" "tf_public_sg" {
name = "tf_public_sg"
description = "Used for access to the public instances"
vpc_id = aws_vpc.tf_vpc.id
# this defines a for-each loop
dynamic "ingress" {
for_each = var.service_ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = [var.accessip]
}
}
} - Work with Terraform
1
2
3
4
5export AWS_ACCESS_KEY_ID="[ACCESS_KEY]"
export AWS_SECRET_ACCESS_KEY="[SECRET_KEY]"
export AWS_DEFAULT_REGION="us-east-1"
terraform12 init
terraform12 plan
Dynamic nested blocks ‘for’
- environment:
~/terraform/t12/dynamic
Edit `main.tf:``
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58variable "vpc_cidr" {
default = "10.123.0.0/16"
}
variable "accessip" {
default = "0.0.0.0/0"
}
variable "service_ports" {
default = [
{
from_port = "22",
to_port = "22"
},
{
from_port = "80",
to_port = "80"
}
]
}
resource "aws_vpc" "tf_vpc" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "tf_vpc"
}
}
resource "aws_security_group" "tf_public_sg" {
name = "tf_public_sg"
description = "Used for access to the public instances"
vpc_id = aws_vpc.tf_vpc.id
dynamic "ingress" {
for_each = [ for s in var.service_ports: {
from_port = s.from_port
to_port = s.to_port
}]
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = "tcp"
cidr_blocks = [var.accessip]
}
}
}
output "ingress_port_mapping" {
value = {
# for loop
for ingress in aws_security_group.tf_public_sg.ingress:
format("From %d", ingress.from_port) => format("To %d", ingress.to_port)
}
}Work in Terraform:
1
2
3
4
5
6
7
8
9export AWS_ACCESS_KEY_ID="[ACCESS_KEY]"
export AWS_SECRET_ACCESS_KEY="[SECRET_KEY]"
export AWS_DEFAULT_REGION="us-east-1"
terraform12 init
terraform12 plan
terraform12 apply -auto-approve
# clean up
terraform12 destroy -auto-approve*
Functions
- Terraform 0.12 and later have built-in functions, previous versions have Interpolation Syntax
- example using
cidrsubnet
function to calculate a subnet address within a given IP network address prefix - environment:
~/terraform/t12/functions
- Edit
main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38variable "vpc_cidr" {
default = "10.123.0.0/16"
}
variable "accessip" {
default = "0.0.0.0/0"
}
variable "subnet_numbers" {
default = [1, 2, 3]
}
resource "aws_vpc" "tf_vpc" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "tf_vpc"
}
}
resource "aws_security_group" "tf_public_sg" {
name = "tf_public_sg"
description = "Used for access to the public instances"
vpc_id = aws_vpc.tf_vpc.id
ingress {
from_port = "22"
to_port = "22"
protocol = "tcp"
vidr_blocks = [
for num in var.subnet_numbers:
# num = netnum -> value got from calculation from vpc_cidr dafault net: 16+8=24
cidrsubnet(aws_vpc.tf_vpc.cidr_block, 8, num)
]
}
} - Work with Terraform
1
2
3
4
5export AWS_ACCESS_KEY_ID="[ACCESS_KEY]"
export AWS_SECRET_ACCESS_KEY="[SECRET_KEY]"
export AWS_DEFAULT_REGION="us-east-1"
terraform12 init
terraform12 plan
Upgrade process example
- Refactor
variables.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21variable "vpc_cidr" {
default = "10.123.0.0/16"
}
variable "accessip" {
default = "0.0.0.0/0"
}
# add the service ports, to populate the block
variable "service_ports" {
default = [
{
from_port = "22",
to_port = "22"
},
{
from_port = "80",
to_port = "80"
}
]
} - Refactor
variables.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62resource "aws_vpc" "tf_vpc" {
## interpolation symbols are no loger needed
## cidr_block = "${var.vpc_cidr}"
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
## now we need and equals sign on tags
## tags {
tags = {
Name = "tf_vpc"
}
}
resource "aws_security_group" "tf_public_sg" {
name = "tf_public_sg"
description = "Used for access to the public instances"
## interpolation symbols are no loger needed
## vpc_id = "${aws_vpc.tf_vpc.id}"
vpc_id = aws_vpc.tf_vpc.id
## refator as loop, and remove interpolation symbols
## #SSH
## ingress {
## from_port = 22
## to_port = 22
## protocol = "tcp"
## cide_blocks = ["$var.accessip"]
## }
## #HTTP
## ingress {
## from_port = 80
## to_port = 80
## protocol = "tcp"
## cide_blocks = ["$var.accessip"]
## }
## set as dynamic block, with maps for each,
## whose values are stored in `variables.tf`
dynamic "ingress" {
for_each = [ for s in var.service_ports: {
from_port = s.from_port
to_port = s.to_port
}]
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = "tcp"
cidr_blocks = [var.accessip]
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
} - Refactor
output.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19output "public_sg" {
value = aws_security_group.tf_public_sg.id
}
## add mapping for ingress port
output "ingress_port_mapping" {
value = {
for ingress in aws_security_group.tf_public_sg.ingress:
format("From %d", ingress.from_port) => format("To %d", ingress.to_port)
}
}
```
4. Launch Terraform to test it
```bash
terraform init
terraform validate
terraform plan
terraform apply –auto-approve
# select a region and go