Nomad Cluster
The nomad_cluster resource creates HashiCorp Nomad clusters as Docker containers. Nomad clusters can be configured as single-node combined server/client instances or multi-node setups with dedicated server and client nodes.
Use Cases
Section titled “Use Cases”As a lab author, you can use nomad_cluster resources to:
- Container Orchestration Learning: Provide hands-on experience with HashiCorp Nomad for container scheduling and management
- Multi-Node Cluster Scenarios: Create realistic distributed computing environments with server and client nodes
- Microservices Architecture: Deploy and manage complex multi-tier applications using Nomad job specifications
Nomad cluster resources enable realistic container orchestration scenarios for learning HashiCorp’s workload scheduler.
HCL Syntax
Section titled “HCL Syntax”Basic Syntax
Section titled “Basic Syntax”resource "nomad_cluster" "name" { network { id = resource.network.main }}Full Syntax
Section titled “Full Syntax”resource "nomad_cluster" "name" { # Network configuration network { id = resource.network.main ip_address = "10.0.0.10" aliases = ["nomad", "server"] }
# Optional cluster configuration client_nodes = 3 datacenter = "dc1" environment = { NOMAD_LOG_LEVEL = "INFO" CUSTOM_VAR = "value" }
# Configuration files server_config = "./nomad/server.hcl" client_config = "./nomad/client.hcl" consul_config = "./consul/config.hcl"
# Image configuration image { name = "hashicorp/nomad:1.8.4" username = "username" password = "password" }
# Volume mounts volume { source = "./nomad-data" destination = "/opt/nomad/data" type = "bind" read_only = false }
# Port mappings port { local = 4646 host = 4646 protocol = "tcp" }
port_range { local_range = "8000-8010" host_range = "8000-8010" protocol = "tcp" }
# Image copying copy_image { name = "myapp:latest" username = "registry_user" password = "registry_pass" }
# Driver configuration config { docker { no_proxy = ["registry.local"] insecure_registries = ["registry.local:5000"] } }
open_in_browser = false}Fields
| Field | Type | Required | Description |
|---|---|---|---|
network | block | — | Connect your container to a specific network to enable communication between containers or services.repeatable |
image | block | — | Container image for the cluster nodes |
client_ | number | — | Number of client nodes |
environment | map(string) | — | Environment variables for the cluster |
server_ | string | — | Path to server configuration file |
client_ | string | — | Path to client configuration file |
consul_ | string | — | Path to Consul configuration file |
volume | block | — | Attach persistent storage or share data between containers using volumes.repeatable |
open_ | bool | — | Open the Nomad UI in the browser after creation |
datacenter | string | — | Nomad datacenter, defaults to dc1 |
copy_ | block | — | Images to copy from local docker cache to the clusterrepeatable |
port | block | — | Expose specific ports so learners can access web apps, APIs, or services running in the container.repeatable |
port_ | block | — | Range of ports to exposerepeatable |
config | block | — | Driver configuration |
Network
Network attachments for the cluster
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | ID of the network to attach the container |
ip_ | string | — | Static IP address to assign container for the network, the ip address must be within range defined by the network subnet. If this parameter is omitted an IP address will be automatically assigned. |
aliases | list(string) | — | Aliases allow alternate names to specified for the container |
Image
Container image for the cluster nodes
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✓ | Docker image name with optional tag ConstraintsMust match `^[a-z0-9]([a-z0-9-]*[a-z0-9])*(\.[a-z0-9]([a-z0-9-]*[a-z0-9])*)*(/[a-z0-9]+([a-z0-9._-]*[a-z0-9])*)*(:[a-z0-9]+([a-z0-9._-]*[a-z0-9])*)?$` |
username | string | — | Docker registry user to use for private repositories |
password | string | — | Docker registry password to use for private repositories |
Volume
Volumes to attach to the cluster
| Field | Type | Required | Description |
|---|---|---|---|
source | string | ✓ | The source volume to mount in the container, can be specified as a relative `./` or absolute path `/usr/local/bin`. Relative paths are relative to the file declaring the container. |
destination | string | ✓ | The destination in the container to mount the volume to, must be an absolute path |
type | string | — | The type of the mount, can be one of the following values:
- bind: bind the source path to the destination path in the container
- volume: source is a Docker volume
- tmpfs: create a temporary filesystem Allowed bind volume tmpfsDefault bind |
read_ | bool | — | Whether or not the volume is read only |
bind_ | string | — | Configures bind propagation for Docker volume mounts, only applies to bind mounts, can be one of the following values:
- shared
- slave
- private
- rslave
- rprivate
For more information please see the Docker documentation. Allowed shared private slave rslave rprivateDefault shared |
bind_ | bool | — | Configures recursiveness of the bind mount. By default Docker mounts with the equivalent of `mount --rbind` meaning that mounts below the the source directory are visible in the container. For instance running `docker run --rm --mount type=bind,src=/,target=/host,readonly` busybox will make `/run` of the host available as `/host/run` in the container. To make matters even worse it will be writable (since only the toplevel bind is set readonly, not the children). If `bind_propagation_non_recursive` is set to true then the container will only see an empty `/host/run`, meaning the `tmpfs` which is typically mounted to `/run` on the host is not propagated into the container. |
selinux_ | string | — | Configures Selinux relabeling for the container (usually specified as :z or :Z) and can be one of the following values:
- shared (Equivalent to :z)
- private (Equivalent to :Z) Allowed shared private |
Copy Image
Images to copy from local docker cache to the cluster
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✓ | Docker image name with optional tag ConstraintsMust match `^[a-z0-9]([a-z0-9-]*[a-z0-9])*(\.[a-z0-9]([a-z0-9-]*[a-z0-9])*)*(/[a-z0-9]+([a-z0-9._-]*[a-z0-9])*)*(:[a-z0-9]+([a-z0-9._-]*[a-z0-9])*)?$` |
username | string | — | Docker registry user to use for private repositories |
password | string | — | Docker registry password to use for private repositories |
Port
Additional ports to expose on the server node
| Field | Type | Required | Description |
|---|---|---|---|
local | number | ✓ | The local port in the container ConstraintsMinimum 1; Maximum 65535 |
remote | number | — | Remote port of the service ConstraintsMinimum 1; Maximum 65535 |
host | number | — | The host port to map the local port to ConstraintsMinimum 1; Maximum 65535 |
protocol | string | — | The protocol to use when exposing the port Allowed tcp udpDefault tcp |
open_ | string | — | When a host port is defined open this port with the given path in a browser |
Port Range
Range of ports to expose
| Field | Type | Required | Description |
|---|---|---|---|
range | string | ✓ | Port range (e.g., '8080-8090') |
enable_ | bool | — | Enable host port mapping |
protocol | string | — | Protocol (tcp, udp) |
Config
Driver configuration
| Field | Type | Required | Description |
|---|---|---|---|
docker | block | — | Docker driver configuration |
Docker
Docker driver configuration
| Field | Type | Required | Description |
|---|---|---|---|
no_ | list(string) | — | Docker registries to exclude from the image cache |
insecure_ | list(string) | — | Docker registries to treat as insecure |
Computed Attributes
These attributes are set by the system and are read-only.
| Attribute | Type | Description |
|---|---|---|
network[].name | string | Name will equal the name of the network as created by jumppad |
network[].assigned_address | string | AssignedAddress will equal if IPAddress is set, else it will be the value automatically assigned from the network |
image.id | string | Unique identifier for the image, this is independent of tag and changes each time the image is built. An image that has been tagged multiple times also shares the same ID. |
copy_image[].id | string | Unique identifier for the image, this is independent of tag and changes each time the image is built. An image that has been tagged multiple times also shares the same ID. |
api_port | number | Port the Nomad API is running on |
connector_port | number | Port where the connector is running |
config_dir | string | Directory where server and client config is written |
server_container_name | string | Fully qualified docker address for the server |
client_container_name | list(string) | Fully qualified docker addresses for the client nodes |
external_ip | string | IP address of the cluster |
Examples
Section titled “Examples”Single Node Cluster
Section titled “Single Node Cluster”resource "network" "nomad" { subnet = "10.0.0.0/24"}
resource "nomad_cluster" "dev" { network { id = resource.network.nomad }}Multi-Node Cluster
Section titled “Multi-Node Cluster”resource "network" "nomad" { subnet = "10.0.0.0/24"}
resource "nomad_cluster" "production" { client_nodes = 3 datacenter = "east"
network { id = resource.network.nomad ip_address = "10.0.0.10" aliases = ["nomad-server", "server"] }
environment = { NOMAD_LOG_LEVEL = "INFO" DATACENTER = "east" }
volume { source = "./nomad-data" destination = "/opt/nomad/data" type = "bind" }
port { local = 4646 host = 4646 }}Cluster with Custom Configuration
Section titled “Cluster with Custom Configuration”resource "nomad_cluster" "custom" { client_nodes = 2
network { id = resource.network.main }
server_config = "./config/server.hcl" client_config = "./config/client.hcl" consul_config = "./config/consul.hcl"
config { docker { no_proxy = ["registry.internal.com"] insecure_registries = ["registry.internal.com:5000"] } }
copy_image { name = "myapp:latest" }
copy_image { name = "postgres:13" }
volume { source = "./nomad-jobs" destination = "/opt/nomad/jobs" type = "bind" read_only = true }}Development Cluster with Port Ranges
Section titled “Development Cluster with Port Ranges”resource "nomad_cluster" "dev" { network { id = resource.network.dev }
environment = { NOMAD_LOG_LEVEL = "DEBUG" }
port_range { local_range = "8000-8010" host_range = "8000-8010" protocol = "tcp" }
port { local = 4646 host = 4646 }
open_in_browser = true}Usage with Jobs
Section titled “Usage with Jobs”Nomad clusters are commonly used with nomad_job resources:
resource "nomad_cluster" "app" { client_nodes = 2
network { id = resource.network.app }}
resource "nomad_job" "web" { cluster = resource.nomad_cluster.app
jobspec = <<-EOF job "web" { datacenters = ["dc1"]
group "web" { count = 2
task "nginx" { driver = "docker"
config { image = "nginx:latest" ports = ["http"] }
resources { cpu = 100 memory = 128 } } } } EOF}Best Practices
Section titled “Best Practices”- Network Planning: Use dedicated networks for Nomad clusters to isolate traffic
- Resource Limits: Configure appropriate resource limits for production workloads
- Configuration Files: Use external configuration files for complex setups
- Data Persistence: Mount volumes for Nomad data directories in production
- Security: Use private registries and secure configuration for sensitive environments
- Monitoring: Expose necessary ports for monitoring and observability tools
- Image Management: Pre-load frequently used images using copy_image blocks
