Terraform/Terragrunt – Create a module. Part 1

In this example, we will create a Terraform module for the AWS provider, which will be launched for 3 different environments using Terragrunt.

 

Requirements:

 

Create the required files for Terragrunt:

terragrunt.hcl

terraform {
  extra_arguments "custom_vars" {
    commands = get_terraform_commands_that_need_vars()
    arguments = [
      "-var-file=${get_terragrunt_dir()}/common.tfvars",
    ]
  }
}

remote_state {
  backend = "s3"
  config = {
    bucket         = "tfstate.eu-west-2.artem"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "eu-west-2"
    encrypt        = true
    dynamodb_table = "my-lock-table"
  }
}

 

Set the S3 bucket name that will store Terragrunt’s state, you don’t need to create it first, Terragrunt will create it yourself. We also set the region.

Create a file to store Terraform and Terragrunt variables:

touch common.tfvars variables.tf

 

We will write the first module that will create the VPC and Internet Gateway for it.

We create a directory for modules and for VPC in particular:

mkdir -p modules/vpc

 

Modules work on the principle of a function; when accessing them, we pass a number of variables.

To create a VPC, we need to know the following:

  • VPC name
  • CIDR

 

Create a separate file for the variables "modules/vpc/variables.tf" and add the following:

variable "vpc_name" {}
variable "vpc_cidr" {}

 

We create the module itself, for this we create the file "modules/vpc/main.tf" with the following contents:

#################### CREATE VPC ####################

resource "aws_vpc" "vpc" {
  cidr_block = var.vpc_cidr
  enable_dns_hostnames = "true"
  enable_dns_support = "true"

  tags = {
    Name = var.vpc_name
  }
}
 
############# CREATE INTERNET GATEWAY ##############

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
 
  tags = {
    Name = "${var.vpc_name}-IGW"
  }
}

 

We will create a template for three different environments:

  • development
  • staging
  • production

 

Fill out the variable file for Terragrunt:

common.tfvars

### DEVELOPMENT ENVIRONMENT ####

development_aws_region = "us-east-1"
development_vpc_name = "ARTEM-DEVELOPMENT-USE1"
development_vpc_cidr = "192.168.0.0/16"

######### END OF BLOCK #########

##### STAGING ENVIRONMENT ######

staging_aws_region = "us-east-1"
staging_vpc_name = "ARTEM-STAGING-USE1"
staging_vpc_cidr = "192.168.0.0/16"

######### END OF BLOCK #########

#### PRODUCTION ENVIRONMENT ####

production_aws_region = "eu-central-1"
production_vpc_name = "ARTEM-PRODUCTION-EUC1"
production_vpc_cidr = "192.168.0.0/16"

######### END OF BLOCK #########

 

Now fill in the Terraform variables file:

variables.tf

### DEVELOPMENT ENVIRONMENT ####

variable "development_aws_region" {}
variable "development_vpc_name" {}
variable "development_vpc_cidr" {}

######### END OF BLOCK #########

##### STAGING ENVIRONMENT ######

variable "staging_aws_region" {}
variable "staging_vpc_name" {}
variable "staging_vpc_cidr" {}

######### END OF BLOCK #########

#### PRODUCTION ENVIRONMENT ####

variable "production_aws_region" {}
variable "production_vpc_name" {}
variable "production_vpc_cidr" {}

######### END OF BLOCK #########

 

We are ready to create the first environment, we will begin with the development of the environment

Create the structure:

mkdir -p environments/development

 

Let’s go to the created directory:

cd environments/development

 

Create the required file "terragrunt.hcl" and paste the following into it:

include {
  path = find_in_parent_folders()
}

 

And create symbolic links to variable files located in the root:

ln -s ../../variables.tf variables.tf
ln -s ../../common.tfvars common.tfvars

 

Create the file "main.tf" with the following contents:

terraform {
  backend "s3" {}
}

provider "aws" {
  region  = var.development_aws_region
}

 

That’s it, now you can create a Terraform file to call the module to create a VPC.

vpc.tf

module "vpc" {
  source        = "../../modules/vpc"
  vpc_name      = var.development_vpc_name
  vpc_cidr      = var.development_vpc_cidr
}

 

Run:

terragrunt init

 

At the first start, Terragrunt will say that the bucket for storing states does not exist, and will offer to create it, we agree.

After init, we look at the version of Terraform and the AWS provider, it is better to specify these versions in the "main.tf" file, if you plan to start from another computer (since we create a basket to store the state, we mean launch from any computer keeping current state)

terraform --version
Terraform v0.12.9
+ provider.aws v2.30.0

 

main.tf

terraform {
  backend "s3" {}
  required_version = "~> 0.12.9"
}

provider "aws" {
  region  = var.development_aws_region
  version = "~> 2.30"
}

 

Now, following the example of a development environment, we will create staging and production. Go back to the root of the project, delete the ".terraform" directory in "envarinments/development" and copy the development environment:

rm -rf environments/development/.terraform/
cp -aR environments/development environments/staging
cp -aR environments/development environments/production

 

Change the variables for staging:

sed -i 's/development/staging/g' environments/staging/{main.tf,vpc.tf}

 

Change the variables for production:

sed -i 's/development/production/g' environments/production/{main.tf,vpc.tf}

 

Now, being at the root of the project, we can start planning for all environments with one command:

terragrunt plan-all

 

You can apply this template for each environment in particular, being in the directory of the necessary environment, run:

terragrunt apply

 

Or for all at once, being at the root of the project, run:

terragrunt apply-all

 

Our final structure is as follows:

.
├── common.tfvars
├── environments
│   ├── development
│   │   ├── common.tfvars -> ../../common.tfvars
│   │   ├── main.tf
│   │   ├── terragrunt.hcl
│   │   ├── variables.tf -> ../../variables.tf
│   │   └── vpc.tf
│   ├── production
│   │   ├── common.tfvars -> ../../common.tfvars
│   │   ├── main.tf
│   │   ├── terragrunt.hcl
│   │   ├── variables.tf -> ../../variables.tf
│   │   └── vpc.tf
│   └── staging
│       ├── common.tfvars -> ../../common.tfvars
│       ├── main.tf
│       ├── terragrunt.hcl
│       ├── variables.tf -> ../../variables.tf
│       └── vpc.tf
├── modules
│   └── vpc
│       ├── main.tf
│       └── variables.tf
├── terragrunt.hcl
└── variables.tf

6 directories, 20 files

 

In order to store our template in the repository, add the following to the ".gitignore" file:

.terraform/
terraform.*

 

This example can be downloaded from the Git repository:

https://bitbucket.org/artem-gatchenko/example-terraform-module-part1

Tagged: Tags

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments