Working with Terraform modules
In this post you’ll see how reuse your Terraform code using modules to avoid writing the same code over and over. Also you will lear how to version your modules and how to use a specific version.
How to define a module?
Just put all your .tf files into a folder, for example:
mymodule/
├── main.tf
├── outputs.tf
├── README.md
└── variables.tf
Then copy it into a modules folder.
How to use the module?
Use the source parameter to specify the path of your module as shown below:
module "example" {
source = "./modules/mymodule"
var1 = "Hello World"
var2 = 1999
}
Module’s variables
As you can see this module receives two arguments, which can be defined in the mymodule’s variables.tf file.
variable "var1" {
description = "A string var"
}
variable "var2" {
description = "A numerical var"
default = 1989
}
Module’s outputs
Modules also have outputs that can be used by other modules and resources. You can define them in the outputs.tf file:
output "id" {
description = "This is the mymodule's id"
}
output "name" {
description = "This is the mymodule's name"
}
Modules Sources
The above examples use the source parameter to retrieve the module from a local folder, but you can also use other sources like a git repository, mercurial repository, HTTP urls, S3 bucket or the Terraform Registry.
For example, instead of using a folder you can use a git repository to version your module and call it this way:
module "example" {
source = "git@bitbucket.org:mygitrepo/mymodule.git"
var1 = "Hello World"
var2 = 1999
}
Module repo branch and version
You can also point to a specific branch or version in a git repository using the ?ref query. For example to specify the dev branch:
module "example" {
source = "git@bitbucket.org:mygitrepo/mymodule.git?ref=dev"
var1 = "Hello World"
var2 = 1999
}
To point to version 0.0.2 use it like this:
module "example" {
source = "git@bitbucket.org:mygitrepo/mymodule.git?ref=0.0.2"
var1 = "Hello World"
var2 = 1999
}
What’s the problem with this approach?
If you want to upgrade the module version and you have used it several times in your project you must edit it in every place you defined it by hand.
Module version
If your are using Terraform version v0.11.0+ you can use a specific version for a module. This help you to point to a specific version, for example to a an stable version of the module. This only works if you are using a module registry like the Terraform Registry
module "example" {
source = "hashicorp/mymodule"
version = "0.0.2"
var1 = "Hello World"
var2 = 1999
}
What’s the problem with this approach?
- The Terraform Registry is a public registry. For private use you must use the Private Registry available ine the Enterprise version.
- Only available for Terraform version v0.11.0+
Using a Terrafile
There’s another approach to overcome the version pitfalls which is to write a file to define the modules to use from a git repository, by branch or version. This file si called the Terrafile:
---
# VPC
tf_aws_vpc:
source : "git@github.com:terraform-community-modules/tf_aws_vpc.git"
version: "master"
tf_my_module:
source: "git@bitbucket.org:mygitrepo/mymodule.git"
version: "0.0.2"
These modules will be downloaded into a modules folder and then you can reference your module using this local folder:
module "example" {
source = "./modules/mymodule"
var1 = "Hello World"
var2 = 1999
}
To get the modules you can use the this Rakefile:
require 'yaml'
require 'fileutils'
# You may want to change this.
def modules_path
'vendor/modules'
end
# You may want to change this.
def terrafile_path
'Terrafile'
end
def read_terrafile
if File.exist? terrafile_path
YAML.load_file terrafile_path
else
fail('[*] Terrafile does not exist')
end
end
def create_modules_directory
unless Dir.exist? modules_path
puts "[*] Creating Terraform modules directory at '#{modules_path}'"
FileUtils.makedirs modules_path
end
end
def delete_cached_terraform_modules
puts "[*] Deleting cached Terraform modules at '#{modules_path}'"
FileUtils.rm_rf modules_path
end
desc 'Fetch the Terraform modules listed in the Terrafile'
task :get_modules do
terrafile = read_terrafile
create_modules_directory
delete_cached_terraform_modules
terrafile.each do |module_name, repository_details|
source = repository_details['source']
version = repository_details['version']
puts "[*] Checking out #{version} of #{source} ...".colorize(:green)
Dir.mkdir(modules_path) unless Dir.exist?(modules_path)
Dir.chdir(modules_path) do
`git clone -b #{version} #{source} #{module_name} &> /dev/null`
end
end
end
And download them using the get_modules function:
rake get_modules
Finally get the modules in Terraform
terraform get
Leave a Comment