Files
monky-deployd/docs/OPERATIONS.md
T
mdella c966450d8e fix(install): fetch from scm.tikali.ai (public project) — Gitea name is split-horizon inside the estate
Inside the estate gitea.cbs.tikali.net resolves to jump1's RED EIP (10.10.0.175),
which has no HTTP ingress, so backend boxes could not download the install
artefacts from the Gitea mirror (cbs/iac#102). scm.tikali.ai is reachable from
those boxes and the project is now public, so the GitLab generic package
registry becomes the PRIMARY source:

- packaging/install.sh: default source = scm.tikali.ai generic package registry
  (projects/69/packages/generic/monky-deployd/<ver>/...); `--source gitea` /
  MONKY_DEPLOYD_SOURCE=gitea keeps the Gitea release as the off-estate
  alternative; --base-url / MONKY_DEPLOYD_BASE_URL still override the base.
- ansible role defaults: monky_deployd_base_url/_deb_url point at the registry,
  Gitea layout kept as a commented alternative.
- README / docs/OPERATIONS.md / CLAUDE.md / CI comments + release description:
  both locations keep being published (release + release:gitea).
- Version 0.1.1 (the tag gate refuses v* tags whose version != __version__);
  tests compare against __version__ instead of a literal. No agent change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KLB7jieMNRkTsJ2epr4Ds1
2026-09-05 17:57:27 +00:00

7.5 KiB

Operating monky-deployd

Units

unit what
monky-deployd.timer fires monky-deployd.service 60 s after the previous tick finished (+ ≤10 s jitter); OnBootSec=90s
monky-deployd.service Type=oneshot, monky-deployd run --once as user monky-deployd (+ docker group); SuccessExitStatus=75; hardened (NoNewPrivileges, ProtectSystem=strict, ReadWritePaths=/var/lib/monky-deployd /etc/monky-deployd /run/docker.sock, UMask=0077, no capabilities)
monky-deployd-proxy.service only with transport: proxy: ziti tunnel proxy -i <identity> monky.tenancy.deploy:18443 openbao:18200 as user ziti; EnvironmentFile=/etc/monky-deployd/proxy.env
ziti-edge-tunnel.service the host identity's tunneler in run-host mode (drop-in run-host.conf written by install.sh)
systemctl status monky-deployd.timer monky-deployd.service
systemctl list-timers monky-deployd.timer
systemctl start monky-deployd.service          # tick now (blocks until done)
journalctl -u monky-deployd -f                 # priorities are real (INFO/WARNING/ERROR)
monky-deployd status                           # exit 0 = token present and in sync
monky-deployd status --json | jq .

Files: /etc/monky-deployd/config.yaml (0640 root:monky-deployd), /etc/monky-deployd/openbao-ca.pem, /etc/monky-deployd/bootstrap.jwt (only until the first login), /var/lib/monky-deployd/{bao.token,state.json,lock}, /var/lib/monky-deployd/<env>/releases/<sha>/ + current (the compose project dir, .env 0600), /opt/openziti/etc/identities/monky-host.<env>.json (ziti:ziti 0600 + ACL u:monky-deployd:r).

Reading the journal

line meaning
checkin: action=none desired=… applied=… then healthy; heartbeat reported converged
checkin: action=apply …read 3 secret(s): GEMINI_API_KEY, …promoted release …applied … a deploy
refused: ENV_INCOMPLETE: unresolved: X the bundle needs a variable no manifest entry supplies — fix the descriptor / set the secret in the console; nothing was started
refused: DISK_INSUFFICIENT: docker data-root has N MiB free, bundle needs M MiB free space (the env-dev-09 lesson): grow the data-root disk or prune
refused: PRIVILEGED_REFUSED / ROLLBACK_REFUSED the bundle needs allow_privileged / allow_rollback in its agent profile
temporary network failure (exit 75) mesh/tenancy unreachable — check ziti-edge-tunnel, the identity's terminators, monky.tenancy.deploy health
AGENT_UNAUTHENTICATED: bearer refused (exit 1) the grant was superseded (kit re-revealed / retire) or the token revoked → re-run the install kit
AGENT_ENV_MISMATCH (exit 78) the token belongs to another env than config.yaml — fix the config or re-issue the identity; the timer keeps firing but every tick exits 78 immediately (no storm)
failed: docker compose pull failed (rc=1) registry/pull problem; compose output is in the report's tail and in the journal

Values never appear in the journal ([REDACTED] for token shapes and every value the agent has read).

Secrets on the box

The only credential is /var/lib/monky-deployd/bao.token (0600, user monky-deployd). .env files under releases/<sha>/ hold the rendered values (0600, same user, docker compose reads them). Rotating a secret in the console changes the bundle sha → the next tick re-reads and re-applies. To force a re-read now: systemctl start monky-deployd.service.

Lost or revoked token: monky-deployd status shows token ABSENT; reveal the kit again (admin, GET /v1/backends/{id}/agent/install), paste its bootstrap grant to /etc/monky-deployd/bootstrap.jwt (0600 monky-deployd) or re-run install.sh (enrolment is skipped when the identity exists), then monky-deployd bootstrap or wait a tick.

Retire and volumes policy

Retire is driven by tenancy (POST /v1/backends/{id}/retire {confirm, force, purge_volumes}): the next check-in returns action: down and the agent runs docker compose down --remove-orphans. Data volumes:

  • -v (remove volumes) only when tenancy sent purge_volumes: true or the box's volumes_on_absent: purge — and never on a prod env (the request is logged and ignored).
  • default volumes_on_absent: keep: volumes stay for a manual docker volume rm later.

After down the agent reports down, clears applied_sha, removes current and keeps releases/ (no secrets outside .env, which you can shred). Tenancy then destroys the Bao paths, revokes the token accessor and deletes the host identity → the following ticks fail with AGENT_UNAUTHENTICATED; systemctl disable --now monky-deployd.timer and apt remove monky-deployd (apt purge also removes /var/lib/monky-deployd and /etc/monky-deployd).

Laptop mode

laptop_mode: true (install.sh --laptop): being offline is normal — a tick that cannot reach the mesh logs one INFO line and exits 0. Run without the system timer:

monky-deployd run             # loop, interval_s + jitter, SIGTERM stops; or a user timer with `run --once`

Liveness grace for laptops is 24 h on the tenancy side (P0); offline only hides the backend from the picker, nothing is retired automatically.

Housekeeping

monky-deployd run --once --prune removes every releases/<sha> except current and runs docker image prune -f after a successful apply. The state dir and the token survive apt remove; apt purge deletes them.

Where the installer downloads from

The primary source is the scm.tikali.ai generic package registry of this (public) project: https://scm.tikali.ai/api/v4/projects/69/packages/generic/monky-deployd/<ver>/<file> for monky-deployd_<ver>_amd64.deb, .sha256 and install.sh; the one-liner fetches the script from https://scm.tikali.ai/tikali/applications/monky/monky-deployd/-/raw/main/packaging/install.sh. Inside the estate gitea.cbs.tikali.net is split-horizon to jump1's RED EIP (10.10.0.175), which has no HTTP ingress, so backend boxes cannot fetch from the Gitea mirror (cbs/iac#102). Off-estate, install.sh --source gitea (ansible: monky_deployd_base_url/_deb_url) uses the Gitea release instead. The tag pipeline publishes to both (release, release:gitea).

Publishing a release to Gitea by hand

When release:gitea is manual (no GITEA_TOKEN in CI) — from jump1 with the Gitea API token:

T=$(tr -d '\n' < ~/.gitlab_tokens/gitea-token); G=http://172.16.8.1:3000/api/v1/repos/mdella/monky-deployd
curl -s -X POST -H "Authorization: token $T" $G/mirror-sync                      # pull the tag
RID=$(curl -s -X POST -H "Authorization: token $T" -H 'Content-Type: application/json' $G/releases \
      -d '{"tag_name":"v0.1.0","name":"monky-deployd v0.1.0","body":"See CHANGELOG.md"}' | jq -r .id)
for f in monky-deployd_0.1.0_amd64.deb monky-deployd_0.1.0_amd64.deb.sha256 install.sh; do
  curl -s -X POST -H "Authorization: token $T" -F "attachment=@$f" "$G/releases/$RID/assets?name=$f"; done

The assets are then at https://gitea.cbs.tikali.net/mdella/monky-deployd/releases/download/v0.1.0/<file>, which is what install.sh --source gitea fetches (GitLab artifacts from the tag pipeline's package job).

Ansible (osg1-07)

ansible/roles/monky_deployd/ is the role skeleton to copy into osg1-07: .deb from the scm.tikali.ai package registry (sha256-verified), config template, bootstrap grant from a vault var, ACL on the identity, timer, one tick. Rolled to env-dev-06..09 after the env-qa-02 pilot; env-dev-01 last.