Skip to content

Module

The module resource allows you to reuse and organize HCL configuration by importing external configuration files. Modules enable code reusability, maintainability, and collaboration by packaging common lab patterns into reusable components that can be shared across different lab configurations.

As a lab author, you can use modules to create more organized and reusable configurations:

  • Configuration Reusability: Package common lab patterns (e.g., LAMP stack, Kubernetes cluster) into modules that can be reused across multiple labs
  • Team Collaboration: Share standardized lab components with team members through module registries or repositories
  • Complex Lab Organization: Break large lab configurations into smaller, manageable modules organized by functionality
  • Environment Variations: Create modules that can be configured with different variables for development, staging, and production environments
  • Third-Party Integration: Use community modules or vendor-provided modules for common infrastructure patterns
  • Version Management: Use different versions of modules to maintain compatibility and control updates

Modules promote code reuse and help maintain consistency across lab configurations while reducing duplication and complexity.

module "name" {
source = "./path/to/module"
}
module "web_stack" {
source = "github.com/example/lab-modules//web-stack"
version = "v1.2.0"
variables = {
environment = "production"
cpu_limit = 2048
replicas = 3
}
depends_on = ["resource.network.main"]
}
FieldRequiredTypeDescription
sourcestringLocation of the module (local path, GitHub URL, or registry reference)
versionstringVersion of the module to use. Defaults to “latest”.
variablesanyVariables to pass to the module (can be object, list, or primitive values)
depends_onlist(string)List of resource dependencies (inherited from ResourceBase)
disabledboolWhether this module is disabled. Defaults to false.

Modules can be sourced from different locations:

Source Type Format Example
Local Filesystem Relative path source = "./modules/web-server"
GitHub Repository GitHub URL with optional subdirectory source = "github.com/org/repo//modules/web"
Module Registry registry/namespace/module format source = "instruqt.com/hashicorp/consul"

Resources within modules are referenced using the syntax:

module.module_name.resource.resource_type.resource_name

Module outputs are referenced using:

module.module_name.output.output_name
module "database" {
source = "./modules/postgres"
variables = {
database_name = "myapp"
username = "admin"
port = 5432
}
}
# Reference module resources
resource "container" "app" {
image {
name = "myapp:latest"
}
environment = {
DB_HOST = module.database.resource.container.postgres.meta.name
DB_PORT = "5432"
}
}
module "k8s_cluster" {
source = "github.com/instruqt/lab-modules//kubernetes/basic-cluster"
version = "v2.1.0"
variables = {
cluster_name = "demo-cluster"
node_count = 3
cpu_per_node = 2048
}
}
# Use module outputs
output "cluster_kubeconfig" {
value = module.k8s_cluster.output.kubeconfig_path
}
module "web_stack" {
source = "instruqt.com/examples/lamp-stack"
variables = {
environment = variable.env
php_version = "8.1"
mysql_root_pass = "secure_password"
}
}
# Base networking module
module "network" {
source = "./modules/network"
variables = {
subnet_cidr = "10.0.0.0/16"
}
}
# Web tier module that depends on network
module "web_tier" {
source = "./modules/web-tier"
depends_on = ["module.network"]
variables = {
network_id = module.network.output.network_id
instance_type = "standard"
replica_count = 2
}
}
# Database tier module
module "db_tier" {
source = "./modules/database"
depends_on = ["module.network"]
variables = {
network_id = module.network.output.network_id
database_size = "large"
backup_enabled = true
}
}
module "microservices" {
source = "./modules/microservices"
variables = {
# String variables
environment = "staging"
namespace = "my-app"
# Number variables
cpu_limit = 1024
memory_limit = 2048
# Boolean variables
monitoring_enabled = true
debug_mode = false
# List variables
services = ["api", "web", "worker"]
ports = [8080, 8081, 8082]
# Object variables
database_config = {
host = "postgres.local"
port = 5432
database = "myapp"
ssl = true
}
# Complex nested structure
service_configs = {
api = {
replicas = 3
cpu = 512
memory = 1024
}
web = {
replicas = 2
cpu = 256
memory = 512
}
}
}
}
module "monitoring" {
source = "./modules/monitoring"
disabled = !variable.enable_monitoring
variables = {
environment = variable.environment
services = ["web", "api", "database"]
}
}
# Base infrastructure module
module "infrastructure" {
source = "./modules/infrastructure"
variables = {
environment = variable.environment
}
}
# Application module using infrastructure outputs
module "application" {
source = "./modules/application"
depends_on = ["module.infrastructure"]
variables = {
network_id = module.infrastructure.output.network_id
subnet_id = module.infrastructure.output.subnet_id
app_name = variable.app_name
}
}
# Monitoring module using both previous modules
module "monitoring" {
source = "./modules/monitoring"
depends_on = ["module.infrastructure", "module.application"]
variables = {
network_id = module.infrastructure.output.network_id
app_container = module.application.output.app_container_name
monitoring_port = 9090
}
}

A typical module directory structure:

modules/
└── web-server/
├── main.hcl # Main module configuration
├── variables.hcl # Variable definitions
├── outputs.hcl # Output definitions
└── templates/ # Template files (if needed)
└── nginx.conf.tpl

modules/web-server/variables.hcl:

variable "server_name" {
default = "web-server"
description = "Name of the web server"
}
variable "port" {
default = 80
description = "Port for the web server"
}
variable "image_tag" {
default = "latest"
description = "Docker image tag to use"
}

modules/web-server/main.hcl:

resource "container" "web" {
image {
name = "nginx:${variable.image_tag}"
}
container_name = variable.server_name
port {
local = variable.port
remote = 80
}
}
resource "template" "config" {
source = "templates/nginx.conf.tpl"
destination = "./nginx.conf"
vars = {
server_name = variable.server_name
listen_port = variable.port
}
}

modules/web-server/outputs.hcl:

output "container_name" {
value = resource.container.web.meta.name
description = "Name of the web server container"
}
output "service_url" {
value = format("http://localhost:%d", variable.port)
description = "URL to access the web server"
}
  1. Clear Interface: Define clear input variables and outputs for your modules
  2. Documentation: Include descriptions for all variables and outputs
  3. Version Control: Use version tags for modules shared across teams
  4. Default Values: Provide sensible defaults for optional variables
  5. Modular Design: Keep modules focused on specific functionality
  6. Dependency Management: Use explicit dependencies when modules need specific ordering
module "app_environment" {
source = "./modules/environment"
variables = {
environment = variable.environment
config = {
dev = {
cpu = 512
memory = 1024
replicas = 1
debug = true
}
prod = {
cpu = 2048
memory = 4096
replicas = 3
debug = false
}
}[variable.environment]
}
}
# Shared database module
module "shared_database" {
source = "./modules/postgres"
variables = {
instance_type = "high-performance"
databases = ["app1", "app2", "app3"]
}
}
# Multiple apps using the shared database
module "app1" {
source = "./modules/web-app"
variables = {
database_host = module.shared_database.output.host
database_name = "app1"
}
}
module "app2" {
source = "./modules/web-app"
variables = {
database_host = module.shared_database.output.host
database_name = "app2"
}
}
  • Source Required: The source field must be specified
  • Valid Module Name: Module names must follow valid identifier rules
  • Dependency References: Dependencies in depends_on must reference existing resources
  • Variable Types: Variables passed to modules must match expected types in the module
  • Single Label: Module blocks must have exactly one label (the module name)

Modules provide a powerful way to organize, reuse, and share lab configuration patterns, enabling you to build complex lab environments from well-tested, reusable components.