Containers & Orchestration·7 min read·

Lightweight Workload Orchestration with HashiCorp Nomad on a Linux VPS

Run containerized and raw binary microservices effortlessly on a single VPS with HashiCorp Nomad, cutting memory overhead compared to full Kubernetes.

NB

Netbay Infrastructure Team

Netbay Engineering

On this page

Kubernetes is the industry benchmark for massive container fleets spanning hundreds of nodes, but running a full Kubernetes control plane on a modest VPS often consumes upwards of 1GB to 2GB of memory before a single user application has even started. HashiCorp Nomad offers a streamlined, single-binary orchestrator capable of managing both Docker containers and raw Linux binaries with a tiny memory footprint of approximately 75MB.

On a single VPS, Nomad can operate simultaneously as both server (evaluating scheduling decisions) and client (managing task runners and cgroup isolation), delivering declarative rolling deployments, health checks, and automatic restart handling.

Nomad's elegance lies in its architectural minimalism. Unlike Kubernetes, which requires reconciling dozens of custom resource definitions (CRDs), dynamic admission webhooks, etcd key-value stores, and API aggregators, Nomad is shipped as a single statically linked binary written in Go. Its core abstractions are intuitive: Jobs define the desired state, Task Groups specify co-located tasks that share networking and allocation directories, and Tasks represent the individual container or binary process to execute.

Expand
Nomad Lightweight Orchestration
Nomad scheduler architecture and job execution

Installing and Configuring Nomad Single-Node Mode

Install the official HashiCorp package and configure a combined server and client daemon in /etc/nomad.d/nomad.hcl:

HashiCorp Nomad Architecture: Single Agent Server + Client Nomad Agent Process (nomad) Single statically linked Go binary (~75MB RAM) Server mode: State store, Raft consensus, Plan scheduler Client mode: Node fingerprinting & task runner Multi-Driver Execution Driver 'docker': Full container isolation Driver 'exec' / 'raw_exec': Native Linux binaries Nomad vs Kubernetes Overhead Memory Footprint: - Nomad: ~75 MB resident RAM - K8s (k3s): ~600 MB - 1.2 GB RAM Operational Surface: - Nomad: 1 binary, 1 declarative HCL file - K8s: etcd, apiserver, scheduler, CNI, CSI Perfect for 2GB - 8GB VPS Deployments
ini
# /etc/nomad.d/nomad.hcl
data_dir  = "/opt/nomad/data"
bind_addr = "127.0.0.1"

server {
  enabled          = true
  bootstrap_expect = 1
}

client {
  enabled = true
  servers = ["127.0.0.1:4646"]
  options = {
    "driver.raw_exec.enable" = "1"
  }
}

plugin "docker" {
  config {
    allow_privileged = false
  }
}

Notice the directive bootstrap_expect = 1. In a single-node setup, this instructs Nomad's internal Raft consensus engine that a single server instance constitutes a full quorum, preventing leader election deadlocks.

Enable and start the Nomad systemd service:

bash
sudo systemctl enable --now nomad
nomad node status
nomad server members

Defining a Production Nomad Job Specification

Nomad uses human-readable HashiCorp Configuration Language (HCL). The following job specification defines a containerized web service with rolling upgrades and dynamic port assignments:

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

  group "web" {
    count = 2

    update {
      max_parallel     = 1
      min_healthy_time = "10s"
      healthy_deadline = "3m"
      auto_revert      = true
    }

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

    task "server" {
      driver = "docker"

      config {
        image = "myorg/api-server:v1.4"
        ports = ["http"]
      }

      resources {
        cpu    = 500
        memory = 256
      }

      service {
        name = "webapp-service"
        port = "http"
        check {
          type     = "http"
          path     = "/healthz"
          interval = "10s"
          timeout  = "2s"
        }
      }
    }
  }
}

The update block in this specification guarantees zero-downtime rolling upgrades. Nomad starts one replacement task instance, verifies that its HTTP health check remains continuously healthy for at least 10 seconds (min_healthy_time), and only then terminates the older instance. If the new version crashes or throws 500 errors within 3 minutes, Nomad automatically invokes auto_revert, rolling back to the previous stable release without manual intervention.

Running and Inspecting Nomad Jobs

Submit the job file to the scheduler and monitor its allocation status:

bash
# Validate the HCL job file syntax
nomad job validate webapp.nomad

# Run or update the job
nomad job run webapp.nomad

# Inspect allocation health and placement
nomad job status webapp
nomad alloc status $(nomad job allocs -json webapp | jq -r '.[0].ID')

In addition to Docker containers, Nomad can orchestrate raw system binaries using the exec or raw_exec task drivers. This enables you to schedule legacy monoliths, Go binaries, or Python scripts with CPU and memory cgroup boundaries directly on the host without containerizing them first.

Nomad delivers declarative container scheduling efficiency tailored for lean infrastructure budgets.

HashiCorp Nomad Orchestration Deep Dive
YouTube

You can spin up an Ubuntu 24.04 instance on Netbay in under 60 seconds with Intel Xeon Platinum compute and high-speed SSD storage in Lucknow — netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance