Télécharger du site de Terraform, décompresser et copier dans un répertoire du PATH:
$ sudo mv ./terraform /usr/local/bin
Sur macOS, peut être installé avec Brew:
$ brew install terraform
Initialiser terraform:
$ terraform init
Validation (non garantie):
$ terraform validate
Plan:
$ terraform plan $ terraform plan -out file.tfplan
Apply:
$ terraform apply "file.tfplan"
Destroy:
$ terraform destroy $ terraform destroy -auto-approve
Créer un fichier dans le home directory nommé .terraformrc :
credentials "app.terraform.io" {
  token = "xxxxxx.atlasv1.zzzzzzzzzzzzz"
}
Dans le répertoire de travail de Terraform, créer un fichier de configuration main.tf.
terraform {
  backend "remote" {
    hostname     = "app.terraform.io"
    organization = "company"
    workspaces {
      name = "workspace-name"
    }
  }
}
Faire l'initialisation par la suite.
$ terraform init
Sources : CLI Configuration File et Backend - Remote.
On peut spécifier le nom, le type et la valeur par défaut d'une variable.
# Spécifier la valeur par défaut et le type (les deux sont facultatifs)
variable "environment_name" {
  type = string
  default = "development"
}
# Spécifier la valeur de la variable
environment_name = "uat"
On peut déclarer des variables de plusieurs sources, celles-ci on une précédence:
Cela signifie qu'une variable qui est initialisée dans un fichier écrasera la valeur de cette variable initialisé depuis une variable d'environnement.
Spécifier une valeur in-line en ligne de commande:
$ terraform -plan -var 'environment_name=production'
Avec map:
variable "cidr" {
  type = map(string)
  default = {
    development = "10.0.0.0/16"
    uat = "10.1.0.0/16"
    production = "10.2.0.0/16"
  }
}
Utilisation:
cidr_block = lookup(var.cidr, var.environment_name)
Random provider:
resource "random_integer" "rand" {
  min = 10000
  max = 99999
}
depends_on: nommer explicitement une dépendance à une autre ressourcecount:for_each: provider: utilisation explicite d'un provider quand on en utilise plusieurs
Exemple de count et depends_on:
resource "aws_instance" "taco_servers" {
  count = 2
  tags {
    Name = "customer-${count.index}"  # Commence à 0
  }
  depends_on = [aws_iam_role_policy.allow_s3]
}
Exemple de for-each:
resource "aws_s3_bucket" "taco_toppings" {
  for_each {
    food = "public-read"
    cash = "private"
  }
  bucket = "${each.key}-${var.bucket_suffix}"
  acl = each.value
}
Simple:
provisioner "file" {
  source = "/local/path/to/file.txt"
  destination = "/path/to/file.txt"
}
Avec connection:
provisioner "file" {
  connection {
    type = "ssh"
    user = "root"
    private_key = "${var.private_key}"
    host = "${var.hostname}"
  }
  source = "/local/path/to/file.txt"
  destination = "/path/to/file.txt"
}
Avec content:
provisioner {
  content = <<EOF
access_key = 
secret_key =
security_token =
use_https = True
bucket_location = US
EOF
  destination = "/home/ec2-user/.s3cfg"
}
Inline:
provisioner "remote-exec" {
  inline = [
    "puppet apply",
    "consul join ${aws_instance.web.private_ip}",
  ]
}
Script:
provisioner "remote-exec" {
  scripts = [
    "./scripts/01_post-install.sh",
  ]
}
Utilise le HCL, qui est un langage de HashiCorp.
Types de données:
string = "taco"
number = 5
bool = true
list = ["Montréal", "New York"]
map = {name = "Ned", age = 42, loves_tacos = true}
Références:
var.taco_day aws_instance.taco_truck.name local.taco_toppings.cheeses module.taco_hut.locations
Référencer une chaîne, nombre et booléen:
local.taco_count # retourne le nombre
Référencer un élément d'une liste ou une map:
local.taco_toppings[2] # retourne l'élément 3 local.taco_map["likes_tacos"] # retourne la valeur à cette clé
Valeurs des ressources:
var.region # us-east-1 data.aws_availability_zones.azs.names[1] # retourne la deuxième zone de disponibilité
Interpolation:
taco_name = "neds-${var.taco_type}"
locals {
  common_tags = {
    BillingCode = var.billing_code_tag
    Environment = var.environment_tag
  }
  s3_bucket_name = "${var.bucket_name_prefix}-${var.environment_tag}-${random_integer.rand.result}"
}
Exemples de fonctions communes:
min(42, 8, 13)  # Numérique
lower("TACOS")  # Chaine
merge(map1, map2)  # Collection
file(path)         # Filesystem
cidrsubnet("10.1.2.0/24", 4, 15)  # IP Network
timestamp()  # Date and time    
# Configure networking
variable network_info {
  default = "10.1.0.0/16"
}
cidr_block = cidrsubnet(var.network_info, 8, 0)  # retourne 10.1.0.0/24
host_ip = cidrhost(var.network_info, 5) # retourne 10.1.0.5
On peut utiliser terraform console pour évaluer et tester les fonctions.
⇒ Référence: Functions
On peut gérer les environnements de différentes façons. On peut le faire avec les Workspaces, mais aussi en indiquant les fichiers à utiliser.
|-- /dev | |-- dev.state | |-- dev.tfvars |-- /uat | |-- uat.state | |-- uat.tfvars |-- /prod | |-- prod.state | |-- prod.tfvars |-- main_config.tf |-- common.tfvars
La commande à utiliser:
$ terraform plan -state=".\dev\dev.state" -var-file="common.tfvars" -var-file=".\dev\dev.tfvars"
$ terraform workspace new dev $ terraform plan
Composantes:
Example d'utilisation:
# Créer le module
module "bucket" {
  name = "taco-bucket"
  source = ".\\Modules\\s3"
}
# L'utiliser
ressource "aws_s3_bucket_object" {
  bucket = module.bucket.bucket_id
  [...]
}
provider "aws" {
  #Virginia, USA
  region = "us-east-1"
}
resource "aws_instance" "example" {
  #Ubuntu 14.04 AMI (Amazon Machine Image)
  ami = "ami-2d39803a"
  instance_type = "t2.micro"
  tags {
    #tags WILL CHANGE the state of previous runnings resources.
    Name = "My Instance Name"
  }
}