Introduction

In the previous article on Terraform, we have seen together what was IaC, how to install Terraform and run a simple test by deploying an EC2 instance. Today, we will discuss about variables, remote state, locking and modules !

Variables

In order to make your deployment dynamics, you can use variables in Terraform.

For example in a variables.tf file :

variable instancetype {
  type        = string
  description = "set aws instance type"
  default     = "t2.nano"
}


variable aws_common_tag {
  type        = map
  description = "Set aws tag"
  default = {
    Name = "ec2-lionel"
  }
}

Terraform also automatically loads a number of variable definitions files if they are present:

  • Files named exactly terraform.tfvars or terraform.tfvars.json.
  • Any files with names ending in .auto.tfvars or .auto.tfvars.json.

If you put the same variable in variables.tf and terraform.tfvars, Terraform will use the value in terraform.tfvars.

To use the variables in your terraform file, just proceed as described here :

resource "aws_instance" "myec2" {
  instance_type   = var.instancetype
  key_name        = "devops"
  tags            = var.aws_common_tag

  root_block_device {
    delete_on_termination = true
  }
}

Finally, if you want to get the key_name value from the “myec2” aws_instance ressource, just call the following anywhere you want in your terraform file :

aws_instance.myec2.key_name

Remote State and Locking

Remote State

By default, Terraform writes its state file to your local filesystem (the terraform.state file.) This works well for personal projects, but once you start working with a team, things start to get more challenging. In a team, you need to make sure everyone has an up to date version of the state file and ensure that two people aren’t making concurrent changes.

Remote state solves those challenges. Remote state is simply storing that state file remotely, rather than on your local filesystem. With a single state file stored remotely, teams can ensure they always have the most up to date state file. With remote state, Terraform can also lock the state file while changes are being made. This ensures all changes are captured, even if concurrent changes are being attempted.

Here is an example of a “backend” resource you can add to our previous code (under provider), in order to save state on a remote S3 bucket :

terraform {
	  backend "s3" {
	    bucket = "terraform-backend-dirane"
	    key    = "dirane.tfstate"
	    region = "us-east-1"
	    access_key = "YOUR AWS ACCESS KEY"
        secret_key = "YOUR AWS SECRET KEY"
	  }
	}

Locking

Moreover, if supported by your backend, Terraform will lock your state for all operations that could write state. This prevents others from acquiring the lock and potentially corrupting your state. State locking happens automatically on all operations that could write state. Be aware, that not all backends support locking.

You can use an AWS DynamoDB for this. First, create a dynamoDB table :

resource "aws_dynamodb_table" "terraform_state_lock" {
  name           = "terraform-lock"
  read_capacity  = 5
  write_capacity = 5
  hash_key       = "LockID"

attribute {
    name = "LockID"
    type = "S"
  }
}

Then, update, the “terraform” block discussed previously :

terraform {
	  backend "s3" {
	    bucket = "terraform-backend-dirane"
	    key    = "dirane.tfstate"
	    region = "us-east-1"
	    access_key = "YOUR AWS ACCESS KEY"
        secret_key = "YOUR AWS SECRET KEY"
        dynamodb_table = "terraform-lock"
	  }

	}

Run a terraform init, to make sure our backend is initialised properly for usage by terraform.

Modules

If you know Ansible (see my articles), it’s a notion very similar on Terraform. You can create your own modules on use existing ones on the following registry.

Your directory structure should look like that :

As you can see, modules are separated from your dev files you will apply.

Here is an example of how to call an AWS module :

provider "aws" {
  region = "us-west-1"
}

module "child" {
  source = "./child"
}

Finally, to access module output values, proceed just like that :

resource "aws_elb" "example" {
  # ...

  instances = module.servers.instance_ids
}

Sources

terraform.io

medium.com

Leave a Comment

Your email address will not be published. Required fields are marked *