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>
4.4 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-netrcsecret (already created), - distinct names/labels (
deploy-bot) and NodePort 32443, /dataon 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.
Bootstrap (first run): conjurer-bot-deploy doesn't exist until the first
[deploy] build. Either land one commit with [deploy] in the message, or seed
it once by hand:
docker pull gitea.czernobog.pl/gitea/conjurer-bot:ac16b77f
docker tag gitea.czernobog.pl/gitea/conjurer-bot:ac16b77f \
gitea.czernobog.pl/gitea/conjurer-bot-deploy:ac16b77f
docker push gitea.czernobog.pl/gitea/conjurer-bot-deploy:ac16b77f
(match the tag in kustomization.yaml). Note the librarian is shared, so it
still tracks latest — mind large bot⇄librarian version skews.
One-time setup
-
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. -
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), keptRETENTION_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.