Provisioners Introduction
In this lesson we'll discuss Terraform provisioners in detail.
We'll cover the following...
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:
variable "my_ip" {}
output.tf
file
We’ll Create a file called output.tf
and paste in:
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") } }
📝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 ...