From ce4dbe06ab2446f91be39a7fc4f18795e21c3227 Mon Sep 17 00:00:00 2001 From: Peter Gonda Date: Wed, 2 Sep 2026 11:09:52 +0200 Subject: [PATCH] fix: make Nomad service deploys actually schedule and pull images Found by deploying a service through the UI on the live server. Two blockers: 1. nomad CLI missing in the app image. The deploy pipeline runs 'nomad job run' to submit to the control plane's own Nomad, but the container had no nomad binary -> '/bin/sh: nomad: not found', so nothing was scheduled (and the deploy falsely reported success). Install the Nomad CLI in the Dockerfile. 2. Docker driver couldn't pull ANY image. The Nomad docker plugin sets auth.config = /root/.docker/config.json, but that file didn't exist, so the driver failed every pull ('Failed to open auth config file'), even public nginx. install.sh and the bootstrap now create an empty {"auths":{}} config before Nomad starts (docker login fills it for private registries later). Verified live: after these, a compose (nginx) deployed via the UI schedules on Nomad, the container runs, and curl returns HTTP 200. Co-Authored-By: Claude Opus 4.8 --- Dockerfile | 9 +++++++++ install.sh | 7 +++++++ packages/server/src/setup/nomad-bootstrap.ts | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/Dockerfile b/Dockerfile index a91ae8f2a..a6f76d4d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,6 +33,15 @@ ENV NODE_ENV=production RUN apt-get update && apt-get install -y curl unzip zip apache2-utils iproute2 rsync git-lfs && git lfs install && rm -rf /var/lib/apt/lists/* +# Nomad CLI — the deploy pipeline runs `nomad job run` to submit jobs to the +# control plane's own Nomad. (Remote-server deploys use that server's own CLI.) +ARG TARGETARCH +ARG NOMAD_VERSION=2.0.5 +RUN curl -fsSL "https://releases.hashicorp.com/nomad/${NOMAD_VERSION}/nomad_${NOMAD_VERSION}_linux_${TARGETARCH}.zip" -o /tmp/nomad.zip \ + && unzip -o /tmp/nomad.zip -d /usr/local/bin/ \ + && rm /tmp/nomad.zip \ + && nomad --version + # Copy only the necessary files COPY --from=build /prod/nomploy/.next ./.next COPY --from=build /prod/nomploy/dist ./dist diff --git a/install.sh b/install.sh index f08e7778f..8e7606000 100755 --- a/install.sh +++ b/install.sh @@ -140,6 +140,13 @@ plugin "docker" { } NOMADHCL +# The Nomad docker plugin above sets auth.config = /root/.docker/config.json. +# If that file is missing, the docker driver fails to pull EVERY image (even +# public ones). Create an empty auth config so public pulls work; `docker login` +# later fills it in for private registries. Must exist before Nomad starts. +$SUDO mkdir -p /root/.docker +[ -s /root/.docker/config.json ] || echo '{"auths":{}}' | $SUDO tee /root/.docker/config.json >/dev/null + # Start via --no-block and poll the HTTP APIs for readiness. The packaged units # are Type=notify; if the agent doesn't signal systemd, a blocking `restart` # would hang and (under set -e) abort the install even though the agent is up. diff --git a/packages/server/src/setup/nomad-bootstrap.ts b/packages/server/src/setup/nomad-bootstrap.ts index 3f064febf..876c177c8 100644 --- a/packages/server/src/setup/nomad-bootstrap.ts +++ b/packages/server/src/setup/nomad-bootstrap.ts @@ -167,6 +167,12 @@ plugin "docker" { } NOMADHCL +# The docker plugin's auth.config points at /root/.docker/config.json; if it's +# missing the driver fails to pull ANY image (even public). Create an empty auth +# config (docker login later fills it for private registries). Before start. +$SUDO mkdir -p /root/.docker +[ -s /root/.docker/config.json ] || echo '{"auths":{}}' | $SUDO tee /root/.docker/config.json >/dev/null + # ── Enable + start services ─────────────────────────────────────────────── echo "==> Starting Consul and Nomad" $SUDO systemctl enable consul nomad