Compare commits

..

1 Commits

Author SHA1 Message Date
gitea a9955a736b feat(astrololo): usluga render — raport PDF (PRE-24)
Nowy komponent skladajacy raport PDF. Osobny obraz, bo dzwiga TeX Live (setki MB)
— ta sama zasada co przy izolacji swissepha (LOG-27): obraz produktu zostaje maly,
TeX aktualizuje sie niezaleznie, a awaria renderu nie kladzie aplikacji, tylko
przycisk „Pobierz PDF".

- render.yaml — Deployment + Service. ClusterIP, BEZ NodePortu i Ingressu: nie ma
  powodu, zeby ktokolwiek siegal do tej uslugi z zewnatrz. Rozmawia wylacznie
  z prezentacja.
- Szyfrowanie: wlasny, TRZECI klucz LINK_KEY_PRESENTATION_RENDER z sekretu
  astrololo-link. Osobny, bo tym laczem plynie CALY raport (dane urodzeniowe
  i opisy z baz) — przejecie go nie moze otwierac lacza do logiki ani danych.
  LINK_ENCRYPTION_REQUIRED=true, wiec bez klucza pod NIE wstaje.
- readOnlyRootFilesystem + emptyDir na /tmp: kompilacja pisze tylko do katalogu
  tymczasowego, raport nie zostawia sladu w kontenerze.
- Limity rozjechane celowo (100m/256Mi -> 1500m/1Gi): XeLaTeX na obszernym
  raporcie bierze duzo, ale na krotko.
- presentation: RENDER_URL + trzeci klucz lacza.

Sekret astrololo-link trzeba UZUPELNIC o trzeci klucz PRZED wdrozeniem,
zachowujac dwa dotychczasowe — komenda w instrukcji.

Sprawdzone: kubectl kustomize + apply --dry-run=server na zywym klastrze
(service/render i deployment.apps/render created).

Pelna instrukcja: docs/wdrozenie-render-pdf.md w repo astrololo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 19:22:11 +02:00
15 changed files with 3 additions and 520 deletions
-15
View File
@@ -8,21 +8,6 @@ Warstwy: `presentation` (wejście z przeglądarki przez **Ingress po https**)
Adres aplikacji: **https://astrololo.czernobog.pl** — patrz [TLS](#-tls--wymagane-kroki-przed-wdrożeniem).
## Co śledzi image-updater — [`image-updater.yaml`](image-updater.yaml)
Lista obrazów podbijanych automatycznie jest **jawna** i żyje w CRD `ImageUpdater`
(ns `argocd`). Obraz, którego na niej nie ma, **nigdy się nie podbije**, choćby CI
go budowało — tak przez chwilę wisiał `render` na `:latest`, zanim dopisaliśmy go do
listy. Dodając nową usługę, dopisz jej wpis w `image-updater.yaml` i nałóż:
```bash
kubectl apply -f astrololo/image-updater.yaml
```
Ten plik **celowo nie jest w `kustomization.yaml`**: resource stoi w ns `argocd`
(poza namespace docelowym aplikacji), a to konfiguracja kontrolera, który wdraża tę
aplikację — nakładamy go ręcznie, w repo trzymamy dla odtwarzalności i historii.
## ⚠️ Sekret `astrololo-auth` — utwórz PRZED wdrożeniem
Aplikacja wystawia treść **oryginalnych baz interpretacyjnych**, dlatego wymaga
-4
View File
@@ -9,10 +9,6 @@ spec:
template:
metadata: { labels: { app: data } }
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 }]
containers:
- name: data
-44
View File
@@ -1,44 +0,0 @@
# Konfiguracja argocd-image-updater dla astrololo — ŹRÓDŁO PRAWDY tego, CO śledzimy.
#
# Model v1.x: osobny CRD `ImageUpdater` w ns `argocd` (nie adnotacje na Application).
# Lista `images` jest JAWNA — obraz, którego tu NIE MA, nigdy nie zostanie podbity,
# choćby CI go budowało. Tak przez chwilę wisiał `render` na `:latest` (PRE-24):
# usługa istniała i budowała tag SHA, ale updater jej nie znał, więc kustomization
# jej nie ruszał. Dopisanie wpisu = wejście usługi do rotacji.
#
# ⚠️ TEGO PLIKU NIE MA w astrololo/kustomization.yaml i NIE MA GO TAM MIEĆ:
# 1. resource żyje w ns `argocd`, a Application astrololo celuje w ns `astrololo`
# — auto-sync przez kustomize próbowałby zapisać poza swój namespace docelowy;
# 2. to konfiguracja kontrolera, który wdraża tę właśnie aplikację — niech app
# nie zarządza narzędziem, które ją wdraża.
# Plik jest trzymany w repo dla odtwarzalności i historii; nakłada się go RĘCZNIE:
# kubectl apply -f astrololo/image-updater.yaml
#
# Strategia `newest-build`: updater bierze obraz o NAJNOWSZYM znaczniku czasu builda
# i zapisuje jego tag SHA do kustomization (write-back git). Uwaga na reprodukowalne
# buildy — identyczny `created` na kilku tagach potrafi zablokować wybór najnowszego.
apiVersion: argocd-image-updater.argoproj.io/v1alpha1
kind: ImageUpdater
metadata:
name: astrololo
namespace: argocd
spec:
applicationRefs:
- namePattern: astrololo
images:
- alias: data
imageName: gitea.czernobog.pl/gitea/astrololo-data
- alias: logic
imageName: gitea.czernobog.pl/gitea/astrololo-logic
- alias: presentation
imageName: gitea.czernobog.pl/gitea/astrololo-presentation
- alias: render
imageName: gitea.czernobog.pl/gitea/astrololo-render
commonUpdateSettings:
updateStrategy: newest-build
writeBackConfig:
method: git:secret:argocd/git-creds
gitConfig:
repository: https://gitea.czernobog.pl/gitea/deploy.git
branch: master
writeBackTarget: kustomization:/astrololo
+3 -3
View File
@@ -10,10 +10,10 @@ resources:
- ingress.yaml # wejście po https + przekierowanie z http
images:
- name: gitea.czernobog.pl/gitea/astrololo-data
newTag: 70c83cfc
newTag: f34016a4
- name: gitea.czernobog.pl/gitea/astrololo-logic
newTag: 70c83cfc
newTag: f34016a4
- name: gitea.czernobog.pl/gitea/astrololo-render
newTag: latest
- name: gitea.czernobog.pl/gitea/astrololo-presentation
newTag: 70c83cfc
newTag: f34016a4
-4
View File
@@ -9,10 +9,6 @@ spec:
template:
metadata: { labels: { app: logic } }
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 }]
containers:
- name: logic
-21
View File
@@ -9,10 +9,6 @@ spec:
template:
metadata: { labels: { app: presentation } }
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 }]
containers:
- name: presentation
@@ -60,26 +56,9 @@ spec:
secretKeyRef: { name: astrololo-link, key: LINK_KEY_PRESENTATION_RENDER }
- name: LINK_ENCRYPTION_REQUIRED
value: "true"
# Konta zakładane z ekranu „Konta" (PRE-26). Konto administracyjne
# zostaje w APP_USER/APP_PASSWORD powyżej — celowo, bo dzięki temu
# NIE DA SIĘ go skasować ani ograniczyć z aplikacji.
- name: ACCOUNTS_FILE
value: "/app/state/accounts.json"
volumeMounts:
# subPath, NIE cały udział: prezentacja dostaje wyłącznie własny
# podkatalog i nie widzi baz interpretacyjnych. Zamontowanie tu całego
# /mnt/Tank1/astrololo obeszłoby bokiem zamknięcie dostępu z DAN-25.
- name: state
mountPath: /app/state
subPath: presentation-state
resources:
requests: { cpu: "100m", memory: "128Mi" }
limits: { cpu: "300m", memory: "256Mi" }
volumes:
- name: state
nfs:
server: 192.168.1.34
path: /mnt/Tank1/astrololo
---
apiVersion: v1
kind: Service
-4
View File
@@ -19,10 +19,6 @@ spec:
template:
metadata: { labels: { app: render } }
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 }]
containers:
- name: render
-106
View File
@@ -1,106 +0,0 @@
# 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
@@ -1,62 +0,0 @@
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
@@ -1,22 +0,0 @@
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
@@ -1,65 +0,0 @@
# 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
@@ -1,80 +0,0 @@
# 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 }]
-19
View File
@@ -1,19 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.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
-67
View File
@@ -1,67 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: librarian
namespace: conjurer
spec:
replicas: 1
selector: { matchLabels: { app: librarian } }
template:
metadata: { labels: { app: librarian } }
spec:
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:
- name: librarian
image: gitea.czernobog.pl/gitea/conjurer-librarian:e243777e
ports: [{ containerPort: 5001 }]
env:
- { name: CONJURER_LIBRARIAN_HOST, value: "0.0.0.0" }
- { name: CONJURER_LIBRARIAN_PORT, value: "5001" }
- { 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" }
volumeMounts:
- { name: doi, mountPath: /doi, readOnly: true }
- { name: state, mountPath: /lib_temp_files }
resources:
requests: { cpu: "100m", memory: "512Mi" }
# 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:
- name: doi
nfs:
server: 192.168.1.34
path: /mnt/Tank1/conjurer_swap/librarian_data/base_it1
- name: state
persistentVolumeClaim: { claimName: librarian-state }
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: librarian-state, namespace: conjurer }
spec:
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 1Gi } }
---
apiVersion: v1
kind: Service
metadata: { name: librarian, namespace: conjurer }
spec:
selector: { app: librarian }
ports: [{ port: 5001, targetPort: 5001 }]
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: conjurer