Commit Graph
19 Commits
Author SHA1 Message Date
Story Crater Bot 23fc334b8a fix(agent-pod): pin api.riotpiao.com via hostAliases
api.riotpiao.com has no in-cluster DNS record (getaddrinfo ENOTFOUND
from inside the pod, confirmed against google.com resolving fine and
kong-proxy.api.svc.cluster.local resolving fine) -- it only resolves
via the home network's own DNS. Node's fetch/undici also silently
drops a manually-set Host header (forbidden header per WHATWG fetch
spec), so overriding Host per-request isn't viable either. hostAliases
pinning the hostname to ingress-nginx-controller's ClusterIP lets
pi's models.json baseUrl work completely unchanged -- TLS SNI/Host
still say api.riotpiao.com so cert validation and Kong's Host-based
routing both still work.
2026-08-16 00:59:14 -07:00
Story Crater Bot 8d60396d14 fix(agent-pod): bump base image to node:22-slim
pi-coding-agent requires node >=22.19.0 (undici's
webidl.util.markAsUncloneable, added in Node 22) -- node:20-slim
installed fine but crashed on every invocation.
2026-08-16 00:54:45 -07:00
Story Crater Bot 0a2757aeac fix(agent-pod): pin pi-coding-agent to a version that actually exists on npm
0.1.23 was pi's own internal version string (from local pi --version),
not the npm package's semver -- npm has no such release, so the
container crash-looped on ETARGET. Latest published is 0.84.2.
2026-08-16 00:34:55 -07:00
Story Crater Bot 3620b4929c feat(agent-pod): deploy pi coding-agent pod for in-cluster harness
Namespace + Deployment (2-4 CPU, 4-8Gi mem) running node:20-slim with
pi installed at startup, wired to the homelab-ornith/reasoning/qwen
model providers via the existing model-invoke-apikey. Placeholder
node:20-slim image for now, real harness image to follow.
2026-08-16 00:23:30 -07:00
Story Crater Bot a005a07648 fix(llm-serving): ornith 504 on cold start
Two bugs. Kong timeouts were on the Ingress; it reads them from the Service, so
its 60s default applied. Moved to the isvc, which KServe propagates.

Probes ran 'ollama list' — models on disk, not in VRAM — so the pod went Ready
before it could serve. Now 'ollama ps', and both models are warmed at startup.
2026-08-15 22:58:24 -07:00
Story Crater Bot e87780b22f feat(llm-serving): adopt InferenceServices into ArgoCD
Five model servers were applied by hand and tracked nowhere. Exported live,
kubectl diff empty on all five, so the first sync adopts without restarting.

prune: false — KServe copies isvc labels to its child Deployment, so ArgoCD
would prune children it does not own and KServe would recreate them.
2026-08-15 22:45:38 -07:00
Story Crater BotandClaude Opus 5 826a2acda3 fix(api): unbreak >10.6KB LLM requests and actually bind key-auth to the model routes
Two independent bugs, both silent, both found while pointing an agent harness
at api.riotpiao.com.

1. Requests over ~10.6KB failed with HTTP 400
   {"error":{"message":"[] is too short - 'messages'"}}.

   The request-transformer plugin on the llm-chat-* routes rewrites the JSON
   body, which means it reads it via kong.request.get_body(). That returns
   nothing once nginx spills the body past client_body_buffer_size into a temp
   file, so the plugin re-serialized a body with no `messages` and the upstream
   rejected it. Measured on /v1/ornith/chat/completions: 10588 B -> 200,
   11088 B -> 400. Isolated by size-sweeping /v1/embeddings, the one route with
   no request-transformer, which passed an 18057 B body straight through to a
   semantic 413 from TEI.

   Raises the Kong http-block buffer to 16m. Any agent request carrying tool
   schemas clears the old ceiling in a single turn.

2. key-auth was never applied to any model route.

   The model-key-auth KongPlugin sat in namespace `api` while all five routes
   that annotate it live in `llm-serving`. The ingress controller resolves
   konghq.com/plugins against the annotated object's own namespace, so the
   reference dangled and the plugin never bound. Verified before the fix:
   unauthenticated GET /v1/models and POST /v1/ornith/chat/completions both
   returned 200. A dangling plugin reference fails open and logs nothing.

   Re-test both without a key after this syncs; expect 401.

Note for follow-up: llm-embeddings and llm-score carry no plugins annotation at
all, so they stay unauthenticated even after this change.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-13 21:34:50 -07:00
Story Crater Bot a118195b6f feat(api): add Kong key-auth for the model API — static API key (ksops-managed model-invoke-apikey) via KongConsumer model-invoker + key-auth plugin on all 5 model routes, OpenAI-SDK compatible (Authorization: Bearer <key>) 2026-08-13 20:28:32 -07:00
Story Crater Bot 0a29d781de fix(homarr): raise CPU limit 500m->2 + disable analytics cron — Next.js aborted with exit 134 (SIGABRT) under CPU throttle during icon-updater/analytics, self-restarting in a loop and 502ing at the ingress 2026-08-13 08:03:22 -07:00
Story Crater Bot b695cee987 fix(api): label Kong pods llm-client=true so llm-serving NetworkPolicy admits them — chat/embeddings/rerank/score routes silently hung until the client timeout because Cilium dropped Kong's packets
llm-serving-default-deny admits port 8080 only from pods carrying
llm-client=true. Kong lacked it, so every route that actually contacts an
upstream timed out. /v1/models masked the problem: request-termination answers
inside Kong and never touches an upstream, so it returned 200 throughout.

Opting in via podLabels rather than relaxing the policy — it is a compensating
control, not hygiene, since vLLM v0.11.0 is frozen on Volta and will not receive
patches for several remote/unauthenticated advisories.

podLabels land only in the pod template, not spec.selector.matchLabels, so this
is not an immutable-field change.
2026-08-13 07:55:21 -07:00
Story Crater Bot 245a03e951 feat(api): add DeepSeek-shaped LLM API on Kong — /v1/models, per-model chat completions, embeddings, rerank, score; disable Kong response buffering so stream:true actually streams
Kong matches routes on host/path/method/header, never on the request body, so a
single /v1/chat/completions dispatching on body.model is not expressible in Kong
OSS (ai-proxy-advanced, which does multi-target model routing, is Enterprise).
Model therefore goes in the path:

  GET  /v1/models                        static list (request-termination)
  POST /v1/reasoning/chat/completions     reasoning-predictor  (vLLM)
  POST /v1/ornith/chat/completions        ornith-predictor     (Ollama)
  POST /v1/qwen/chat/completions          ornith-predictor     (Ollama, same pod)
  POST /v1/embeddings                     embeddings-predictor (TEI)
  POST /v1/rerank                         reranker-predictor   (TEI)
  POST /v1/score                          verifier-predictor   (vLLM pooling)

- each chat route force-overwrites body.model via request-transformer add+replace:
  ornith:35b and qwen2.5:3b-instruct share one Ollama pod, so without this a
  client hitting /v1/qwen with "model":"ornith:35b" would silently get the 35B
- routes live in ns llm-serving, not api: an Ingress can only reference a Service
  in its own namespace, and KIC watches all namespaces
- embeddings and score need no rewrite (TEI/vLLM already serve the canonical
  paths); rerank does, since /v1/rerank 404s and only /rerank exists
- read/write timeouts 1h: Kong defaults to 60s, which a 32B model on Volta
  exceeds mid-generation and returns 504
- nginx_proxy_proxy_buffering=off: buffered responses lump or stall SSE, and both
  hops (nginx Ingress and Kong) must be unbuffered or the buffered one wins
- no auth for now, per decision; api.riotpiao.com is reachable through nginx, so
  GPU time is currently unauthenticated
2026-08-13 07:47:45 -07:00
Story Crater Bot 063f9bcd23 fix(homarr): add AUTH_OIDC_URI + email account linking — homarr hides the Authentik sign-in button unless AUTH_OIDC_URI (authorize endpoint) is set alongside AUTH_OIDC_ISSUER (per authentik/homarr SSO docs); was the missing var 2026-08-13 07:26:59 -07:00
Story Crater Bot a07af6bf07 feat(sms): add BlueBubbles iMessage delivery (Docker-OSX macOS VM pinned to worker-2) + ArgoCD app + dedicated longhorn-imessage-local SC — default longhorn SC can't schedule a 3-replica 200Gi volume (only worker-1 has 200Gi free at 100% over-provisioning) and Immediate binding would pin the qcow2 to the wrong node
- namespace: PodSecurity privileged, needed for /dev/kvm + privileged QEMU
- storageclass: 1 replica, strict-local, WaitForFirstConsumer
- deployment: nodeSelector workload=imessage + matching NoSchedule toleration,
  Recreate strategy (two QEMU procs on one qcow2 corrupts it), no readiness
  probe (guest install is interactive and takes many minutes)
- services: ClusterIP only; VNC is an unauthenticated console, reach it with
  port-forward, never an Ingress
- networkpolicy: default-deny, opt-in via sms-client=true on port 1234
2026-08-13 07:15:02 -07:00
Story Crater Bot 2ba89f2ec0 fix(homarr): tune probes via chart values, drop fragile fix-probes-job — first-boot icon updater blocks health endpoint ~50s; default 10s×3 liveness SIGTERMs the pod (247 restarts, 503); chart exposes probes so the PostSync patch-job was unnecessary and reverted on every rollout 2026-08-13 06:33:34 -07:00
Story Crater Bot 8cf342b27c chore(duckdns): remove duckdns updater entirely — superseded by cloudflared tunnel; drop app-def, manifests, kube-system Deployment 2026-08-12 14:01:01 -07:00
Story Crater Bot beb3cb21a0 refactor(argocd): replace SOPS CMP with ksops kustomize generator, rotate age key — CMP discover glob silently shadowed kustomize rendering of any app whose path held a .enc.yaml (MinIO Tenant/cloudflared/authentik jobs never applied); centralize 8 Secret manifests under k8s/argocd/secrets, defer 4 helm-values fragments 2026-08-12 13:16:15 -07:00
Story Crater Bot 8b88e13762 fix(portainer): pin to az-b (talos-cp-2), the real Longhorn storage node
nodeSelector still targeted az-a/talos-cp-1 from before the 3-CP topology
change. talos-cp-2 (az-b) has the dedicated Longhorn disks now, so the
pod's zone pin and the PVC's only viable replica location never matched
- ReplicaSchedulingFailure: disks are unavailable, pod stuck
ContainerCreating waiting on AttachVolume.
2026-08-11 16:12:13 -07:00
Story Crater Bot 3fd930c518 fix(portainer): correct storageClass name, longhorn-wffc never existed as a class
PVC sat Pending for 17 days — storageclass.storage.k8s.io "longhorn-wffc"
not found. Only longhorn, longhorn-cnpg, longhorn-static exist. Straight
naming drift, no such class was ever created.
2026-08-11 14:50:39 -07:00
Story Crater Bot e6f2ab1423 refactor(k8s): consolidate to infra/+apps/ single-source tree, dedicated per-app CNPG (authentik-db/temporal-db), wire monitoring-config, forgejo→cicd ns, drop orphan/stale (data-schemas, ollama, story-crater, sqs/argocd, key-rotation) 2026-07-23 20:54:02 -07:00