Files
deploy/conjurer/DEPLOY-BOT.md
gitea 597cbd40f8 conjurer: deploy bot on its own [deploy]-gated image channel
The production bot now tracks conjurer-bot-deploy instead of conjurer-bot,
so it updates only when the conjurer CI promotes a build (commit message
contains [deploy]). Adds the image-updater 'deploy-bot' alias and the
kustomization images entry for it; DEPLOY-BOT.md documents the channel and
the one-time bootstrap. Test bot + librarian keep tracking every build.

Pairs with conjurer#20 (the CI promotion step).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 21:11:36 +02:00

4.5 KiB

Production ("deploy") Conjurer bot

A second Conjurer bot that runs alongside the test bot in the conjurer namespace, sharing the same librarian / musician / radio and the shared CONJURER_API_KEY. It differs from the test bot only in:

  • its Discord token: the deploy-conjurer-netrc secret (already created),
  • distinct names/labels (deploy-bot) and NodePort 32443,
  • /data on NFS (RWX) instead of a block PVC — so you can seed/upload files while it runs and back it up concurrently.

Files: deploy-bot.yaml (Deployment + Service), deploy-bot-backup.yaml (daily backup CronJob). Both are wired into kustomization.yaml.

Update channel — only on [deploy]

Unlike the test bot (which tracks every build), the production bot updates only when you promote a version. It runs a separate image, conjurer-bot-deploy, which the conjurer CI tags only when the commit message contains [deploy] (it re-tags the already-built conjurer-bot:<sha> — same bytes). The image-updater's deploy-bot alias then bumps this bot's tag.

So: normal commits update the test bot + librarian; a commit with [deploy] in its message is the one that also rolls the production bot.

Already bootstrapped: the channel was seeded by the first [deploy] commit (the merge of conjurer#20), which promoted conjurer-bot-deploy:fbd1ec9f — the tag pinned in kustomization.yaml. From here the image-updater keeps it current on each future [deploy] commit. Note the librarian is shared and still tracks latest, so mind large bot⇄librarian version skews.

If you ever need to seed a tag by hand:

docker pull gitea.czernobog.pl/gitea/conjurer-bot:<sha>
docker tag  gitea.czernobog.pl/gitea/conjurer-bot:<sha> \
            gitea.czernobog.pl/gitea/conjurer-bot-deploy:<sha>
docker push gitea.czernobog.pl/gitea/conjurer-bot-deploy:<sha>

One-time setup

  1. Secret — already exists as deploy-conjurer-netrc (a netrc carrying the deploy Discord token, key .netrc). Nothing to do; the Deployment mounts it at /secrets/.netrc.

  2. NFS export — create the data + backup dirs on the NFS server (192.168.1.34, adjust to your real export):

    /mnt/Tank1/conjurer_swap/deploy-bot/data
    /mnt/Tank1/conjurer_swap/deploy-bot/backups
    

Seeding / uploading config & state into /data

Because /data is a plain NFS export, you upload files by copying them onto the share — no kubectl cp, no scaling the bot down. From the PVE box that holds /srv/data (mount the same export there, or rsync over it):

# on a host that can see the NFS export:
rsync -a /srv/data/ 192.168.1.34:/mnt/Tank1/conjurer_swap/deploy-bot/data/

The bot roots everything under CONJURER_DATA_DIR=/data, so these land where it expects them:

accident_log.json  Conjurer_graphics/  music/  pamiec.json
pamiec_muzyki.json  settings.json  system_gpt_settings.json  transcripts/

Upload as much or as little as you like — the bot seeds any missing JSON on first run. Live-editing pamiec.json while the bot writes to it can race; prefer seeding before first start or during a brief kubectl -n conjurer scale deploy/deploy-bot --replicas=0 window.

Backups (production only)

deploy-bot-backup runs daily (04:17) and writes to the backups export:

  • current/ — a full rsync mirror of /data (incl. music/graphics), always the latest state,
  • snapshots/deploy-state-<date>.tgz — dated archives of the critical small state (both memories, settings, accident log, transcripts), kept RETENTION_DAYS (30) days.

The test bot is deliberately not backed up (amnesia there is fine).

Restore example:

tar xzf snapshots/deploy-state-2026-08-03-0417.tgz -C /mnt/.../deploy-bot/data/

Routing librarian / musician callbacks

Librarian — handled automatically. Each bot advertises its own CONJURER_SELF_CALLBACK (test …:32442, this bot …:32443) on every query and ping, and the librarian answers each result/pong back to the bot that asked. One librarian serves both bots — no CONJURER_MAIN_BOT repointing needed. (The librarian keeps CONJURER_MAIN_BOT: http://bot:5000 only as a fallback for a bot that doesn't send a callback.)

Musician — still single-target. The musician pushes "now playing" events to its one CONJURER_MAIN_BOT (currently the test bot, 192.168.1.73:32442). Only one bot gets radio events; repoint the musician's CONJURER_MAIN_BOT to 192.168.1.73:32443 if the production bot should show them instead.