Docs navigation
Get started
AI agents
Connect
Operate
Day to day
When it breaks
Govern access
Team & account
Access
Identity concepts
Provider guides
Account
Nomad system job
A Nomad system
job places one runner on every client node. This example uses the release archive and a
persistent host volume.
To read what a containerized runner can reach, see Install in a container.
-
The
nomadCLI pointed at your cluster, with permission to submit system jobs and write Nomad Variables. - amd64 Linux client nodes. The example pins the linux-amd64 archive; for arm64 clients change the architecture in the artifact source and the binary path.
-
Outbound HTTPS from every client node to
emisar.dev:443andregistry.emisar.dev:443. See Network requirements for the optional GitHub fallback domains.
Prepare the deployment#
The raw_exec
driver has no filesystem or process isolation, so the runner has the same access as the
Nomad client process. Enable the driver only on nodes that need host actions.
Complete these steps before you submit the job:
-
Enable
raw_execon every client that should run a runner. -
Register a host volume named
emisar-stateat/var/lib/emisaron each client. - Create a reusable enrollment key.
-
Store the key as
enrollment_keyin the Nomad Variablenomad/jobs/emisar-runner. -
Open the
runner release manifest
and copy the version and the linux-amd64 archive's
sha256.
The system job#
The artifact stanza checks the archive digest before extraction. One template writes the runner config, the other reads the enrollment key from Nomad Variables, and the host volume keeps the runner token and durable dispatch state.
variable "runner_version" { type = string } variable "archive_sha256" { type = string } job "emisar-runner" { type = "system" group "runner" { volume "state" { type = "host" source = "emisar-state" # a host volume registered on each Nomad client } task "runner" { driver = "raw_exec" artifact { source = "https://emisar.dev/releases/runner/runner-v${var.runner_version}/emisar-${var.runner_version}-linux-amd64.tar.gz" options { checksum = "sha256:${var.archive_sha256}" } } template { destination = "local/config.yaml" perms = "0600" data = <<-EOH schema_version: 1 runner: group: nomad cloud: url: https://emisar.dev enrollment_key_env: EMISAR_ENROLLMENT_KEY paths: data_dir: /var/lib/emisar packs: - emisar-${var.runner_version}-linux-amd64/packs events: jsonl_path: /var/lib/emisar/events.jsonl EOH } template { destination = "secrets/emisar.env" env = true data = <<-EOH EMISAR_ENROLLMENT_KEY={{ with nomadVar "nomad/jobs/emisar-runner" }}{{ .enrollment_key | toJSON }}{{ end }} EOH } config { command = "local/emisar-${var.runner_version}-linux-amd64/emisar" args = ["connect", "--config", "local/config.yaml"] } volume_mount { volume = "state" destination = "/var/lib/emisar" } resources { cpu = 100 memory = 128 } } } }
Deploy and verify#
Set the release version and its digest, then validate, plan, and run:
export EMISAR_VERSION=<version> export EMISAR_ARCHIVE_SHA256=<64-character-sha256> nomad job validate \ -var "runner_version=$EMISAR_VERSION" \ -var "archive_sha256=$EMISAR_ARCHIVE_SHA256" \ emisar-runner.nomad.hcl nomad job plan \ -var "runner_version=$EMISAR_VERSION" \ -var "archive_sha256=$EMISAR_ARCHIVE_SHA256" \ emisar-runner.nomad.hcl nomad job run \ -var "runner_version=$EMISAR_VERSION" \ -var "archive_sha256=$EMISAR_ARCHIVE_SHA256" \ emisar-runner.nomad.hcl
-
Run
nomad job status emisar-runner. Confirm every client has one running allocation. - Open Runners. Confirm each client's runner is online.
- Run
linux.uptimeon one client runner. - Open Audit. Confirm that the event records the runner, action, operator, and reason.
Driver and visibility#
The driver decides what the runner can reach. This is the same
namespace question
as any container deployment. raw_exec
runs the binary straight on the client. Use the docker
driver instead when the runner only needs mounted files and services.
Keys and pack credentials#
Use a reusable enrollment key — with a single-use key the first node spends it, and every other node fails to enroll.
Give packs their credentials through environment variables on the runner's
inherit_env
allowlist, never through action arguments. A Nomad template can read the values from
Nomad Variables or Vault. The allowlist is covered in Giving packs their credentials.
After it is connected#
Manage the runner fleet covers work after the first connection — groups, labels, pack credentials, updates, reconnects, and removal. To roll the system job across datacenters in phases, see the Go to production.