Trabajando con módulos en Terraform

3 minute read

Logo Terraform

En este artículo verás cómo reutilizar tu código de Terraform usando módulos para evitar tener que rescribir el mismo código una y otra vez. También aprenderás como versionar tus módulos y cómo usar versiones específicas.

¿Cómo defino un módulo?

Solo coloca todos tus archivos .tf en una carpeta, por ejemplo:

mymodule/
├── main.tf
├── outputs.tf
├── README.md
└── variables.tf

Luego cópiala dentro de una carpeta modules.

¿Cómo uso el módulo?

Usa el parámetro source para especificar la ruta de tu módulo como se muestra a continuación:

module "example" {

  source = "./modules/mymodule"

  var1 = "Hello World"
  var2 = 1999
}

Variables del módulo

Como puedes ver este módulo recibe dos argumentos, los cuales pueden ser definidos en el archivo variables.tf de mymodule.

variable "var1" {
  description = "A string var"
}

variable "var2" {
  description = "A numerical var"
default = 1989
}

Salidas del módulo

Los módulos también tienen salidas que pueden ser usadas por otros módulos y recursos. Puedes definir las salidas en el archivo outputs.tf:


output "id" {
  description = "This is the mymodule's id"
}

output "name" {
  description = "This is the mymodule's name"
}

Sources de los módulos

Los ejemplos de arriba usan el parámetro source para obtener el módulo de la carpeta local pero también puedes usar otras fuentes como un repositorio git, mercurial, urls HTTPS, buckets S3 or el Registro de módulos de Terraform.

Por ejemplo, en vez de usar una carpeta lcoal puedes usar un repositorio git para versionar tu módulo y llamarlo de esta forma:

module "example" {

  source = "git@bitbucket.org:mygitrepo/mymodule.git"

  var1 = "Hello World"
  var2 = 1999
}

Branch y versión del repositorio del módulo

Puedes también apuntar a un branch o versión específica en un repositorio git usando el query ?ref. Por ejemplo para especificar el branch dev:

module "example" {

  source = "git@bitbucket.org:mygitrepo/mymodule.git?ref=dev"

  var1 = "Hello World"
  var2 = 1999
}

Para apuntar a la versión 0.0.2 usalo así:

module "example" {

  source = "git@bitbucket.org:mygitrepo/mymodule.git?ref=0.0.2"

  var1 = "Hello World"
  var2 = 1999
}

¿Cuál es el problema con este enfoque?

Si quieres actualizar el módulo y lo has usado varias veces en un proyecto, debes editar a a mano la definición en cada lugar.

Versión del módulo

Si estás usando una versión de Terraform v0.11.0+ puedes especificar la versión del módulo. Esto ayuda a apuntar a una versión específica, por ejemplo a una estable del módulo. Esto solo funciona si estás usando un registro de módulo como el Terraform Registry

module "example" {
  source  = "hashicorp/mymodule"
  version = "0.0.2"

  var1 = "Hello World"
  var2 = 1999
}

¿Cuál es el problema con este enfoque?

  • El registro de Terraform es público. Para usar el registro privado (Private Registry) debes usar la versión Enterpise
  • Solo disponible para las versiones v0.11.0+ de Terraform

Usando un Terrafile

Hay otro enfoque para superar los problemas de las versiones, el cual consiste en escribir un archivo para definir los módulos a usar desde un repositorio git, por branch o versión. Este archivo es conocido como 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"                   

Estos módulos se descargaran en la carpeta modules: y luego puedes referenciarlos en tu módulo usando esta carpeta local_:

module "example" {

  source = "./modules/mymodule"

  var1 = "Hello World"
  var2 = 1999
}

Para obtener los módulos usa este 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

Y descárgalos usando la función get_modules:

rake get_modules

Finalmente obten los módulos en Terraform:

terraform get

Referencias

Leave a Comment