SlideShare a Scribd company logo
1 of 82
Terraform
Modules
Restructured
āœ“ Reusable
āœ“ Composable
āœ“ Automated Tests
āœ“ Confidence to Make Changes
āœ“ Implementation Abstraction
These slides are heavily influenced by the slides and talks from
Yevgeniy Brikman from terragrunt.io
It goes hand in hand with the following talk:
https://blog.gruntwork.io/5-lessons-learned-from-writing-over-300-000-lines-of-infrastructure-code-36ba7fadeac1
Credits
Ami Mahloof
Senior Cloud Architect at DoIT International.
LinkedIn Profile
Medium blog posts
Who Am I?
At DoiT International, we tackle complex problems of scale which are
sometimes unique to internet-scale customers while using our expertise
in resolving problems, coding, algorithms, complexity analysis, and large-
scale system design.
1. Introduction to Terraform
2. Module Anatomy
3. Modules Structure
4. Testing
5. Terraform Modules Best Practices
6. Migrating Existing Infrastructure Into New Code Structure
Outline
An Introduction To Terraform
āŒ¾ Terraform can manage existing and new infrastructure
āŒ¾ Talk to multiple cloud/infrastructure providers
āŒ¾ Ensure creation and consistency
āŒ¾ Single DSL (Domain Specific Language) to express API agnostic calls
āŒ¾ Preview changes, destroy when needed
āŒ¾ Single source of truth infrastructure state
āŒ¾ Even order a pizza from Dominoā€™s
Terraform is a tool for building, changing, and versioning infrastructure
safely and efficiently
AnIntroductiontoTerraform
Just like in code a function has inputs (arguments) and outputs
(attributes)
The following sudo code creates an EC2 instance from the given args
function create_ec2(name, type) {
ec2 = aws.create_instance(name, type)
print ec2.instance_ip
}
HashiCorp Configuration Language (HCL) Syntax
AnIntroductiontoTerraform
Mapping A Code To HCL Syntax
function create_ec2(name, type) {
ec2 = aws.create_instance(name, type)
print ec2.instance_ip
}
Inputs (arguments)
outputs (attributes)
AnIntroductiontoTerraform
Mapping A Code To HCL Syntax
function create_ec2(name, type) {
ec2 = aws.create_instance(name, type)
print ec2.instance_ip
}
create_ec2("test", "t2.micro")
resource "aws_ec2_instance" "create_ec2" {
name = "test"
type = "t2.micro"
}
output "instance_ip" {
value = aws_ec2_instance.create_ec2.ipv4_address
}
name label
AnIntroductiontoTerraform
Mapping A Code To HCL Syntax
function create_ec2(name, type) {
ec2 = aws.create_instance(name, type)
print ec2.instance_ip
}
create_ec2("test", "t2.micro")
resource "aws_ec2_instance" "create_ec2" {
name = "test"
type = "t2.micro"
}
output "instance_ip" {
value = aws_ec2_instance.create_ec2.ipv4_address
}
provider resource API
AnIntroductiontoTerraform
Mapping A Code To HCL Syntax
function create_ec2(name, type) {
ec2 = aws.create_instance(name, type)
print ec2.instance_ip
}
create_ec2("test", "t2.micro")
resource "aws_ec2_instance" "create_ec2" {
name = "test"
type = "t2.micro"
}
output "instance_ip" {
value = aws_ec2_instance.create_ec2.ipv4_address
}
resource arguments
AnIntroductiontoTerraform
Mapping A Code To HCL Syntax
function create_ec2(name, type) {
ec2 = aws.create_instance(name, type)
print ec2.instance_ip
}
create_ec2("test", "t2.micro")
resource "aws_ec2_instance" "create_ec2" {
name = "test"
type = "t2.micro"
}
output "instance_ip" {
value = aws_ec2_instance.create_ec2.ipv4_address
}
output values
AnIntroductiontoTerraform
Mapping A Code To HCL Syntax
resource blocks are for create API calls:
resource "aws_ec2_instance" "create_ec2" {...
data blocks are for get API calls:
data "aws_ec2_instance" "instance_data" {
name = "test"
}
output "az" {
value = data.aws_ec2_instance.instance_data.availbility_zone
}
āŒ¾ JSON representation of known
infrastrurcture state provisioned by
terraform
āŒ¾ Stored in file or externally
āŒ¾ Locking (useful for team working on
the same project or tasks)
āŒ¾ Source of truth for infrastructure
AnIntroductiontoTerraform
Terraform State File
{
"version": 4,
"terraform_version": "0.12.6",
"serial": 18,
"lineage": "b3bfb3fc-8417-cc89-d87f-6ab0008e2056",
"outputs": {
"group-id": {
"value": "6521262259226325019",
"type": "string"
}
},
"resources": [
{
"mode": "data",
"type": "template_file",
"name": "filter_pattern",
"provider": "provider.template",
"instances": ...
terraform.tfstate
Monolithic Terraform
āŒ¾ One/several huge files - fear of making changes, no reusability, a mistake
anywhere can break everything
āŒ¾ Hard to find/debug - variables and sections are harder to find when one needs
to make a change
āŒ¾ Guess work - going back and forth between variables and resources just to
understand what is required and what is the default
āŒ¾ Slower development cycles - increased time and effort needed to start
working with it
Issues with monolithic Terraform:
10,000 ft View Approach
10,000 ft View Approach
Since Terraform will combine all the files into a plan, we can use that to
create smaller files with better visibility using the following simple module
anatomy.
Being able to quickly find what youā€™re looking for during development and
debugging an issue is crucial when working with Terraform.
Module Anatomy
The module anatomy is a scaffold that provides better visibility and guidelines
for developing, and working with Terraform modules.
Since Terraform compiles all resources in all files into an execution plan, we can
use that to create better visibility and readability.
There are no hard-coded values, as each hard-coded value becomes a default
variable, and every attribute is a variable.
Development of a module is done through the examples folder which holds a
main.tf file with:
āŒ¾ Hard-coded values for all variables
āŒ¾ Lock down a specific version for a Terraform provider
āŒ¾ State location
āŒ¾ Terraform version
This will serve as a usage example when you finish development on the module
ModuleAnatomy
terraform {
backend "s3" {
region = "eu-west-3"
bucket = "some-s3-bucket"
key = "dev/eu-west-3/infrastructure"
}
required_version = ">=12.6"
}
# This is where you setup the provider to use with the module
provider "aws" {
version = "~> 2.0"
region = "us-east-1"
}
module "route53_record_name_cname_exmaple" {
source = "../"
domain_name = "tf.domain.com"
value = "1.2.3.4"
}
ModuleAnatomy examples/main.tf
āŒ¾ examples - a folder containing examples for usage
āŒ¾ test - Go Terratest folder
āŒ¾ data.tf - Terraform data sources
āŒ¾ main.tf - resources to be created
if itā€™s over 30 lines long, break it into files with names
applied for resources i.e., autoscaling.tf, ec2.tf, etc.
āŒ¾ outputs.tf - outputs for the module
āŒ¾ README.md - clear inputs/outputs and description for the
module as well as usage
āŒ¾ default-variables - variables with default values
āŒ¾ required-variables - variables with values that are required
ModuleAnatomy
Module Anatomy - Quick scaffolding with bash:
āžœ export module_name="sample"
āžœ mkdir -p $module_name/examples $module_name/test
āžœ cd $module_name && touch 
main.tf 
versions.tf 
default-variables.tf 
required-variables.tf 
outputs.tf 
data.tf
ModuleAnatomy
3-Tier Modules Structure
3-TierModulesStructure
Create and extend your own library of primitives building blocks (resources)
The 3-Tier Module-Based Hierarchy Structure
3-TierModulesStructure
Build services from these primitives building blocks
The 3-Tier Module-Based Hierarchy Structure
3-TierModulesStructure
Deploy end-to-end environments from services (live deployments)
The 3-Tier Module-Based Hierarchy Structure
3-TierModulesStructure
What are the 3-Tier modules structure major benefits:
āŒ¾ Hide all lower level details to allow the end user to focus
on building the infrastructure
āŒ¾ Each tier is tested providing a quicker
development/debugging cycle
āŒ¾ Provides the confidence needed to make changes
The 3-Tier Module-Based Hierarchy Structure
3-TierModulesStructure
The goal is to isolate each (live) environment (dev, staging, production),
then take each component in that environment and break it up into a
generic service module, and for each generic service module break it
into resource modules.
Restructuring Existing Infrastructure
3-TierModulesStructure
Break your architecture code down by live environment
terraform-live-envs
L dev
L vpc
L mysql
L kubernetes
L staging
L vpc
L mysql
L kubernetes
L production
L vpc
L mysql
L kubernetes
3-TierModulesStructure
Then by service (infrastructure type)
terraform-live-envs
L dev
L vpc
L mysql
L kubernetes
L staging
L vpc
L mysql
L kubernetes
L production
L vpc
L mysql
L kubernetes
terraform-services (generic modules)
L gke
L vpc
L sql
Implement infrastructure in modules
3-TierModulesStructure
Build complex modules from smaller, simpler modules
terraform-live-envs
L dev
L vpc
L mysql
L kubernetes
L staging
L vpc
L mysql
L kubernetes
L production
L vpc
L mysql
L kubernetes
terraform-services
L gke
L vpc
L sql
terraform-resources
L vpc
L sql
L instance
L user
Tier-1 Terraform Resources Modules
This is the lowest tier
terraform-resources is a folder containing modules with a single resource to be
created
These resource modules are creating only one thing
These modules should have an output.tf file with outputs values providing
information on the resource created
This information can be used to create hard dependencies between modules
(required by the 2nd tier)
3-TierModulesStructure
Tier-2 Terraform Services Modules
This is the middle tier
terraform-services is a folder containing modules combining resources modules
together from the terraform-resources folder
Each service module is a generic service that can create multiple versions based on
the variables passed in
Example; an SQL instance module can create postgreSQL or mySQL instance
3-TierModulesStructure
Tier-3 Terraform-live-envs Modules
This is the top tier
The terraform-live-envs is a folder containing modules implementing the
infrastructure that is deployed
These modules are usually built from the services modules but can also have
resources modules mixed in
Every module attribute is a hard-coded value representing the value that is deployed
3-TierModulesStructure
Tier-3 terraform-live-envs Modules
Each module should have one single file called main.tf that will contain:
āŒ¾ Terraform state block
āŒ¾ Modules with hard-coded values
āŒ¾ Locals block (shared variables between modules in this file)
āŒ¾ Outputs
This makes for a readable easy-to-use and maintainable deployment file
3-TierModulesStructure
Terraform Remote State
By default, Terraform stores state locally in a file named terraform.tfstate
This does not scale because thereā€™s no locking or central location to work with
Terraform in a team.
With remote state, Terraform writes the state data to a remote data store, which
can then be shared between all members of a team. Terraform supports storing
state in Terraform Cloud, HashiCorp Consul, Amazon S3, Alibaba Cloud OSS, and
more.
Base Remote State
Often you need to create a base infrastructure for other deployments to use/read
Example:
You might create a VPC in one region only once, but you can deploy multiple
services on that VPC.
To do that, break your deployment into 2-steps:
āŒ¾ step-1-infrastructure
Creates and outputs the VPC information (vpc_id, subnets etc..)
āŒ¾ step-2-some-service
Accepts the remote state location (defined in step-1) as an input that will be
used to read the output information for step-1, and creates the service on that
VPC
BaseRemoteState
BaseRemoteState
terraform {
backend "s3" {
region = "eu-west-3"
bucket = "my-terraform-bucket"
key = "dev/eu-west-3/infrastructure"
}
}
module "vpc" {
vpc_name = "vpc-dev"
vpc_availability_zones = ["eu-west-3a", "eu-west-3b"]
vpc_private_subnets = ["10.10.1.0/24", "10.10.2.0/24"]
vpc_public_subnets = ["10.10.11.0/24", "10.10.12.0/24"]
}
output "infra" {
value = module.vpc
}
Step 1 - Infrastructure
BaseRemoteState
terraform {
backend "s3" {
region = "eu-west-3"
bucket = "my-terraform-bucket"
# separate the state file location from the infrastructure state location
key = "dev/eu-west-3/deployment/code-pipeline/nodejs-app"
}
}
module "code_pipeline" {
source = "../codebuild-pipeline"
# these are taken from step-1 terraform backend block
terraform_state_store_region = "eu-west-3"
terraform_state_store_bucket = "my-terraform-bucket"
infrastructure_terraform_state_store_key = "dev/eu-west-3/infrastructure"
}
...
Step 2 - Services on Infrastructure
BaseRemoteState
deployment/step2-codepipeline/main.tf
module "code_pipeline" {
source = "../codebuild-pipeline"
...
}
Codebuild-pipeline module
# Read the information from the remote state file of step 1 infrastructure
data "terraform_remote_state" "infra" {
backend = "s3"
config = {
region = var.terraform_state_store_region
bucket = var.terraform_state_store_bucket
key = var.infrastructure_terraform_state_store_key
}
}
# Assign data to locals to read the data only once
locals {
vpc_id = data.terraform_remote_state.infra.outputs.infra.vpc.vpc_id
subnets = data.terraform_remote_state.infra.outputs.infra.vpc.subnets
}
# Use locals in the modules to get to the infrastructure data
module "pipeline" {
source = "../../modules/pipeline"
vpc_id = local.vpc_id
...
}
Refactoring existing terraform code
āŒ¾ Create a new bucket for the new terraform state to be stored at.
āŒ¾ Rewrite your new code into the 3-tiers modules (as illustrated above and
detailed in the slides).
āŒ¾ Import each of the resources into your live-envs terraform code.
āŒ¾ terraform will show you the execution plan for the import operation:
ā—‹ values that exist in the deployed version but not in your code
will be marked with a (-) minus sign for removal.
ā—‹ values that do not exist in the deployed version but do exists in your code
will be marked with a (+) plus sign for addition.
The goal is to get a no change plan.
Code Versioning
Modules Git Repo
Create a separate git repository for each of the tiers, and an additional to hold the
shared Go code for testing the modules:
āŒ¾ terraform-resources
āŒ¾ terraform-services
āŒ¾ terraform-live-envs
āŒ¾ terratest-common
Codeversioning
Managing Module Versions
For the development process, it is recommended to use a relative path when
working with the source attribute of a module
source = "../gcp/sql_instance"
You should change the source attribute value to a git repo when the module is ready
for release
When a module is released, it should be tagged and added to the source attribute
value using the ref argument
source = "git@github.com:unicorn/terraform-resources//gcp/sql_instance?ref=...v1.0.0"
Codeversioning
Modules in Subdirectories
Since we are using modules in a repo, the module itself is in a subdirectory relative
to the root of the repo.
A special double-forward-slash syntax is interpreted by Terraform to indicate that
the remaining path after that point is a subdirectory.
source = "git@github.com:unicorn/terraform-resources//gcp/sql_instance?ref=v1.0.0"
The ref argument can be either a tag or a branch name
Codeversioning
Modules Tagging Convention
Here is a recommended tagging convention for a module in the same repo:
<module-name>-v<semantic_versioning>
The module name should follow the directory structure you have in place.
Example:
Feel free to come up with your own tagging convention.
Codeversioning
gcp-sql-instance-v1.0.0
Terraform Modules Best Practices
Lock Down Terraform Version
Lock down the Terraform version that was used to create the module.
Place the following content in a file called versions.tf in the module:
terraform {
required_version = ">= 0.12"
}
TerraformModulesBestPractices
Using Provider in Module
TerraformModulesBestPractices
provider "aws" {
region = var.region
version = "~> 2.24"
}
module "this_module" {
source "../"
name = "unicorn"
}
Terraform provider is inherited in modules.
This means that a provider will be inherited by the
modules your main module is calling.
Use an inline provider block inside your examples folder.
Only use the examples folder to test/develop your
module.
Prefer Hard Dependencies Over depends_on
āŒ¾ depends_on doesnā€™t work with modules (currently on 0.12.6)
āŒ¾ depends_on doesnā€™t work with data sources
āŒ¾ There are some cases where depends_on would fail if the resource is it
depends_on is conditionally created
āŒ¾ Itā€™s better to be consistent across all the code that needs dependencies
TerraformModulesBestPractices
Instead of using depends_on (i.e., resources), create a hard dependency in
Terraform between resources:
TerraformModulesBestPractices
Prefer Hard Dependencies Over depends_on
Or between modules:
TerraformModulesBestPractices
Prefer Hard Dependencies Over depends_on
No Hard-coded Values
Each module should have the following files:
āŒ¾required-variables.tf
āŒ¾default-variables.tf
All of the resource attributes should be variables. If an existing module is
hard-coded, you should move it into the default-variables.tf file.
You donā€™t have to use all attributes as documented in Terraform docs,
you can add them as you go.
TerraformModulesBestPractices
No tfvar Files
tfvar files are key=value lines of variables passed into a module.
The main problem with using this feature is that you canā€™t tell which variable
belongs to which module.
This makes code usability hard to maintain and understand quickly.
TerraformModulesBestPractices
Plugins Cache
Instead of having to download the same provider plugin to each module over and
over again, you should set your plugin cache folder via an environment variable
like so:
export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"
This will ensure that the provider plugin is linked to this folder and speed up
running Terraform init on new modules.
TerraformModulesBestPractices
Terraform State Management
āŒ¾ Create a storage bucket (S3/GCS) per environment
Do not use the same bucket for multiple envs
āŒ¾ Enable versioning on the bucket - this will serve as a backup if state is
corrupted or can be used to compare concurrent executions
āŒ¾ Use prefix with the same folder structure you set in terraform-live-envs folder
āŒ¾ Use a separate prefix for infrastructure
i.e., vpc-network should be put into infrastructure/us-west2/blog-network
TerraformModulesBestPractices
Terraform Null Attribute
Use a null value for an attribute you want to
remove from the resource.
Example; aws_s3_bucket can either be a
standalone bucket or a website.
If you need to make a single resource for
that, you would then make a default variable
with the value null, which effectively
removes the attribute from the resource
before creating that resource.
TerraformModulesBestPractices
Terraform and Lists
Terraform will create a membership
resource per user, but behind the
scene, the count is also saved as an
index in the state file.
If you remove someone from the
middle of the list, the rest of the index
will shift up, causing the rest to be
added/recreated
In github this means delete user with
its forks!
TerraformModulesBestPractices
Cascade Variables and Outputs
Always cascade (copy over) the default and required variables along with the
outputs to the next module tier, so the variable applied goes through all the
modules.
TerraformModulesBestPractices
Terraform Testing Using Terratest
Terratest is a Go library by terragrunt.io
It automates the creation of the IaC (Infrastructure as code), and then tests that
the actual result is what you are expecting to get.
Once the tests are completed, Terratest will tear down and cleanup the resources
it has created using Terraform destroy command.
Tips:
āŒ¾ You can use Terreatest with Docker, Packer and even helm charts!
āŒ¾ Use vscode with its Go extension for a quick coding with Go
āŒ¾ Learn Go interactively https://tour.golang.org
Typical Test Structure
// TestVPCCreatedWithDefaults - test VPC is created without overriding any of the default variables
func TestVPCCreatedWithDefaults(t *testing.T) {
terraformOptions := &terraform.Options{
// The path to where our Terraform code is located
TerraformDir: "../step1-infrastructure",
// Variables to pass to our Terraform code using -var options
Vars: map[string]interface{}{
"region": "us-east-1",
},
}
}
TerraformTestingwithTerratest
terraformOptions is a Golang struct defining the location of the code, as well as
terraform variables for the execution.
Typical Test Structure
func TestVPCCreatedWithDefaults(t *testing.T) {
terraformOptions := &terraform.Options{
...
}
// At the end of the test, run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t, terraformOptions)
...
}
TerraformTestingwithTerratest
defer will run at the end of the test and call terraform destroy to clean up the
resources created by this test.
Typical Test Structure
func TestVPCCreatedWithDefaults(t *testing.T) {
terraformOptions := &terraform.Options{
...
}
// At the end of the test, run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t, terraformOptions)
// Run `terraform init` and `terraform apply` and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)
...
}
TerraformTestingwithTerratest
Run terraform init followed by terraform apply
Typical Test Structure
func TestVPCCreatedWithDefaults(t *testing.T) {
terraformOptions := &terraform.Options{
...
}
ā€¦
vpc_id := terraform.Output(t, terraformOptions, "vpc_id"),
validateVPC(t, vpcID)
}
func ValidateVPC(t *testing.T, vpcID string) {...}
TerraformTestingwithTerratest
Validate it works as expected
Terratestbuilt-infunctions
Terratest has many built-in functions to check your infrastructure - but itā€™s relatively easy to
extend and write your own.
Terratest
Terratest Built-in Functions
Terratest
Validate Function Example
Run Go test.
You now have a unit test you can run after every commit!
Note:
Go tests timeout after 10 minutes, so make sure you set a
greater timeout to allow infrastructure to be created
Running the Test
Terratest
Reproducible Test Results:
Running tests does not take remote state configuration, thus the local module will
end up having a local state file, which can lead to a stale test results.
Donā€™t put the hard-coded path to the module in the test like so:
terraformOptions := &terraform.Options{
// The path to where our Terraform code is located
TerraformDir: "../step1-infrastructure",
ā€¦
Use a built-in function in Terratest that will copy the module to a temporary folder
and return the path to that folder:
Terratest Testing Techniques
Terratest
import (
test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
)
func TestRoute53CNAMERecord(t *testing.T) {
rootFolder := "../../.."
modulePathRelativeToRootFolder := "terraform-aws-route53-resource/record-set"
terraformTempDir := test_structure.CopyTerraformFolderToTemp(
t,
rootFolder,
modulePathRelativeToRootFolder,
)
terraformOptions := &terraform.Options{
TerraformDir: tempTestFolder,
ā€¦
}
Terratest Testing Techniques
Terratest
In Go, a test will only report PASS or FAILED on the function name:
Multiple Tests Within a Test (subtests)
Terratest
Often you will need a few tests to check for the same function and reflect that in the
test outputs. This concept is called subtests.
Use the following to run multiple validations for the same test:
Multiple Tests Within a Test (subtests)
Terratest
Just about every method foo in Terratest comes in two versions: foo and fooE
(e.g., terraform.Apply and terraform.ApplyE).
āŒ¾ foo: The base method takes a t *testing.T as an argument. If the method
hits any errors, it calls t.Fatal to fail the test.
āŒ¾ fooE: Methods that end with the capital letter E always return an error as the
last argument and never call t.Fatal themselves. This allows you to decide
how to handle errors.
Terratest Error Handling
Terratest
You will use the base method name most of the time, as it allows you to keep your
code more concise by avoiding if err != nil checks all over the place:
terraform.Init(t, terraformOptions)
terraform.Apply(t, terraformOptions)
url := terraform.Output(t, terraformOptions, "url")
In the code above, if Init, Apply, or Output hits an error, the method will call t.Fatal
and fail the test immediately, which is typically the behavior you want. However, if
you are expecting an error and don't want it to cause a test failure, use the method
name that ends with a capital E:
if _, err := terraform.InitE(t, terraformOptions); err != nil {
// Do something with err
}
Terratest Error Handling
Terratest
The Test Pyramid
As you go up the pyramid, tests get more expensive, brittle and slower
The Test Pyramid
How the test pyramid works with infrastructure code:
The Test Pyramid
Lots of unit tests:
test individual sub-modules (keep them small!)
and static analysis (TFLint, Terraform validate)
Individual modules {
The Test Pyramid
Fewer integration tests:
test multiple sub-modules together
Individual modules
Multiple modules {
The Test Pyramid
A handful of high value E2E tests:
test entire environments (stage, prod)
Individual modules
multiple modules
Entire stack {
The Test Pyramid
Note the test times!
This is another reason to use small modules
60-240 minutes
(terraform-live-envs modules)
5-60 minutes
(terraform-services modules)
1-20 minutes
(terraform-resources modules)
1-60 seconds
(tflint/terraform validate)
To minimize the downsides of testing infrastructure as a code on a real platform,
follow the guidelines below:
1. Unit tests, integration tests, end-to-end tests
2. Testing environment
3. Namespacing
4. Cleanup
5. Timeouts and logging
6. Debugging interleaved test output
7. Avoid test caching
8. Error handling
9. Iterating locally using Docker
10. Iterating locally using test stages
Terratest Best Practices
Terratest
ā— Use VSCode for Terraform and Go integration
(you can opt to use JetBrains intelliJ too too or Vim)
ā— VSCode extensions:
Once installed you need to open the command palette (View -> Command
Palette) and type: ā€œTerraform: Enable Language Serverā€ which will prompt you
for installing the latest package for the terraform 0.12 support.
Pro Tips
Terratest
Questions?

More Related Content

What's hot

Terraform Introduction
Terraform IntroductionTerraform Introduction
Terraform Introductionsoniasnowfrog
Ā 
Terraform modules and best-practices - September 2018
Terraform modules and best-practices - September 2018Terraform modules and best-practices - September 2018
Terraform modules and best-practices - September 2018Anton Babenko
Ā 
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...Yevgeniy Brikman
Ā 
Infrastructure-as-Code (IaC) using Terraform
Infrastructure-as-Code (IaC) using TerraformInfrastructure-as-Code (IaC) using Terraform
Infrastructure-as-Code (IaC) using TerraformAdin Ermie
Ā 
Developing Terraform Modules at Scale - HashiTalks 2021
Developing Terraform Modules at Scale - HashiTalks 2021Developing Terraform Modules at Scale - HashiTalks 2021
Developing Terraform Modules at Scale - HashiTalks 2021TomStraub5
Ā 
Terraform on Azure
Terraform on AzureTerraform on Azure
Terraform on AzureMithun Shanbhag
Ā 
Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...
Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...
Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...Amazon Web Services
Ā 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform TrainingYevgeniy Brikman
Ā 
Terraform -- Infrastructure as Code
Terraform -- Infrastructure as CodeTerraform -- Infrastructure as Code
Terraform -- Infrastructure as CodeMartin SchĆ¼tte
Ā 
Terraform: Infrastructure as Code
Terraform: Infrastructure as CodeTerraform: Infrastructure as Code
Terraform: Infrastructure as CodePradeep Bhadani
Ā 
An introduction to terraform
An introduction to terraformAn introduction to terraform
An introduction to terraformJulien Pivotto
Ā 
A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...
A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...
A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...Alex Cachia
Ā 
Getting Started with Infrastructure as Code
Getting Started with Infrastructure as CodeGetting Started with Infrastructure as Code
Getting Started with Infrastructure as CodeWinWire Technologies Inc
Ā 

What's hot (20)

Terraform Introduction
Terraform IntroductionTerraform Introduction
Terraform Introduction
Ā 
Terraform modules and best-practices - September 2018
Terraform modules and best-practices - September 2018Terraform modules and best-practices - September 2018
Terraform modules and best-practices - September 2018
Ā 
Advanced Terraform
Advanced TerraformAdvanced Terraform
Advanced Terraform
Ā 
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
Ā 
Infrastructure-as-Code (IaC) using Terraform
Infrastructure-as-Code (IaC) using TerraformInfrastructure-as-Code (IaC) using Terraform
Infrastructure-as-Code (IaC) using Terraform
Ā 
Developing Terraform Modules at Scale - HashiTalks 2021
Developing Terraform Modules at Scale - HashiTalks 2021Developing Terraform Modules at Scale - HashiTalks 2021
Developing Terraform Modules at Scale - HashiTalks 2021
Ā 
Terraform on Azure
Terraform on AzureTerraform on Azure
Terraform on Azure
Ā 
Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...
Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...
Using HashiCorpā€™s Terraform to build your infrastructure on AWS - Pop-up Loft...
Ā 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform Training
Ā 
Terraform -- Infrastructure as Code
Terraform -- Infrastructure as CodeTerraform -- Infrastructure as Code
Terraform -- Infrastructure as Code
Ā 
Terraform
TerraformTerraform
Terraform
Ā 
Terraform
TerraformTerraform
Terraform
Ā 
Terraform on Azure
Terraform on AzureTerraform on Azure
Terraform on Azure
Ā 
Terraform
TerraformTerraform
Terraform
Ā 
Terraform
TerraformTerraform
Terraform
Ā 
Terraform: Infrastructure as Code
Terraform: Infrastructure as CodeTerraform: Infrastructure as Code
Terraform: Infrastructure as Code
Ā 
An introduction to terraform
An introduction to terraformAn introduction to terraform
An introduction to terraform
Ā 
Terraform Basics
Terraform BasicsTerraform Basics
Terraform Basics
Ā 
A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...
A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...
A brief introduction to IaC with Terraform by Kenton Robbins (codeHarbour May...
Ā 
Getting Started with Infrastructure as Code
Getting Started with Infrastructure as CodeGetting Started with Infrastructure as Code
Getting Started with Infrastructure as Code
Ā 

Similar to Terraform modules restructured

PuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into OperationsPuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into Operationsgrim_radical
Ā 
Terraform training šŸŽ’ - Basic
Terraform training šŸŽ’ - BasicTerraform training šŸŽ’ - Basic
Terraform training šŸŽ’ - BasicStephaneBoghossian1
Ā 
Terraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentTerraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentZane Williamson
Ā 
Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423
Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423
Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423Giulio Vian
Ā 
Terraform Abstractions for Safety and Power
Terraform Abstractions for Safety and PowerTerraform Abstractions for Safety and Power
Terraform Abstractions for Safety and PowerCalvin French-Owen
Ā 
Terraform training - Modules šŸŽ’
Terraform training - Modules šŸŽ’Terraform training - Modules šŸŽ’
Terraform training - Modules šŸŽ’StephaneBoghossian1
Ā 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native CompilationPGConf APAC
Ā 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Rajeev Rastogi (KRR)
Ā 
Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...
Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...
Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...Chris Fregly
Ā 
OroCRM Partner Technical Training: September 2015
OroCRM Partner Technical Training: September 2015OroCRM Partner Technical Training: September 2015
OroCRM Partner Technical Training: September 2015Oro Inc.
Ā 
Patterns in Python
Patterns in PythonPatterns in Python
Patterns in Pythondn
Ā 
Linux Assignment 3
Linux Assignment 3Linux Assignment 3
Linux Assignment 3Diane Allen
Ā 
Building and deploying LLM applications with Apache Airflow
Building and deploying LLM applications with Apache AirflowBuilding and deploying LLM applications with Apache Airflow
Building and deploying LLM applications with Apache AirflowKaxil Naik
Ā 
20100730 phpstudy
20100730 phpstudy20100730 phpstudy
20100730 phpstudyYusuke Ando
Ā 
Web Template Mechanisms in SOC Verification - DVCon.pdf
Web Template Mechanisms in SOC Verification - DVCon.pdfWeb Template Mechanisms in SOC Verification - DVCon.pdf
Web Template Mechanisms in SOC Verification - DVCon.pdfSamHoney6
Ā 
Productionizing Machine Learning - Bigdata meetup 5-06-2019
Productionizing Machine Learning - Bigdata meetup 5-06-2019Productionizing Machine Learning - Bigdata meetup 5-06-2019
Productionizing Machine Learning - Bigdata meetup 5-06-2019Iulian Pintoiu
Ā 
Hadoop cluster performance profiler
Hadoop cluster performance profilerHadoop cluster performance profiler
Hadoop cluster performance profilerIhor Bobak
Ā 
Apachecon 2002 Struts
Apachecon 2002 StrutsApachecon 2002 Struts
Apachecon 2002 Strutsyesprakash
Ā 
How to use source control with apex?
How to use source control with apex?How to use source control with apex?
How to use source control with apex?Oliver Lemm
Ā 

Similar to Terraform modules restructured (20)

PuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into OperationsPuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into Operations
Ā 
Terraform training šŸŽ’ - Basic
Terraform training šŸŽ’ - BasicTerraform training šŸŽ’ - Basic
Terraform training šŸŽ’ - Basic
Ā 
Terraform Modules and Continuous Deployment
Terraform Modules and Continuous DeploymentTerraform Modules and Continuous Deployment
Terraform Modules and Continuous Deployment
Ā 
Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423
Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423
Infrastructure as Code in your CD pipelines - London Microsoft DevOps 0423
Ā 
Terraform Abstractions for Safety and Power
Terraform Abstractions for Safety and PowerTerraform Abstractions for Safety and Power
Terraform Abstractions for Safety and Power
Ā 
Terraform training - Modules šŸŽ’
Terraform training - Modules šŸŽ’Terraform training - Modules šŸŽ’
Terraform training - Modules šŸŽ’
Ā 
Go Faster With Native Compilation
Go Faster With Native CompilationGo Faster With Native Compilation
Go Faster With Native Compilation
Ā 
Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2Go faster with_native_compilation Part-2
Go faster with_native_compilation Part-2
Ā 
Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...
Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...
Hands-on Learning with KubeFlow + Keras/TensorFlow 2.0 + TF Extended (TFX) + ...
Ā 
OroCRM Partner Technical Training: September 2015
OroCRM Partner Technical Training: September 2015OroCRM Partner Technical Training: September 2015
OroCRM Partner Technical Training: September 2015
Ā 
Patterns in Python
Patterns in PythonPatterns in Python
Patterns in Python
Ā 
Linux Assignment 3
Linux Assignment 3Linux Assignment 3
Linux Assignment 3
Ā 
Building and deploying LLM applications with Apache Airflow
Building and deploying LLM applications with Apache AirflowBuilding and deploying LLM applications with Apache Airflow
Building and deploying LLM applications with Apache Airflow
Ā 
20100730 phpstudy
20100730 phpstudy20100730 phpstudy
20100730 phpstudy
Ā 
Web Template Mechanisms in SOC Verification - DVCon.pdf
Web Template Mechanisms in SOC Verification - DVCon.pdfWeb Template Mechanisms in SOC Verification - DVCon.pdf
Web Template Mechanisms in SOC Verification - DVCon.pdf
Ā 
Productionizing Machine Learning - Bigdata meetup 5-06-2019
Productionizing Machine Learning - Bigdata meetup 5-06-2019Productionizing Machine Learning - Bigdata meetup 5-06-2019
Productionizing Machine Learning - Bigdata meetup 5-06-2019
Ā 
Hadoop cluster performance profiler
Hadoop cluster performance profilerHadoop cluster performance profiler
Hadoop cluster performance profiler
Ā 
Apachecon 2002 Struts
Apachecon 2002 StrutsApachecon 2002 Struts
Apachecon 2002 Struts
Ā 
Play Framework
Play FrameworkPlay Framework
Play Framework
Ā 
How to use source control with apex?
How to use source control with apex?How to use source control with apex?
How to use source control with apex?
Ā 

Recently uploaded

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
Ā 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vƔzquez
Ā 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
Ā 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
Ā 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
Ā 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024SynarionITSolutions
Ā 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
Ā 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
Ā 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
Ā 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
Ā 
Scaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organizationScaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organizationRadu Cotescu
Ā 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
Ā 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
Ā 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
Ā 
šŸ¬ The future of MySQL is Postgres šŸ˜
šŸ¬  The future of MySQL is Postgres   šŸ˜šŸ¬  The future of MySQL is Postgres   šŸ˜
šŸ¬ The future of MySQL is Postgres šŸ˜RTylerCroy
Ā 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
Ā 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
Ā 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
Ā 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
Ā 

Recently uploaded (20)

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
Ā 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Ā 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
Ā 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
Ā 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
Ā 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
Ā 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
Ā 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
Ā 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
Ā 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Ā 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Ā 
Scaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organizationScaling API-first ā€“ The story of a global engineering organization
Scaling API-first ā€“ The story of a global engineering organization
Ā 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
Ā 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Ā 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
Ā 
šŸ¬ The future of MySQL is Postgres šŸ˜
šŸ¬  The future of MySQL is Postgres   šŸ˜šŸ¬  The future of MySQL is Postgres   šŸ˜
šŸ¬ The future of MySQL is Postgres šŸ˜
Ā 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
Ā 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
Ā 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
Ā 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
Ā 

Terraform modules restructured

  • 1. Terraform Modules Restructured āœ“ Reusable āœ“ Composable āœ“ Automated Tests āœ“ Confidence to Make Changes āœ“ Implementation Abstraction
  • 2. These slides are heavily influenced by the slides and talks from Yevgeniy Brikman from terragrunt.io It goes hand in hand with the following talk: https://blog.gruntwork.io/5-lessons-learned-from-writing-over-300-000-lines-of-infrastructure-code-36ba7fadeac1 Credits
  • 3. Ami Mahloof Senior Cloud Architect at DoIT International. LinkedIn Profile Medium blog posts Who Am I? At DoiT International, we tackle complex problems of scale which are sometimes unique to internet-scale customers while using our expertise in resolving problems, coding, algorithms, complexity analysis, and large- scale system design.
  • 4. 1. Introduction to Terraform 2. Module Anatomy 3. Modules Structure 4. Testing 5. Terraform Modules Best Practices 6. Migrating Existing Infrastructure Into New Code Structure Outline
  • 5. An Introduction To Terraform āŒ¾ Terraform can manage existing and new infrastructure āŒ¾ Talk to multiple cloud/infrastructure providers āŒ¾ Ensure creation and consistency āŒ¾ Single DSL (Domain Specific Language) to express API agnostic calls āŒ¾ Preview changes, destroy when needed āŒ¾ Single source of truth infrastructure state āŒ¾ Even order a pizza from Dominoā€™s Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently
  • 6. AnIntroductiontoTerraform Just like in code a function has inputs (arguments) and outputs (attributes) The following sudo code creates an EC2 instance from the given args function create_ec2(name, type) { ec2 = aws.create_instance(name, type) print ec2.instance_ip } HashiCorp Configuration Language (HCL) Syntax
  • 7. AnIntroductiontoTerraform Mapping A Code To HCL Syntax function create_ec2(name, type) { ec2 = aws.create_instance(name, type) print ec2.instance_ip } Inputs (arguments) outputs (attributes)
  • 8. AnIntroductiontoTerraform Mapping A Code To HCL Syntax function create_ec2(name, type) { ec2 = aws.create_instance(name, type) print ec2.instance_ip } create_ec2("test", "t2.micro") resource "aws_ec2_instance" "create_ec2" { name = "test" type = "t2.micro" } output "instance_ip" { value = aws_ec2_instance.create_ec2.ipv4_address } name label
  • 9. AnIntroductiontoTerraform Mapping A Code To HCL Syntax function create_ec2(name, type) { ec2 = aws.create_instance(name, type) print ec2.instance_ip } create_ec2("test", "t2.micro") resource "aws_ec2_instance" "create_ec2" { name = "test" type = "t2.micro" } output "instance_ip" { value = aws_ec2_instance.create_ec2.ipv4_address } provider resource API
  • 10. AnIntroductiontoTerraform Mapping A Code To HCL Syntax function create_ec2(name, type) { ec2 = aws.create_instance(name, type) print ec2.instance_ip } create_ec2("test", "t2.micro") resource "aws_ec2_instance" "create_ec2" { name = "test" type = "t2.micro" } output "instance_ip" { value = aws_ec2_instance.create_ec2.ipv4_address } resource arguments
  • 11. AnIntroductiontoTerraform Mapping A Code To HCL Syntax function create_ec2(name, type) { ec2 = aws.create_instance(name, type) print ec2.instance_ip } create_ec2("test", "t2.micro") resource "aws_ec2_instance" "create_ec2" { name = "test" type = "t2.micro" } output "instance_ip" { value = aws_ec2_instance.create_ec2.ipv4_address } output values
  • 12. AnIntroductiontoTerraform Mapping A Code To HCL Syntax resource blocks are for create API calls: resource "aws_ec2_instance" "create_ec2" {... data blocks are for get API calls: data "aws_ec2_instance" "instance_data" { name = "test" } output "az" { value = data.aws_ec2_instance.instance_data.availbility_zone }
  • 13. āŒ¾ JSON representation of known infrastrurcture state provisioned by terraform āŒ¾ Stored in file or externally āŒ¾ Locking (useful for team working on the same project or tasks) āŒ¾ Source of truth for infrastructure AnIntroductiontoTerraform Terraform State File { "version": 4, "terraform_version": "0.12.6", "serial": 18, "lineage": "b3bfb3fc-8417-cc89-d87f-6ab0008e2056", "outputs": { "group-id": { "value": "6521262259226325019", "type": "string" } }, "resources": [ { "mode": "data", "type": "template_file", "name": "filter_pattern", "provider": "provider.template", "instances": ... terraform.tfstate
  • 14. Monolithic Terraform āŒ¾ One/several huge files - fear of making changes, no reusability, a mistake anywhere can break everything āŒ¾ Hard to find/debug - variables and sections are harder to find when one needs to make a change āŒ¾ Guess work - going back and forth between variables and resources just to understand what is required and what is the default āŒ¾ Slower development cycles - increased time and effort needed to start working with it Issues with monolithic Terraform:
  • 15. 10,000 ft View Approach
  • 16. 10,000 ft View Approach Since Terraform will combine all the files into a plan, we can use that to create smaller files with better visibility using the following simple module anatomy. Being able to quickly find what youā€™re looking for during development and debugging an issue is crucial when working with Terraform.
  • 17. Module Anatomy The module anatomy is a scaffold that provides better visibility and guidelines for developing, and working with Terraform modules. Since Terraform compiles all resources in all files into an execution plan, we can use that to create better visibility and readability. There are no hard-coded values, as each hard-coded value becomes a default variable, and every attribute is a variable.
  • 18. Development of a module is done through the examples folder which holds a main.tf file with: āŒ¾ Hard-coded values for all variables āŒ¾ Lock down a specific version for a Terraform provider āŒ¾ State location āŒ¾ Terraform version This will serve as a usage example when you finish development on the module ModuleAnatomy
  • 19. terraform { backend "s3" { region = "eu-west-3" bucket = "some-s3-bucket" key = "dev/eu-west-3/infrastructure" } required_version = ">=12.6" } # This is where you setup the provider to use with the module provider "aws" { version = "~> 2.0" region = "us-east-1" } module "route53_record_name_cname_exmaple" { source = "../" domain_name = "tf.domain.com" value = "1.2.3.4" } ModuleAnatomy examples/main.tf
  • 20. āŒ¾ examples - a folder containing examples for usage āŒ¾ test - Go Terratest folder āŒ¾ data.tf - Terraform data sources āŒ¾ main.tf - resources to be created if itā€™s over 30 lines long, break it into files with names applied for resources i.e., autoscaling.tf, ec2.tf, etc. āŒ¾ outputs.tf - outputs for the module āŒ¾ README.md - clear inputs/outputs and description for the module as well as usage āŒ¾ default-variables - variables with default values āŒ¾ required-variables - variables with values that are required ModuleAnatomy
  • 21. Module Anatomy - Quick scaffolding with bash: āžœ export module_name="sample" āžœ mkdir -p $module_name/examples $module_name/test āžœ cd $module_name && touch main.tf versions.tf default-variables.tf required-variables.tf outputs.tf data.tf ModuleAnatomy
  • 23. 3-TierModulesStructure Create and extend your own library of primitives building blocks (resources) The 3-Tier Module-Based Hierarchy Structure
  • 24. 3-TierModulesStructure Build services from these primitives building blocks The 3-Tier Module-Based Hierarchy Structure
  • 25. 3-TierModulesStructure Deploy end-to-end environments from services (live deployments) The 3-Tier Module-Based Hierarchy Structure
  • 26. 3-TierModulesStructure What are the 3-Tier modules structure major benefits: āŒ¾ Hide all lower level details to allow the end user to focus on building the infrastructure āŒ¾ Each tier is tested providing a quicker development/debugging cycle āŒ¾ Provides the confidence needed to make changes The 3-Tier Module-Based Hierarchy Structure
  • 27. 3-TierModulesStructure The goal is to isolate each (live) environment (dev, staging, production), then take each component in that environment and break it up into a generic service module, and for each generic service module break it into resource modules. Restructuring Existing Infrastructure
  • 28. 3-TierModulesStructure Break your architecture code down by live environment terraform-live-envs L dev L vpc L mysql L kubernetes L staging L vpc L mysql L kubernetes L production L vpc L mysql L kubernetes
  • 29. 3-TierModulesStructure Then by service (infrastructure type) terraform-live-envs L dev L vpc L mysql L kubernetes L staging L vpc L mysql L kubernetes L production L vpc L mysql L kubernetes terraform-services (generic modules) L gke L vpc L sql Implement infrastructure in modules
  • 30. 3-TierModulesStructure Build complex modules from smaller, simpler modules terraform-live-envs L dev L vpc L mysql L kubernetes L staging L vpc L mysql L kubernetes L production L vpc L mysql L kubernetes terraform-services L gke L vpc L sql terraform-resources L vpc L sql L instance L user
  • 31. Tier-1 Terraform Resources Modules This is the lowest tier terraform-resources is a folder containing modules with a single resource to be created These resource modules are creating only one thing These modules should have an output.tf file with outputs values providing information on the resource created This information can be used to create hard dependencies between modules (required by the 2nd tier) 3-TierModulesStructure
  • 32. Tier-2 Terraform Services Modules This is the middle tier terraform-services is a folder containing modules combining resources modules together from the terraform-resources folder Each service module is a generic service that can create multiple versions based on the variables passed in Example; an SQL instance module can create postgreSQL or mySQL instance 3-TierModulesStructure
  • 33. Tier-3 Terraform-live-envs Modules This is the top tier The terraform-live-envs is a folder containing modules implementing the infrastructure that is deployed These modules are usually built from the services modules but can also have resources modules mixed in Every module attribute is a hard-coded value representing the value that is deployed 3-TierModulesStructure
  • 34. Tier-3 terraform-live-envs Modules Each module should have one single file called main.tf that will contain: āŒ¾ Terraform state block āŒ¾ Modules with hard-coded values āŒ¾ Locals block (shared variables between modules in this file) āŒ¾ Outputs This makes for a readable easy-to-use and maintainable deployment file 3-TierModulesStructure
  • 35. Terraform Remote State By default, Terraform stores state locally in a file named terraform.tfstate This does not scale because thereā€™s no locking or central location to work with Terraform in a team. With remote state, Terraform writes the state data to a remote data store, which can then be shared between all members of a team. Terraform supports storing state in Terraform Cloud, HashiCorp Consul, Amazon S3, Alibaba Cloud OSS, and more.
  • 36. Base Remote State Often you need to create a base infrastructure for other deployments to use/read Example: You might create a VPC in one region only once, but you can deploy multiple services on that VPC.
  • 37. To do that, break your deployment into 2-steps: āŒ¾ step-1-infrastructure Creates and outputs the VPC information (vpc_id, subnets etc..) āŒ¾ step-2-some-service Accepts the remote state location (defined in step-1) as an input that will be used to read the output information for step-1, and creates the service on that VPC BaseRemoteState
  • 38. BaseRemoteState terraform { backend "s3" { region = "eu-west-3" bucket = "my-terraform-bucket" key = "dev/eu-west-3/infrastructure" } } module "vpc" { vpc_name = "vpc-dev" vpc_availability_zones = ["eu-west-3a", "eu-west-3b"] vpc_private_subnets = ["10.10.1.0/24", "10.10.2.0/24"] vpc_public_subnets = ["10.10.11.0/24", "10.10.12.0/24"] } output "infra" { value = module.vpc } Step 1 - Infrastructure
  • 39. BaseRemoteState terraform { backend "s3" { region = "eu-west-3" bucket = "my-terraform-bucket" # separate the state file location from the infrastructure state location key = "dev/eu-west-3/deployment/code-pipeline/nodejs-app" } } module "code_pipeline" { source = "../codebuild-pipeline" # these are taken from step-1 terraform backend block terraform_state_store_region = "eu-west-3" terraform_state_store_bucket = "my-terraform-bucket" infrastructure_terraform_state_store_key = "dev/eu-west-3/infrastructure" } ... Step 2 - Services on Infrastructure
  • 40. BaseRemoteState deployment/step2-codepipeline/main.tf module "code_pipeline" { source = "../codebuild-pipeline" ... } Codebuild-pipeline module # Read the information from the remote state file of step 1 infrastructure data "terraform_remote_state" "infra" { backend = "s3" config = { region = var.terraform_state_store_region bucket = var.terraform_state_store_bucket key = var.infrastructure_terraform_state_store_key } } # Assign data to locals to read the data only once locals { vpc_id = data.terraform_remote_state.infra.outputs.infra.vpc.vpc_id subnets = data.terraform_remote_state.infra.outputs.infra.vpc.subnets } # Use locals in the modules to get to the infrastructure data module "pipeline" { source = "../../modules/pipeline" vpc_id = local.vpc_id ... }
  • 41. Refactoring existing terraform code āŒ¾ Create a new bucket for the new terraform state to be stored at. āŒ¾ Rewrite your new code into the 3-tiers modules (as illustrated above and detailed in the slides). āŒ¾ Import each of the resources into your live-envs terraform code. āŒ¾ terraform will show you the execution plan for the import operation: ā—‹ values that exist in the deployed version but not in your code will be marked with a (-) minus sign for removal. ā—‹ values that do not exist in the deployed version but do exists in your code will be marked with a (+) plus sign for addition. The goal is to get a no change plan.
  • 43. Modules Git Repo Create a separate git repository for each of the tiers, and an additional to hold the shared Go code for testing the modules: āŒ¾ terraform-resources āŒ¾ terraform-services āŒ¾ terraform-live-envs āŒ¾ terratest-common Codeversioning
  • 44. Managing Module Versions For the development process, it is recommended to use a relative path when working with the source attribute of a module source = "../gcp/sql_instance" You should change the source attribute value to a git repo when the module is ready for release When a module is released, it should be tagged and added to the source attribute value using the ref argument source = "git@github.com:unicorn/terraform-resources//gcp/sql_instance?ref=...v1.0.0" Codeversioning
  • 45. Modules in Subdirectories Since we are using modules in a repo, the module itself is in a subdirectory relative to the root of the repo. A special double-forward-slash syntax is interpreted by Terraform to indicate that the remaining path after that point is a subdirectory. source = "git@github.com:unicorn/terraform-resources//gcp/sql_instance?ref=v1.0.0" The ref argument can be either a tag or a branch name Codeversioning
  • 46. Modules Tagging Convention Here is a recommended tagging convention for a module in the same repo: <module-name>-v<semantic_versioning> The module name should follow the directory structure you have in place. Example: Feel free to come up with your own tagging convention. Codeversioning gcp-sql-instance-v1.0.0
  • 48. Lock Down Terraform Version Lock down the Terraform version that was used to create the module. Place the following content in a file called versions.tf in the module: terraform { required_version = ">= 0.12" } TerraformModulesBestPractices
  • 49. Using Provider in Module TerraformModulesBestPractices provider "aws" { region = var.region version = "~> 2.24" } module "this_module" { source "../" name = "unicorn" } Terraform provider is inherited in modules. This means that a provider will be inherited by the modules your main module is calling. Use an inline provider block inside your examples folder. Only use the examples folder to test/develop your module.
  • 50. Prefer Hard Dependencies Over depends_on āŒ¾ depends_on doesnā€™t work with modules (currently on 0.12.6) āŒ¾ depends_on doesnā€™t work with data sources āŒ¾ There are some cases where depends_on would fail if the resource is it depends_on is conditionally created āŒ¾ Itā€™s better to be consistent across all the code that needs dependencies TerraformModulesBestPractices
  • 51. Instead of using depends_on (i.e., resources), create a hard dependency in Terraform between resources: TerraformModulesBestPractices Prefer Hard Dependencies Over depends_on
  • 52. Or between modules: TerraformModulesBestPractices Prefer Hard Dependencies Over depends_on
  • 53. No Hard-coded Values Each module should have the following files: āŒ¾required-variables.tf āŒ¾default-variables.tf All of the resource attributes should be variables. If an existing module is hard-coded, you should move it into the default-variables.tf file. You donā€™t have to use all attributes as documented in Terraform docs, you can add them as you go. TerraformModulesBestPractices
  • 54. No tfvar Files tfvar files are key=value lines of variables passed into a module. The main problem with using this feature is that you canā€™t tell which variable belongs to which module. This makes code usability hard to maintain and understand quickly. TerraformModulesBestPractices
  • 55. Plugins Cache Instead of having to download the same provider plugin to each module over and over again, you should set your plugin cache folder via an environment variable like so: export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache" This will ensure that the provider plugin is linked to this folder and speed up running Terraform init on new modules. TerraformModulesBestPractices
  • 56. Terraform State Management āŒ¾ Create a storage bucket (S3/GCS) per environment Do not use the same bucket for multiple envs āŒ¾ Enable versioning on the bucket - this will serve as a backup if state is corrupted or can be used to compare concurrent executions āŒ¾ Use prefix with the same folder structure you set in terraform-live-envs folder āŒ¾ Use a separate prefix for infrastructure i.e., vpc-network should be put into infrastructure/us-west2/blog-network TerraformModulesBestPractices
  • 57. Terraform Null Attribute Use a null value for an attribute you want to remove from the resource. Example; aws_s3_bucket can either be a standalone bucket or a website. If you need to make a single resource for that, you would then make a default variable with the value null, which effectively removes the attribute from the resource before creating that resource. TerraformModulesBestPractices
  • 58. Terraform and Lists Terraform will create a membership resource per user, but behind the scene, the count is also saved as an index in the state file. If you remove someone from the middle of the list, the rest of the index will shift up, causing the rest to be added/recreated In github this means delete user with its forks! TerraformModulesBestPractices
  • 59. Cascade Variables and Outputs Always cascade (copy over) the default and required variables along with the outputs to the next module tier, so the variable applied goes through all the modules. TerraformModulesBestPractices
  • 60. Terraform Testing Using Terratest Terratest is a Go library by terragrunt.io It automates the creation of the IaC (Infrastructure as code), and then tests that the actual result is what you are expecting to get. Once the tests are completed, Terratest will tear down and cleanup the resources it has created using Terraform destroy command. Tips: āŒ¾ You can use Terreatest with Docker, Packer and even helm charts! āŒ¾ Use vscode with its Go extension for a quick coding with Go āŒ¾ Learn Go interactively https://tour.golang.org
  • 61. Typical Test Structure // TestVPCCreatedWithDefaults - test VPC is created without overriding any of the default variables func TestVPCCreatedWithDefaults(t *testing.T) { terraformOptions := &terraform.Options{ // The path to where our Terraform code is located TerraformDir: "../step1-infrastructure", // Variables to pass to our Terraform code using -var options Vars: map[string]interface{}{ "region": "us-east-1", }, } } TerraformTestingwithTerratest terraformOptions is a Golang struct defining the location of the code, as well as terraform variables for the execution.
  • 62. Typical Test Structure func TestVPCCreatedWithDefaults(t *testing.T) { terraformOptions := &terraform.Options{ ... } // At the end of the test, run `terraform destroy` to clean up any resources that were created defer terraform.Destroy(t, terraformOptions) ... } TerraformTestingwithTerratest defer will run at the end of the test and call terraform destroy to clean up the resources created by this test.
  • 63. Typical Test Structure func TestVPCCreatedWithDefaults(t *testing.T) { terraformOptions := &terraform.Options{ ... } // At the end of the test, run `terraform destroy` to clean up any resources that were created defer terraform.Destroy(t, terraformOptions) // Run `terraform init` and `terraform apply` and fail the test if there are any errors terraform.InitAndApply(t, terraformOptions) ... } TerraformTestingwithTerratest Run terraform init followed by terraform apply
  • 64. Typical Test Structure func TestVPCCreatedWithDefaults(t *testing.T) { terraformOptions := &terraform.Options{ ... } ā€¦ vpc_id := terraform.Output(t, terraformOptions, "vpc_id"), validateVPC(t, vpcID) } func ValidateVPC(t *testing.T, vpcID string) {...} TerraformTestingwithTerratest Validate it works as expected
  • 65. Terratestbuilt-infunctions Terratest has many built-in functions to check your infrastructure - but itā€™s relatively easy to extend and write your own. Terratest Terratest Built-in Functions
  • 67. Run Go test. You now have a unit test you can run after every commit! Note: Go tests timeout after 10 minutes, so make sure you set a greater timeout to allow infrastructure to be created Running the Test Terratest
  • 68. Reproducible Test Results: Running tests does not take remote state configuration, thus the local module will end up having a local state file, which can lead to a stale test results. Donā€™t put the hard-coded path to the module in the test like so: terraformOptions := &terraform.Options{ // The path to where our Terraform code is located TerraformDir: "../step1-infrastructure", ā€¦ Use a built-in function in Terratest that will copy the module to a temporary folder and return the path to that folder: Terratest Testing Techniques Terratest
  • 69. import ( test_structure "github.com/gruntwork-io/terratest/modules/test-structure" ) func TestRoute53CNAMERecord(t *testing.T) { rootFolder := "../../.." modulePathRelativeToRootFolder := "terraform-aws-route53-resource/record-set" terraformTempDir := test_structure.CopyTerraformFolderToTemp( t, rootFolder, modulePathRelativeToRootFolder, ) terraformOptions := &terraform.Options{ TerraformDir: tempTestFolder, ā€¦ } Terratest Testing Techniques Terratest
  • 70. In Go, a test will only report PASS or FAILED on the function name: Multiple Tests Within a Test (subtests) Terratest Often you will need a few tests to check for the same function and reflect that in the test outputs. This concept is called subtests.
  • 71. Use the following to run multiple validations for the same test: Multiple Tests Within a Test (subtests) Terratest
  • 72. Just about every method foo in Terratest comes in two versions: foo and fooE (e.g., terraform.Apply and terraform.ApplyE). āŒ¾ foo: The base method takes a t *testing.T as an argument. If the method hits any errors, it calls t.Fatal to fail the test. āŒ¾ fooE: Methods that end with the capital letter E always return an error as the last argument and never call t.Fatal themselves. This allows you to decide how to handle errors. Terratest Error Handling Terratest
  • 73. You will use the base method name most of the time, as it allows you to keep your code more concise by avoiding if err != nil checks all over the place: terraform.Init(t, terraformOptions) terraform.Apply(t, terraformOptions) url := terraform.Output(t, terraformOptions, "url") In the code above, if Init, Apply, or Output hits an error, the method will call t.Fatal and fail the test immediately, which is typically the behavior you want. However, if you are expecting an error and don't want it to cause a test failure, use the method name that ends with a capital E: if _, err := terraform.InitE(t, terraformOptions); err != nil { // Do something with err } Terratest Error Handling Terratest
  • 74. The Test Pyramid As you go up the pyramid, tests get more expensive, brittle and slower
  • 75. The Test Pyramid How the test pyramid works with infrastructure code:
  • 76. The Test Pyramid Lots of unit tests: test individual sub-modules (keep them small!) and static analysis (TFLint, Terraform validate) Individual modules {
  • 77. The Test Pyramid Fewer integration tests: test multiple sub-modules together Individual modules Multiple modules {
  • 78. The Test Pyramid A handful of high value E2E tests: test entire environments (stage, prod) Individual modules multiple modules Entire stack {
  • 79. The Test Pyramid Note the test times! This is another reason to use small modules 60-240 minutes (terraform-live-envs modules) 5-60 minutes (terraform-services modules) 1-20 minutes (terraform-resources modules) 1-60 seconds (tflint/terraform validate)
  • 80. To minimize the downsides of testing infrastructure as a code on a real platform, follow the guidelines below: 1. Unit tests, integration tests, end-to-end tests 2. Testing environment 3. Namespacing 4. Cleanup 5. Timeouts and logging 6. Debugging interleaved test output 7. Avoid test caching 8. Error handling 9. Iterating locally using Docker 10. Iterating locally using test stages Terratest Best Practices Terratest
  • 81. ā— Use VSCode for Terraform and Go integration (you can opt to use JetBrains intelliJ too too or Vim) ā— VSCode extensions: Once installed you need to open the command palette (View -> Command Palette) and type: ā€œTerraform: Enable Language Serverā€ which will prompt you for installing the latest package for the terraform 0.12 support. Pro Tips Terratest