Compare commits

..

74 Commits

Author SHA1 Message Date
gitea abc0f98034 sec(astrololo): pody bez tokenu konta serwisowego (LOG-33)
Wszystkie cztery usługi biegły na koncie `default` z AUTOMATYCZNIE montowanym
tokenem API Kubernetesa. Żadna z nich nie rozmawia z API klastra — sekrety dostają
przez `secretKeyRef`, który wstrzykuje kubelet, nie pod. Token był więc zbędny,
a leżał w każdym kontenerze jako gotowy punkt wyjścia do klastra dla kogoś, kto
przejmie proces (np. przez lukę w zależności).

`automountServiceAccountToken: false` w szablonie poda data/logic/presentation/
render. Zweryfikowane `kubectl kustomize` — pole trafia do `.spec.template.spec`,
nie do specu Deploymentu (tam byłoby ciche i bez efektu).

Zero wpływu na działanie: nic w kodzie nie woła API Kubernetesa.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 17:08:39 +02:00
argocd-image-updater 71b9fe0842 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag '9f22dbf9' to 'ae1bd677'
2026-08-04 13:18:01 +00:00
argocd-image-updater 261b41240d build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'fbd1ec9f' to '9f22dbf9'
2026-08-04 11:43:36 +00:00
argocd-image-updater de4d41808a build: automatic update of astrololo
updates image gitea/astrololo-data tag '4c1e7f88' to '70c83cfc'
updates image gitea/astrololo-logic tag '4c1e7f88' to '70c83cfc'
updates image gitea/astrololo-presentation tag '4c1e7f88' to '70c83cfc'
2026-08-04 10:59:11 +00:00
argocd-image-updater b9289c4f8c build: automatic update of astrololo
updates image gitea/astrololo-data tag 'dd32f7e8' to '4c1e7f88'
updates image gitea/astrololo-logic tag 'dd32f7e8' to '4c1e7f88'
updates image gitea/astrololo-presentation tag 'd3d9b365' to '4c1e7f88'
2026-08-04 10:29:00 +00:00
argocd-image-updater 536b2bbbbb build: automatic update of astrololo
updates image gitea/astrololo-presentation tag 'dd32f7e8' to 'd3d9b365'
2026-08-03 23:04:28 +00:00
argocd-image-updater e2af5e331e build: automatic update of astrololo
updates image gitea/astrololo-data tag '78af6d47' to 'dd32f7e8'
updates image gitea/astrololo-logic tag '7b435d42' to 'dd32f7e8'
updates image gitea/astrololo-presentation tag '7b435d42' to 'dd32f7e8'
2026-08-03 22:34:20 +00:00
argocd-image-updater 1a02704422 build: automatic update of astrololo
updates image gitea/astrololo-data tag 'b36b3bee' to '78af6d47'
2026-08-03 20:33:52 +00:00
argocd-image-updater 91890b701e build: automatic update of astrololo
updates image gitea/astrololo-logic tag 'b36b3bee' to '7b435d42'
updates image gitea/astrololo-presentation tag 'a9f2a038' to '7b435d42'
2026-08-03 19:38:53 +00:00
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
argocd-image-updater 6983814a5c build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'f4dea535' to 'fbd1ec9f'
updates image gitea/conjurer-bot tag 'f4dea535' to 'fbd1ec9f'
2026-08-03 18:46:40 +00:00
argocd-image-updater cc3c2b512d build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'd4c6d78c' to 'f4dea535'
updates image gitea/conjurer-bot tag 'd4c6d78c' to 'f4dea535'
2026-08-03 18:38:32 +00:00
argocd-image-updater 4d8ca6f4fd build: automatic update of conjurer
updates image gitea/conjurer-bot tag 'ac16b77f' to 'd4c6d78c'
2026-08-03 17:50:23 +00:00
argocd-image-updater 311d5ae071 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'ac16b77f' to 'd4c6d78c'
2026-08-03 17:48:20 +00:00
gitea 5b6040c60d conjurer: add CONJURER_SELF_CALLBACK to both bots (per-origin librarian answers)
Pairs with conjurer#18: each bot advertises its own callback so the shared
librarian answers results/pongs back to the bot that asked - test bot
http://192.168.1.73:32442, deploy bot :32443. No CONJURER_MAIN_BOT
repointing needed for the librarian anymore; DEPLOY-BOT.md updated (only
the musician stays single-target).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 17:47:32 +00:00
gitea 358356a1b1 conjurer: add production ('deploy') bot + data seeding/backup
A second Conjurer bot alongside the test one, sharing librarian/musician/
radio and the API key, differing only in:
 * Discord token from the deploy-conjurer-netrc secret,
 * distinct names/labels (deploy-bot) and NodePort 32443,
 * /data on an NFS export (RWX) instead of a block PVC - so config/state
   can be uploaded while it runs (copy onto the share) and backed up
   concurrently.

deploy-bot-backup: a daily CronJob that mirrors /data and keeps 30 days of
dated snapshots of the critical small state (both memories, settings,
accident log, transcripts) on NFS. Production only - the test bot's
amnesia is fine. DEPLOY-BOT.md documents seeding, backup/restore, and the
librarian/musician callback routing (they push to one bot; repoint
CONJURER_MAIN_BOT to :32443 to feed this one).

kubectl kustomize builds cleanly (10 objects).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 17:47:32 +00:00
argocd-image-updater 71133be104 build: automatic update of astrololo
updates image gitea/astrololo-presentation tag 'b36b3bee' to 'a9f2a038'
2026-08-03 16:52:05 +00:00
argocd-image-updater 05107b57de build: automatic update of astrololo
updates image gitea/astrololo-data tag 'a0d1135d' to 'b36b3bee'
updates image gitea/astrololo-logic tag 'a0d1135d' to 'b36b3bee'
updates image gitea/astrololo-presentation tag 'a0d1135d' to 'b36b3bee'
2026-08-03 15:47:48 +00:00
argocd-image-updater 630ce61be3 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'c5643aa2' to 'ac16b77f'
updates image gitea/conjurer-bot tag 'c5643aa2' to 'ac16b77f'
2026-08-03 15:45:49 +00:00
argocd-image-updater a268cd392c build: automatic update of astrololo
updates image gitea/astrololo-data tag 'a0d1135d' to 'b36b3bee'
updates image gitea/astrololo-logic tag 'a0d1135d' to 'b36b3bee'
2026-08-03 15:45:46 +00:00
argocd-image-updater 056ebce791 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag '40605b95' to 'c5643aa2'
updates image gitea/conjurer-bot tag '8e18071b' to 'c5643aa2'
2026-08-03 15:43:47 +00:00
gitea a7cab0acd7 conjurer: give librarian 60s termination grace for checkpointing
The librarian now checkpoints an in-progress search on SIGTERM and exits
within CONJURER_LIBRARIAN_GRACEFUL_TIMEOUT (default 45s). Raise k8s
terminationGracePeriodSeconds to 60 so that graceful checkpoint isn't cut
short by SIGKILL - otherwise the long DB scan restarts instead of resuming.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 15:42:10 +00:00
argocd-image-updater 87048cdbc4 build: automatic update of astrololo
updates image gitea/astrololo-data tag '8ebce816' to 'a0d1135d'
updates image gitea/astrololo-logic tag '8ebce816' to 'a0d1135d'
updates image gitea/astrololo-presentation tag '8ebce816' to 'a0d1135d'
2026-08-03 11:06:43 +00:00
argocd-image-updater 7a33250d98 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag '8e18071b' to '40605b95'
2026-08-02 17:39:36 +00:00
gitea d94ad4a0dc conjurer: bump librarian memory limit 1Gi -> 2Gi (headroom)
The work-queue OOM is fixed in code (bounded queue), but a deep search
still loads up to 15000 Crossref records and the accumulating result
JSONs into RAM. Give 2Gi of headroom so a big search isn't OOM-killed;
raise the request to 512Mi to match its real baseline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 19:36:14 +02:00
argocd-image-updater 791e745865 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag '44b7298a' to '8e18071b'
updates image gitea/conjurer-bot tag '44b7298a' to '8e18071b'
2026-08-02 17:05:31 +00:00
argocd-image-updater 9fa72af1bf build: automatic update of conjurer
updates image gitea/conjurer-librarian tag '44b7298a' to '8ac68df1'
updates image gitea/conjurer-bot tag '44b7298a' to '8ac68df1'
2026-08-02 17:03:28 +00:00
argocd-image-updater abbba17dd0 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag '5d321f2f' to '44b7298a'
updates image gitea/conjurer-bot tag '5d321f2f' to '44b7298a'
2026-08-02 15:33:09 +00:00
gitea b7f226062c conjurer: napraw drogę powrotną librarian/musician -> bot
Wyniki wyszukań (librarian) i eventy 'now playing' (musician) POST-owane do
bota ginęły, bo droga powrotna do bota była krucha:

* Service 'bot' był NodePort BEZ przypiętego nodePort -> k8s losował port z
  30000-32767 przy każdym (od)tworzeniu Service, a musician/betoniarka z
  Dockera adresują bota na sztywno http://192.168.1.73:32442. Rozjazd = każdy
  POST leci w zamknięty port. Przypinam nodePort: 32442.
* Librarian jest w tym samym klastrze co bot, a mimo to szedł przez nodePort
  węzła. Przełączam na DNS Service'u http://bot:5000 - odporne na
  przetasowania nodePortu (nodePort zostaje tylko dla zewnętrznych z Dockera).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-02 17:04:57 +02:00
gitea d84b982e0f fx 2026-08-01 20:44:00 +02:00
argocd-image-updater 83f928c278 build: automatic update of conjurer
updates image gitea/conjurer-bot tag 'defc482a' to '5d321f2f'
2026-08-01 17:16:14 +00:00
argocd-image-updater a0330b0b77 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'defc482a' to '5d321f2f'
2026-08-01 17:14:12 +00:00
gitea e33d59b70c fx 2026-08-01 14:33:17 +02:00
argocd-image-updater 5d1be5398b build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'latest' to 'defc482a'
updates image gitea/conjurer-bot tag 'e1fca864' to 'defc482a'
2026-08-01 11:54:44 +00:00
gitea 70161cb7bd fx 2026-08-01 13:52:47 +02:00
argocd-image-updater 486e81a817 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'latest' to 'defc482a'
2026-08-01 11:52:39 +00:00
argocd-image-updater 3d521a20c8 build: automatic update of conjurer
updates image gitea/conjurer-bot tag '3f4a1d50' to 'e1fca864'
2026-07-31 20:32:28 +00:00
argocd-image-updater 92c1683363 build: automatic update of conjurer
updates image gitea/conjurer-bot tag 'latest' to '3f4a1d50'
2026-07-31 18:15:55 +00:00
argocd-image-updater 627a8b5d7f build: automatic update of conjurer
updates image gitea/conjurer-bot tag 'latest' to 'e9e731e2'
2026-07-31 18:11:52 +00:00
argocd-image-updater 6c0213911d build: automatic update of conjurer
updates image gitea/conjurer-librarian tag '031c1f8a' to 'latest'
2026-07-30 17:43:53 +00:00
argocd-image-updater 814673390f build: automatic update of astrololo
updates image gitea/astrololo-render tag '8ebce816' to 'latest'
2026-07-30 17:31:41 +00:00
argocd-image-updater cab8bda7f8 build: automatic update of conjurer
updates image gitea/conjurer-bot tag '031c1f8a' to 'latest'
2026-07-30 17:11:02 +00:00
gitea aa4f015212 fx 2026-07-30 17:39:22 +02:00
argocd-image-updater 8ec74d1af0 build: automatic update of conjurer
updates image gitea/conjurer-bot tag 'f177dee4' to '031c1f8a'
2026-07-30 15:34:35 +00:00
argocd-image-updater bdb8a0cb0d build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'f177dee4' to '031c1f8a'
2026-07-30 15:26:22 +00:00
argocd-image-updater 268ea8359f build: automatic update of astrololo
updates image gitea/astrololo-render tag 'latest' to '8ebce816'
2026-07-30 15:17:47 +00:00
argocd-image-updater a88148f7d3 build: automatic update of astrololo
updates image gitea/astrololo-data tag '52b7c20c' to '8ebce816'
updates image gitea/astrololo-logic tag '52b7c20c' to '8ebce816'
updates image gitea/astrololo-presentation tag '52b7c20c' to '8ebce816'
2026-07-30 15:11:39 +00:00
argocd-image-updater 7b61f2e309 build: automatic update of astrololo
updates image gitea/astrololo-logic tag '9b1e4dbb' to '52b7c20c'
updates image gitea/astrololo-presentation tag '9b1e4dbb' to '52b7c20c'
2026-07-30 15:03:35 +00:00
argocd-image-updater 48250c7015 build: automatic update of astrololo
updates image gitea/astrololo-data tag 'f5dec15e' to '52b7c20c'
2026-07-30 15:01:31 +00:00
argocd-image-updater 6524258e1c build: automatic update of astrololo
updates image gitea/astrololo-render tag '998c83b2' to 'latest'
2026-07-30 11:38:30 +00:00
argocd-image-updater 6844dd5b55 build: automatic update of astrololo
updates image gitea/astrololo-render tag 'f5dec15e' to '998c83b2'
2026-07-30 09:42:47 +00:00
argocd-image-updater 311f1b2ce1 build: automatic update of astrololo
updates image gitea/astrololo-logic tag 'f5dec15e' to '9b1e4dbb'
updates image gitea/astrololo-presentation tag '4bdfb673' to '9b1e4dbb'
2026-07-29 00:06:27 +00:00
argocd-image-updater 3bd5ba7a81 build: automatic update of astrololo
updates image gitea/astrololo-presentation tag 'f5dec15e' to '4bdfb673'
2026-07-28 23:36:09 +00:00
argocd-image-updater dda554d98c build: automatic update of astrololo
updates image gitea/astrololo-data tag '998c83b2' to 'f5dec15e'
updates image gitea/astrololo-logic tag '998c83b2' to 'f5dec15e'
updates image gitea/astrololo-presentation tag '495f3734' to 'f5dec15e'
updates image gitea/astrololo-render tag 'latest' to 'f5dec15e'
2026-07-28 19:50:13 +00:00
argocd-image-updater a60dd816e8 build: automatic update of astrololo
updates image gitea/astrololo-render tag 'latest' to 'f5dec15e'
2026-07-28 19:48:08 +00:00
argocd-image-updater 3aba21d062 build: automatic update of astrololo
updates image gitea/astrololo-presentation tag '998c83b2' to '495f3734'
2026-07-28 18:29:32 +00:00
argocd-image-updater 615293b916 build: automatic update of astrololo
updates image gitea/astrololo-data tag '623603b1' to '998c83b2'
updates image gitea/astrololo-logic tag '623603b1' to '998c83b2'
updates image gitea/astrololo-presentation tag '4b17f2dd' to '998c83b2'
2026-07-28 16:27:02 +00:00
argocd-image-updater a2bd1e0202 build: automatic update of astrololo
updates image gitea/astrololo-data tag '623603b1' to '998c83b2'
updates image gitea/astrololo-logic tag '623603b1' to '998c83b2'
2026-07-28 16:24:58 +00:00
argocd-image-updater 073ed904e9 build: automatic update of astrololo
updates image gitea/astrololo-data tag '623603b1' to '998c83b2'
updates image gitea/astrololo-render tag '56131b20' to 'latest'
2026-07-28 16:22:44 +00:00
argocd-image-updater 494b49b9ac build: automatic update of astrololo
updates image gitea/astrololo-render tag '56131b20' to 'latest'
2026-07-28 16:18:33 +00:00
argocd-image-updater 14e62adc94 build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'e243777e' to 'f177dee4'
updates image gitea/conjurer-bot tag 'e243777e' to 'f177dee4'
2026-07-28 13:51:02 +00:00
argocd-image-updater 3dccbeb27d build: automatic update of conjurer
updates image gitea/conjurer-librarian tag 'e243777e' to 'f177dee4'
2026-07-28 13:48:55 +00:00
gitea 00ce859105 2 2026-07-28 15:37:48 +02:00
gitea d4dda58492 1 2026-07-28 15:34:12 +02:00
gitea 182c579664 Fix updater 2026-07-28 14:21:00 +02:00
argocd-image-updater 2f4e8d1799 build: automatic update of conjurer
updates image gitea/conjurer-bot tag 'c8aae106' to 'e243777e'
2026-07-28 12:17:50 +00:00
gitea 65d1d0c4d8 imageupdater 2026-07-28 14:10:07 +02:00
gitea 8020eb6b05 bot 2026-07-28 13:56:46 +02:00
gitea 327028ce42 bot 2026-07-28 13:40:49 +02:00
gitea 4fa3700f9c Libr 2026-07-28 13:28:38 +02:00
gitea 31a97615a3 Libr 2026-07-28 13:25:04 +02:00
gitea 19ed73cd11 Libr 2026-07-28 11:22:00 +00:00
argocd-image-updater 303be20455 build: automatic update of astrololo
updates image gitea/astrololo-render tag 'latest' to '56131b20'
2026-07-26 19:32:42 +00:00
argocd-image-updater a092350b3b build: automatic update of astrololo
updates image gitea/astrololo-presentation tag '623603b1' to '4b17f2dd'
2026-07-25 23:58:48 +00:00
12 changed files with 392 additions and 8 deletions
+4
View File
@@ -9,6 +9,10 @@ spec:
template: template:
metadata: { labels: { app: data } } metadata: { labels: { app: data } }
spec: spec:
# LOG-33: pody nie rozmawiają z API Kubernetesa, więc token konta
# serwisowego jest im niepotrzebny — a zamontowany byłby gotowym
# punktem wyjścia do klastra dla kogoś, kto przejmie kontener.
automountServiceAccountToken: false
imagePullSecrets: [{ name: gitea-registry }] imagePullSecrets: [{ name: gitea-registry }]
containers: containers:
- name: data - name: data
+3 -3
View File
@@ -10,10 +10,10 @@ resources:
- ingress.yaml # wejście po https + przekierowanie z http - ingress.yaml # wejście po https + przekierowanie z http
images: images:
- name: gitea.czernobog.pl/gitea/astrololo-data - name: gitea.czernobog.pl/gitea/astrololo-data
newTag: 623603b1 newTag: 70c83cfc
- name: gitea.czernobog.pl/gitea/astrololo-logic - name: gitea.czernobog.pl/gitea/astrololo-logic
newTag: 623603b1 newTag: 70c83cfc
- name: gitea.czernobog.pl/gitea/astrololo-render - name: gitea.czernobog.pl/gitea/astrololo-render
newTag: latest newTag: latest
- name: gitea.czernobog.pl/gitea/astrololo-presentation - name: gitea.czernobog.pl/gitea/astrololo-presentation
newTag: 623603b1 newTag: 70c83cfc
+4
View File
@@ -9,6 +9,10 @@ spec:
template: template:
metadata: { labels: { app: logic } } metadata: { labels: { app: logic } }
spec: spec:
# LOG-33: pody nie rozmawiają z API Kubernetesa, więc token konta
# serwisowego jest im niepotrzebny — a zamontowany byłby gotowym
# punktem wyjścia do klastra dla kogoś, kto przejmie kontener.
automountServiceAccountToken: false
imagePullSecrets: [{ name: gitea-registry }] imagePullSecrets: [{ name: gitea-registry }]
containers: containers:
- name: logic - name: logic
+4
View File
@@ -9,6 +9,10 @@ spec:
template: template:
metadata: { labels: { app: presentation } } metadata: { labels: { app: presentation } }
spec: spec:
# LOG-33: pody nie rozmawiają z API Kubernetesa, więc token konta
# serwisowego jest im niepotrzebny — a zamontowany byłby gotowym
# punktem wyjścia do klastra dla kogoś, kto przejmie kontener.
automountServiceAccountToken: false
imagePullSecrets: [{ name: gitea-registry }] imagePullSecrets: [{ name: gitea-registry }]
containers: containers:
- name: presentation - name: presentation
+4
View File
@@ -19,6 +19,10 @@ spec:
template: template:
metadata: { labels: { app: render } } metadata: { labels: { app: render } }
spec: spec:
# LOG-33: pody nie rozmawiają z API Kubernetesa, więc token konta
# serwisowego jest im niepotrzebny — a zamontowany byłby gotowym
# punktem wyjścia do klastra dla kogoś, kto przejmie kontener.
automountServiceAccountToken: false
imagePullSecrets: [{ name: gitea-registry }] imagePullSecrets: [{ name: gitea-registry }]
containers: containers:
- name: render - name: render
+106
View File
@@ -0,0 +1,106 @@
# 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:
```bash
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):
```bash
# 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:
```bash
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.
+62
View File
@@ -0,0 +1,62 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: bot
namespace: conjurer
spec:
replicas: 1 # NIGDY więcej — jedna sesja gateway na token
strategy: { type: Recreate } # NIE RollingUpdate — dwa pody = wojna o sesję Discord
selector: { matchLabels: { app: bot } }
template:
metadata: { labels: { app: bot } }
spec:
imagePullSecrets: [{ name: gitea-registry }]
containers:
- name: bot
image: gitea.czernobog.pl/gitea/conjurer-bot:c8aae106
ports: [{ containerPort: 5000 }]
env:
- { name: CONJURER_DATA_DIR, value: "/data" }
- { name: CONJURER_DISCORD_HOST, value: "0.0.0.0" }
- { name: CONJURER_DISCORD_PORT, value: "5000" }
- { name: CONJURER_API_KEY, value: "d97008b3-7a5a-11f1-acd1-000b0e0f00ed" }
- { name: CONJURER_NETRC_FILE, value: "/secrets/.netrc" }
# ↓ NAZWY PODSTAW WG WYNIKU grepa z 0.2 ↓
- { name: CONJURER_LIBRARIAN_SERVICE, value: "http://librarian:5001" }
- { name: CONJURER_MUSICIAN_SERVICE, value: "http://192.168.1.89:5000" }
- { name: CONJURER_RADIO_SERVICE, value: "http://192.168.1.79:5005" }
- { name: CONJURER_FILE_SERVICE, value: "http://192.168.1.89:5000" }
- { name: CONJURER_RADIO_HARBOR, value: "http://192.168.1.79:54321" }
# Where the librarian sends THIS bot's results/pongs back to (its own
# NodePort). Lets one librarian serve both bots - see deploy-bot.yaml.
- { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32442" }
volumeMounts:
- { name: data, mountPath: /data }
- { name: netrc, mountPath: /secrets, readOnly: true }
resources:
requests: { cpu: "200m", memory: "256Mi" }
limits: { cpu: "2", memory: "1Gi" }
volumes:
- name: data
persistentVolumeClaim: { claimName: bot-data }
- name: netrc
secret: { secretName: conjurer-netrc }
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: bot-data, namespace: conjurer }
spec:
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 2Gi } }
---
apiVersion: v1
kind: Service
metadata: { name: bot, namespace: conjurer }
spec:
type: NodePort # radio/musician z Dockera muszą go dosięgnąć
selector: { app: bot }
# nodePort PRZYPIĘTY na sztywno. Bez tego k8s losuje port z 30000-32767 przy
# (od)tworzeniu Service, a musician/betoniarka z Dockera adresują bota po
# http://192.168.1.73:32442 na sztywno - rozjazd = wyniki/eventy giną w locie.
ports: [{ port: 5000, targetPort: 5000, nodePort: 32442 }]
+22
View File
@@ -0,0 +1,22 @@
apiVersion: argocd-image-updater.argoproj.io/v1alpha1
kind: ImageUpdater
metadata:
name: conjurer
namespace: argocd
spec:
commonUpdateSettings:
updateStrategy: "newest-build"
writeBackConfig:
method: "git:secret:argocd/git-creds"
gitConfig:
repository: "https://gitea.czernobog.pl/gitea/deploy.git"
branch: "master" # ← gałąź repo deploy
writeBackTarget: "kustomization:/conjurer"
applicationRefs:
- namePattern: "conjurer"
images:
- { alias: "librarian", imageName: "gitea.czernobog.pl/gitea/conjurer-librarian" }
- { alias: "bot", imageName: "gitea.czernobog.pl/gitea/conjurer-bot" }
# Production bot tracks its own image, which only gets new tags on
# [deploy] commits (conjurer CI) - so it updates only on promoted builds.
- { alias: "deploy-bot", imageName: "gitea.czernobog.pl/gitea/conjurer-bot-deploy" }
+65
View File
@@ -0,0 +1,65 @@
# Daily backup of the PRODUCTION ("deploy") bot's /data.
#
# Only production is backed up - the test bot's amnesia is fine, this bot's is
# not (pamiec.json / pamiec_muzyki.json are the conversation & music memory).
# Both volumes are NFS (RWX), so this runs while the bot is live - no RWO clash.
#
# Two-part backup:
# * a full, space-efficient MIRROR (rsync --delete) of everything, incl. music
# and graphics - always the current state,
# * dated SNAPSHOTS of just the small critical state (the memories, settings,
# accident log, transcripts) so you can roll back to a point in time.
# Snapshots older than RETENTION_DAYS are pruned.
apiVersion: batch/v1
kind: CronJob
metadata:
name: deploy-bot-backup
namespace: conjurer
spec:
schedule: "17 4 * * *" # every day at 04:17
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: alpine:3.20
command: ["/bin/sh", "-c"]
args:
- |
set -eu
apk add --no-cache rsync >/dev/null
STAMP="$(date +%F-%H%M)"
mkdir -p /backup/current /backup/snapshots
echo "[$STAMP] mirroring /data -> /backup/current"
rsync -a --delete /data/ /backup/current/
echo "[$STAMP] snapshotting critical state"
tar czf "/backup/snapshots/deploy-state-$STAMP.tgz" -C /data \
accident_log.json pamiec.json pamiec_muzyki.json \
settings.json system_gpt_settings.json transcripts \
2>/dev/null || echo " (some files absent - skipped)"
echo "[$STAMP] pruning snapshots older than ${RETENTION_DAYS}d"
find /backup/snapshots -name 'deploy-state-*.tgz' -type f \
-mtime +"${RETENTION_DAYS}" -delete
echo "[$STAMP] backup done"
env:
- { name: RETENTION_DAYS, value: "30" }
volumeMounts:
- { name: data, mountPath: /data, readOnly: true }
- { name: backup, mountPath: /backup }
volumes:
# Same export the bot mounts (read-only here).
- name: data
nfs:
server: 192.168.1.34
path: /mnt/Tank1/conjurer_swap/deploy-bot/data
# Backup target - ADJUST to your export.
- name: backup
nfs:
server: 192.168.1.34
path: /mnt/Tank1/conjurer_swap/deploy-bot/backups
+80
View File
@@ -0,0 +1,80 @@
# Production ("deploy") Conjurer bot.
#
# Same infrastructure as the test `bot` (shares librarian / musician / radio and
# the CONJURER_API_KEY), with three deliberate differences:
# 1. its Discord token comes from the `deploy-conjurer-netrc` secret,
# 2. distinct names/labels so it coexists with the test bot in this namespace,
# 3. /data is an NFS volume (RWX) instead of a block PVC - so config/state can
# be uploaded while the bot runs (just copy onto the share) and backed up
# concurrently (see deploy-bot-backup.yaml). The test bot keeps its RWO PVC.
#
# ┌─ IMPORTANT: librarian & musician call ONE bot back ─────────────────────────┐
# │ The librarian (CONJURER_MAIN_BOT) and musician push search results and │
# │ "now playing" events to a SINGLE bot address - currently the test bot's │
# │ NodePort 192.168.1.73:32442. Only one bot can receive them. To make the │
# │ PRODUCTION bot the one that gets librarian results / radio events, repoint │
# │ those services' CONJURER_MAIN_BOT to this bot's NodePort (…:32443 below). │
# └─────────────────────────────────────────────────────────────────────────────┘
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-bot
namespace: conjurer
spec:
replicas: 1 # NIGDY więcej — jedna sesja gateway na token
strategy: { type: Recreate } # NIE RollingUpdate — dwa pody = wojna o sesję Discord
selector: { matchLabels: { app: deploy-bot } }
template:
metadata: { labels: { app: deploy-bot } }
spec:
imagePullSecrets: [{ name: gitea-registry }]
containers:
- name: bot
# SEPARATE image from the test bot: conjurer-bot-deploy only gets a new
# tag when a commit message contains [deploy] (see the conjurer CI), so
# this bot updates only on versions you explicitly promote. Tag is
# managed by the image-updater (kustomization images:).
image: gitea.czernobog.pl/gitea/conjurer-bot-deploy:c8aae106
ports: [{ containerPort: 5000 }]
env:
- { name: CONJURER_DATA_DIR, value: "/data" }
- { name: CONJURER_DISCORD_HOST, value: "0.0.0.0" }
- { name: CONJURER_DISCORD_PORT, value: "5000" }
- { name: CONJURER_API_KEY, value: "d97008b3-7a5a-11f1-acd1-000b0e0f00ed" }
- { name: CONJURER_NETRC_FILE, value: "/secrets/.netrc" }
- { name: CONJURER_LIBRARIAN_SERVICE, value: "http://librarian:5001" }
- { name: CONJURER_MUSICIAN_SERVICE, value: "http://192.168.1.89:5000" }
- { name: CONJURER_RADIO_SERVICE, value: "http://192.168.1.79:5005" }
- { name: CONJURER_FILE_SERVICE, value: "http://192.168.1.89:5000" }
- { name: CONJURER_RADIO_HARBOR, value: "http://192.168.1.79:54321" }
# This bot's own callback (its NodePort). The librarian records it per
# query and answers results/pongs HERE - so it serves this bot AND the
# test bot from one instance, no CONJURER_MAIN_BOT repointing needed.
- { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32443" }
volumeMounts:
- { name: data, mountPath: /data }
- { name: netrc, mountPath: /secrets, readOnly: true }
resources:
requests: { cpu: "200m", memory: "256Mi" }
limits: { cpu: "2", memory: "1Gi" }
volumes:
# /data on NFS (RWX): lets you seed/upload files while the bot runs (copy
# straight onto the export from the PVE box that holds /srv/data) and lets
# the backup CronJob read it concurrently. ADJUST server/path to your
# actual export - mirrors the librarian's 192.168.1.34 Tank1 layout.
- name: data
nfs:
server: 192.168.1.34
path: /mnt/Tank1/conjurer_swap/deploy-bot/data
- name: netrc
secret: { secretName: deploy-conjurer-netrc }
---
apiVersion: v1
kind: Service
metadata: { name: deploy-bot, namespace: conjurer }
spec:
type: NodePort # so librarian/musician COULD reach it if repointed
selector: { app: deploy-bot }
# Distinct pinned nodePort (test bot owns 32442). Point librarian/musician
# CONJURER_MAIN_BOT at 192.168.1.73:32443 to route their callbacks here.
ports: [{ port: 5000, targetPort: 5000, nodePort: 32443 }]
+15 -1
View File
@@ -2,4 +2,18 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
resources: resources:
- namespace.yaml - namespace.yaml
- librarian.yaml - librarian.yaml
- bot.yaml
- deploy-bot.yaml
- deploy-bot-backup.yaml
images:
- name: gitea.czernobog.pl/gitea/conjurer-librarian
newTag: ae1bd677
- name: gitea.czernobog.pl/gitea/conjurer-bot
newTag: fbd1ec9f
# Production bot channel - only bumped when a [deploy]-tagged build appears.
# Bootstrapped to fbd1ec9f: that's the image the first [deploy] build (merge
# of conjurer#20) promoted to conjurer-bot-deploy. From here the image-updater
# keeps it current across future [deploy] commits.
- name: gitea.czernobog.pl/gitea/conjurer-bot-deploy
newTag: fbd1ec9f
+23 -4
View File
@@ -10,26 +10,45 @@ spec:
metadata: { labels: { app: librarian } } metadata: { labels: { app: librarian } }
spec: spec:
imagePullSecrets: [{ name: gitea-registry }] imagePullSecrets: [{ name: gitea-registry }]
# On SIGTERM the librarian checkpoints the running search and exits within
# CONJURER_LIBRARIAN_GRACEFUL_TIMEOUT (default 45s). Give k8s enough grace
# to let that finish before it SIGKILLs - otherwise a long scan's checkpoint
# is cut short and the search restarts from scratch instead of resuming.
terminationGracePeriodSeconds: 60
containers: containers:
- name: librarian - name: librarian
image: gitea.czernobog.pl/gitea/conjurer-librarian:v0.1.0 image: gitea.czernobog.pl/gitea/conjurer-librarian:e243777e
ports: [{ containerPort: 5001 }] ports: [{ containerPort: 5001 }]
env: env:
- { name: CONJURER_LIBRARIAN_HOST, value: "0.0.0.0" } - { name: CONJURER_LIBRARIAN_HOST, value: "0.0.0.0" }
- { name: CONJURER_LIBRARIAN_PORT, value: "5001" } - { name: CONJURER_LIBRARIAN_PORT, value: "5001" }
- { name: CONJURER_LIBRARIAN_DB_PATH, value: "/doi/" } - { name: CONJURER_LIBRARIAN_DB_PATH, value: "/doi/" }
- { name: CONJURER_API_KEY, value: "d97008b3-7a5a-11f1-acd1-000b0e0f00ed" }
- { name: CONJURER_LIBRARIAN_MAXTHREADS, value: "40" }
- { name: CONJURER_CROSSREF_MAILTO, value: "mtuszowski@gmail.com" }
- { name: CONJURER_LIBRARIAN_CHUNK, value: "_chunk.txt" }
# Librarian jest W TYM SAMYM klastrze/namespace co bot - gada z nim
# po DNS Service'u, nie przez nodePort węzła (ten zostaje tylko dla
# zewnętrznych musician/betoniarka z Dockera). Odporne na przetasowania.
- { name: CONJURER_MAIN_BOT, value: "http://bot:5000" }
- { name: CONJURER_LIBRARIAN_STATE_DIR, value: "/lib_temp_files" } - { name: CONJURER_LIBRARIAN_STATE_DIR, value: "/lib_temp_files" }
volumeMounts: volumeMounts:
- { name: doi, mountPath: /doi, readOnly: true } - { name: doi, mountPath: /doi, readOnly: true }
- { name: state, mountPath: /lib_temp_files } - { name: state, mountPath: /lib_temp_files }
resources: resources:
requests: { cpu: "100m", memory: "256Mi" } requests: { cpu: "100m", memory: "512Mi" }
limits: { cpu: "1", memory: "1Gi" } # Headroom bump: the work-queue OOM is fixed in code, but a deep
# search still pulls up to 15000 Crossref records into RAM and the
# accumulating result JSONs are loaded whole. 2Gi gives margin so a
# big search isn't OOM-killed. Tune down if the node is tight.
limits: { cpu: "1", memory: "2Gi" }
volumes: volumes:
- name: doi - name: doi
nfs: nfs:
server: 192.168.1.34 server: 192.168.1.34
path: /mnt/Tank1/conjurer_doi path: /mnt/Tank1/conjurer_swap/librarian_data/base_it1
- name: state - name: state
persistentVolumeClaim: { claimName: librarian-state } persistentVolumeClaim: { claimName: librarian-state }
--- ---