Nomad by HashiCorp is a workload orchestrator: it schedules and runs applications across a cluster of servers, much like Kubernetes, but with a much smaller footprint and simpler concepts. It runs Docker containers, plain binaries, Java apps and VMs, all from the same job files. For small teams with a handful of VPS servers, Nomad can be a pragmatic middle ground between Docker Compose and Kubernetes.

Comparison: Kubernetes vs Docker Compose.

Architecture

  • Servers (3 for high availability; 1 for small or dev setups): store state, and make scheduling decisions (Raft consensus).
  • Clients: run the workloads, using task drivers (docker, exec, raw_exec, java, qemu, podman).
  • A single binary (nomad) acts as server, client, or both.

Often paired with Consul (service discovery and health checks) and Vault (secrets), but both are optional. Nomad has built-in service discovery for simple setups.

Licensing note

HashiCorp moved Nomad (and its other products) to the Business Source License (BSL). Using Nomad to run your own workloads is permitted, but offering it as a competing commercial service isn’t. Check the current licence terms for your use case.

Try it: single-node dev agent

# install from HashiCorp's apt repository (see their docs), then:
sudo nomad agent -dev -bind 0.0.0.0 -network-interface=eth0
# UI at http://<server>:4646  (keep it private: SSH tunnel or VPN)

Docker must be installed on the client for the docker driver. See install Docker.

A job file

# web.nomad.hcl
job "web" {
  datacenters = ["dc1"]
  type        = "service"

  group "web" {
    count = 2

    network {
      port "http" { to = 80 }
    }

    service {
      name     = "web"
      port     = "http"
      provider = "nomad"
      check {
        type     = "http"
        path     = "/"
        interval = "10s"
        timeout  = "2s"
      }
    }

    task "nginx" {
      driver = "docker"
      config {
        image = "nginx:1.27"
        ports = ["http"]
      }
      resources {
        cpu    = 200   # MHz
        memory = 128   # MB
      }
    }

    update {
      max_parallel     = 1
      health_check     = "checks"
      auto_revert      = true
    }
  }
}
nomad job plan web.nomad.hcl      # dry run: what would change
nomad job run web.nomad.hcl
nomad job status web
nomad alloc logs <alloc-id>

The update block gives rolling updates with automatic rollback, if health checks fail.

Multi-node cluster (outline)

  1. Install Nomad on 3 server nodes, with server { enabled = true, bootstrap_expect = 3 }.
  2. Install Nomad on client nodes, with client { enabled = true, servers = [...] }, plus Docker.
  3. Connect nodes over a private network or VPN, and open Nomad’s ports (4646 HTTP, 4647 RPC, 4648 gossip) only between them. See WireGuard.
  4. Enable ACLs and TLS before production use.

Routing traffic

Nomad doesn’t include an ingress. Common choices are Traefik or Fabio, reading Nomad or Consul service registrations, or Nginx with consul-template. See Traefik reverse proxy.

When Nomad fits

Good fit Less ideal
Small team, a few servers, mixed workloads (containers + binaries) You need the Kubernetes ecosystem (Helm charts, operators)
Want HA scheduling without Kubernetes complexity Strict open-source licence requirements
Batch jobs and periodic jobs alongside services Teams already skilled in Kubernetes

Quick reference

Task Command
Dev agent nomad agent -dev
Plan / run nomad job plan / nomad job run file.hcl
Status nomad job status web
Logs nomad alloc logs <id>
Stop nomad job stop web
Ports 4646 (UI/API), 4647, 4648

Related: Docker Swarm and k3s.

  • DevOps
  • Containers
  • Orchestration