---
okf: "0.1"
type: runbook
visibility: private
status: active
updated: 2026-08-03
links:
  - ../services/job-deploy-runner.md
  - ../decisions/deploy-runner-uzasadnienie.md
---

# deploy-runner — instalacja i obsluga

## Install (per node)

Not deployed by `deploy.sh` — it is a host-level systemd unit, like
`jobs/documents-ingest/`. On the target node:

```bash
# 1. config
sudo mkdir -p /opt/homelab/config/deploy-runner
sudo cp ~/homelab-codex-ws/jobs/deploy-runner/env.example \
        /opt/homelab/config/deploy-runner/env
sudo chown oskar:oskar /opt/homelab/config/deploy-runner/env
sudoedit /opt/homelab/config/deploy-runner/env      # set NODE_NAME; clear VPS_EVENTS_HOST on the VPS

# 2. units
sudo cp ~/homelab-codex-ws/jobs/deploy-runner/systemd/homelab-deploy-runner.{service,timer} \
        /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now homelab-deploy-runner.timer

# 3. verify (no action queued yet → one clean, empty run)
sudo systemctl start homelab-deploy-runner.service
journalctl -u homelab-deploy-runner.service -n 30 --no-pager
```

Requirements on the node: repo checkout at `REPO_PATH`, the service user in the
`docker` group, `python3` + PyYAML, `rsync`, and (remote nodes only) an ssh key
that reaches the VPS — the same one node-agent already uses for event shipping.

On the **VPS** leave `VPS_EVENTS_HOST` empty: the executor writes into the same
`/opt/homelab` mount, so there is nothing to pull and nothing to push.

## Operating it

- Dispatched but not yet collected: `ls /opt/homelab/actions/deploy/<node>/` on the VPS.
- Per-action deploy output: `/opt/homelab/logs/deploy-runner/<action_id>-<ts>.log` on the node.
- Runner activity: `journalctl -u homelab-deploy-runner.service`.
- A redeploy for a service with its own `deploy-local.sh` (control-plane) is
  reported as **failed** with an explanatory message — those need an operator
  deploy, by design.
- To let an already-processed action run again, remove its marker:
  `rm /opt/homelab/state/processed-deploy-actions/<action_id>.done`.

## Tests

`tests/` — validation and rejection cases, the event format contract against the
executor's real parser, the `docker compose` argv contract of
`scripts/deploy/deploy-service.sh`, and an end-to-end run of the runner itself
with a stubbed `docker`.

```bash
python3 -m pytest jobs/deploy-runner/tests -q
```
