Provisioners Introduction

In this lesson we'll discuss Terraform provisioners in detail.

Terraform provisioner

A provisioner in Terraform can run a script either remotely or locally after a resource has been created. Hashicorp added provisioners to Terraform to allow for certain scenarios that are not natively supported by the provider you are using. I include them here for completeness. However, Hashicorp recommends that they are a last resort as they are imperative. Therefore, Terraform has no way of knowing how to apply a change you make to your script to the real world like it does with normal resources.

For example, say you have a provisioner script that installs some yum packages on a Linux server and then runs a command. If you want to update that provisioner script, you need to ensure that the newly updated script works for a machine that has never had the script run just as it does for one that has had the old version run. This headache could be avoided by using Terraform in the first place, which is one of the main reasons they are discouraged.

Project example

The example code for provisioners is quite a bit more in-depth than the examples we have been using so far. By this point, though, we are ready to take on a bit of a more ambitious Terraform project.

variables.tf file

To set up this project, we’ll create a new file called variables.tf and paste in the following code:

Press + to interact
variable "my_ip" {}

output.tf file

We’ll Create a file called output.tf and paste in:

Press + to interact
output "command" {
value = "curl http://${aws_instance.nginx.public_ip}"
}

main.tf file

Then we’ll create a file called main.tf and paste in the following code:



provider "aws" {
    region = "us-east-2"
}

resource "aws_vpc" "vpc" {
    cidr_block = "10.0.0.0/16"
}

resource "aws_internet_gateway" "main" {
    vpc_id = aws_vpc.vpc.id
}

resource "aws_subnet" "public" {
    vpc_id = aws_vpc.vpc.id
    cidr_block = aws_vpc.vpc.cidr_block
    map_public_ip_on_launch = true
    availability_zone = "us-east-1a"
}

resource "aws_route_table" "public" {
    vpc_id = aws_vpc.vpc.id

    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.main.id
    }
}

resource "aws_route_table_association" "gateway_route" {
    subnet_id = aws_subnet.public.id
    route_table_id = aws_route_table.public.id
}

resource "aws_security_group" "rules" {
    name = "example"
    vpc_id = aws_vpc.vpc.id

    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["${var.my_ip}/32"]
    }

    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }

    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

resource "aws_key_pair" "keypair" {
    key_name = "my_key"
    public_key = file("nginx_key.pub")
}

data "aws_ami" "ami" {
    most_recent = true
    owners = ["amazon"]

    filter {
        name = "name"
        values = ["amzn2-ami-hvm-2.0.*-x86_64-gp2"]
    }
}

resource "aws_instance" "nginx" {
    ami = data.aws_ami.ami.image_id
    instance_type = "t2.micro"
    subnet_id = aws_subnet.public.id
    vpc_security_group_ids = [aws_security_group.rules.id]
    key_name = aws_key_pair.keypair.key_name


    provisioner "remote-exec" {
        inline = [
            "sudo amazon-linux-extras enable nginx1.12",
            "sudo yum -y install nginx",
            "sudo chmod 777 /usr/share/nginx/html/index.html",
            "echo \"Hello from nginx on AWS\" > /usr/share/nginx/html/index.html",
            "sudo systemctl start nginx",
        ]
    }

    connection {
        host = aws_instance.nginx.public_ip
        type = "ssh"
        user = "ec2-user"
        private_key = file("nginx_key")
    }
}
main.tf file of our Terraform project example

📝Note: Please don’t forget to run terraform destroy to destroy the project after running all the desired commands.

Code explanation

Let’s start at the top.

my_ip variable

The variable my_ip should be set to your IP address. To find out your current IP address, visit https://www.whatismyip.com/ or curl ifconfig.co. You can then default your IP address as the value of the my_ip variable either by setting the default parameter or by ...