# Terraform
# What is Terraform
Allows to write infrastructure as code. Keeps infrastructure in a certain state (compliant)
- Tries to match it at all times
- Makes infratructure auditable
Ansible, Chef, Puppet, Saltstack focus on automating the installation and config of software. Terraform can automate provisioning the infrastructure itself.
Hardware (Terraform) -> Software (Ansible,etc)
# Terraform HCL (HashiCorp Config Language)
Interprets .tf
files
# Variables Basics
variable
is a keyword to create variables:
variable "myvar" {
type = "string"
default = "hello terraform"
}
//Map of strings
variable "mymap" {
type = map(string)
default = {
mykey = "my value"
}
}
variable "mylist" {
type = list
default = [1,2,3]
}
Enter the terraform console
terraform console
and then run the following examples
var.myvar
//outputs 'hello terraform'
var.mymap
//outputs '{"mykey" = "my value"}'
var.mymap["mykey"]
//outputs 'my value'
var.mylist
//outputs [1,2,3]
var.mylist[0]
//outputs 1
element(var.mylist,1)
//outputs 2
slice(var.mylist,0,1)
//outputs [1,2]
I can also create variables in files. E.g. file.tfvars
AWS_REGION="eu-west-1"
then, in the console I can do
var.AWS_REGION
//outputs eu-west-1
Terraform Simple Variable Types
- String
- Number
- Bool
Terraform Complex Types
- list(type)
- List:
[1,2,3]
- Is always ordered
- List:
- Set(Type)
- It's like a list but no order (given by user) is preserved, can only contain unique values
- Map(type)
{"key" = "value"}
- Tuple([])
- Like a list but each element can have a different type
- Object({})
- Like a map but each element can have a different type
# Resources
When creating a resource one needs to add a provider with the provider
keyword. The keyword resource
denotes a resource.
Syntax for a resource
resource <resource type> <name> {
<properties>
}
provider "aws"{
}
resource "aws_instance" "example"{
ami = var.AMIS[var.AWS_REGION]
instance_type = "t2.micro"
}
an alternate notation is:
resource "aws_instance" "example"{
ami = ${var.AMIS[var.AWS_REGION]}
instance_type = "t2.micro"
}
Macro Steps when Running Terraform
//Run this to download cloud-specific plugins or when in a new directory
terraform init
//This command actually executes the code
terraform apply
//Destroy created resources
terraform destroy
//Shows the plan
terraform plan
# Variables Deep Dive
Use variables for elements that might change or to make it easier to reuse terraform files.
Instead of having:
instance.tf
provider "aws" {
access_key = "ACCESS_KEY"
secret_key = "SECRET_KEY"
region = "us-east-1"
}
resource "aws_instance" "example" {
ami = "ami_id_here"
instance_type = "t2.micro"
}
better to split the files to:
provider.tf
provider "aws" {
access_key = "${var.ACCESS_KEY}"
secret_key = "${var.AWS_SECRET_KEY}"
region = "${var.AWS_REGION}"
}
vars.tf
Here we declare the variablaes
variable "ACCESS_KEY" {}
variable "AWS_SECRET_KEY" {}
variable "AWS_REGION" {
default = "eu-west-1"
}
variable "AMIS" {
type = "map"
default = {
us-east-1 = "ami-xxx1"
us-west-2 = "ami-xxx2"
eu-west-1 = "ami-xxx3"
}
}
terraform.tfvars
This one HAS to be included in .gitignore
ACCESS_KEY = ""
AWS_SECRET_KEY = ""
instance.tf
resource "aws_instance" "example" {
ami = "${lookup(var.AMIS,var.AWS_REGION)}"
instance_type = "t2.micro"
}
# Software Privision Basics
Ways to provision software:
- Buold own custom AMI and bundle Software
- Packer
- Boot Standard AMI, and then install software
- Using file uploads
- Using remote exec
- Use Chef (integrated with terraform), Puppet, Ansible
File Uploads
provisioner "file" {
source = "app.conf"
destination = "/etc/myapp.conf"
}
File uploads can be used in conjunction with remote-exec
We might have to override SSH defaults
provisioner "file" {
source = "app.conf"
destination = "/etc/myapp.conf"
connection {
user = "${var.instance_username}"
password = "${var.instance_password}"
}
}
To use SSH keypairs:
resource "aws_key_pair" "mykey" {
key_name = "mykey"
public_key = "ssh-rsa my-public-key"
}
resource "aws_instance" "example" {
ami = "${lookup(var.AMIS, var.AWS_REGION)}"
instance_type = "t2.micro"
key_name = "${aws_key_pair.mykey.key_name}"
}
provisioner "file" {
source = "app.conf"
destination = "/opt/script.sh"
connection {
user = "${var.instance_username}"
private_key = "${file(${var.path_to_private_key})}"
}
}
After uploading a script, we need to execute it
```terraform
provisioner "remote-exec" {
inline = [
"chmod +x /opt/script.sh",
"/opt/script.sh arguments"
]
}
# Output
Terraform keeps attributes of resources created. They can be queried using the keyword output
.
resource "aws_instance" "example" {
ami = ""
instance_type=""
}
output "ip" {
value = "${aws_instance.example.public_ip}"
}
Attributes can also be used in a script.