Files
bluejay-infra/apps/intranet/intranet.yaml
2026-06-13 17:20:28 -05:00

221 lines
7.3 KiB
YAML

apiVersion: v1
kind: Namespace
metadata:
name: intranet
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: intranet-vector-store
namespace: intranet
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: ConfigMap
metadata:
name: intranet-config
namespace: intranet
data:
KnowledgeApiKey: ""
TrustedHeaderSharedSecret: ""
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: intranet-web
namespace: intranet
labels:
app: intranet-web
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: intranet-web
template:
metadata:
labels:
app: intranet-web
spec:
# notes-corpus-clone: shallow-clones the Notes docs corpus into an emptyDir so
# the IntranetSearch indexer has /srv/flowercore-notes/docs to index. Uses the
# trailing-dot FQDN (gitea-clusterip.gitea.svc.cluster.local.) to bypass the
# CoreDNS *.iamworkin.lan template that otherwise resolves the in-cluster service
# name to the Traefik VIP for musl / ndots:5 pods (search-domain appending).
# Cred: gitea-corpus-cred (in-ns secret with the canonical 1P bluejay read cred;
# mirrors the imperative gitea-flowercore-notes argocd repo-cred pattern).
initContainers:
- name: notes-corpus-clone
image: alpine/git:2.45.2
imagePullPolicy: IfNotPresent
envFrom:
- secretRef:
name: gitea-corpus-cred
env:
- name: GIT_LFS_SKIP_SMUDGE
value: "1"
command: ["/bin/sh", "-c"]
args:
- 'git clone --depth 1 http://$username:$password@gitea-clusterip.gitea.svc.cluster.local.:3000/bluejay/FlowerCore.Notes.git /srv/flowercore-notes && echo "notes corpus cloned; docs entries:" && ls /srv/flowercore-notes/docs | wc -l'
volumeMounts:
- name: notes-corpus
mountPath: /srv/flowercore-notes
containers:
- name: intranet-web
image: localhost/fc-intranet-web:v20260613-cx2-1-reindex-aea7866
imagePullPolicy: Never
ports:
- containerPort: 5300
name: http
env:
- name: ASPNETCORE_ENVIRONMENT
value: Production
- name: ASPNETCORE_URLS
value: "http://+:5300"
# Embed backend = edge1 Ollama BY IPv4 (10.0.57.17:11434; has
# nomic-embed-text). The hostname edge1.iamworkin.lan is UNUSABLE from
# cluster pods: it resolves to an unroutable IPv6 (fdbc:56:*) and the
# CoreDNS *.iamworkin.lan template maps the name to the Traefik VIP, so
# embeds failed with "No route to host". Use a bare pod-routable IPv4.
# Backend is BLUEJAY-AI's GPU node (Ollama / Vulkan Iris Xe, INFRA VLAN
# 10.0.56.132) which embeds nomic-embed-text in ~160ms vs the edge1 Pi 5's
# ~3.2s for the same ~512-token chunk (~20x faster bulk embed), proven
# pod-routable from the intranet namespace 2026-06-13. The prior edge1 Pi 5
# backend (10.0.57.17:11434) remains a working fallback if BLUEJAY-AI is
# down. Bulk embed runs in the background; /health does not depend on it.
# Memory: feedback_pi5_nomic_embed_slow.
- name: IntranetSearch__OllamaBaseUrl
value: "http://10.0.56.132:11434"
# Notes docs corpus IS now mounted at /srv/flowercore-notes (see the
# notes-corpus-clone initContainer + notes-corpus-sync sidecar), so the
# IntranetSearch indexer is ENABLED. First-boot bulk embed of the corpus
# runs in the background via the edge1 Ollama backend above (~6s/chunk on
# the Pi 5); /health readiness does not depend on it, so the pod stays Ready.
- name: IntranetSearch__Enabled
value: "true"
# Page-reading override SQLite persistence on the writable PVC at
# /data. This backs pronunciation, notes, corrections, and
# page-profile metadata across pod restarts.
- name: PageReadingOverrides__DatabasePath
value: "/data/page-reading-overrides.db"
- name: KnowledgeFleetSearch__BaseUrl
value: "https://knowledge.iamworkin.lan"
- name: KnowledgeFleetSearch__ApiKey
valueFrom:
configMapKeyRef:
name: intranet-config
key: KnowledgeApiKey
optional: true
- name: TrustedHeaderAuthentication__SharedSecret
valueFrom:
configMapKeyRef:
name: intranet-config
key: TrustedHeaderSharedSecret
optional: true
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 5300
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 5300
initialDelaySeconds: 10
periodSeconds: 10
volumeMounts:
- name: vector-store
mountPath: /data
- name: notes-corpus
mountPath: /srv/flowercore-notes
readOnly: true
# notes-corpus-sync: keeps the mounted corpus fresh between pod restarts by
# pulling the Notes repo every 30 min (best-effort; the initContainer guarantees
# a fresh clone at pod start). Reuses the clone's origin (trailing-dot host + creds).
- name: notes-corpus-sync
image: alpine/git:2.45.2
imagePullPolicy: IfNotPresent
envFrom:
- secretRef:
name: gitea-corpus-cred
env:
- name: GIT_LFS_SKIP_SMUDGE
value: "1"
command: ["/bin/sh", "-c"]
args:
- 'while true; do sleep 1800; git -C /srv/flowercore-notes pull --depth 1 2>&1 | sed "s/^/[notes-corpus-sync] /" || true; done'
resources:
requests:
memory: "32Mi"
cpu: "10m"
limits:
memory: "128Mi"
cpu: "200m"
volumeMounts:
- name: notes-corpus
mountPath: /srv/flowercore-notes
volumes:
- name: vector-store
persistentVolumeClaim:
claimName: intranet-vector-store
- name: notes-corpus
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: intranet-web
namespace: intranet
spec:
selector:
app: intranet-web
ports:
- port: 5300
targetPort: 5300
name: http
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: intranet-tls
namespace: intranet
spec:
secretName: intranet-tls
issuerRef:
name: step-ca-acme
kind: ClusterIssuer
dnsNames:
- intranet.iamworkin.lan
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: intranet
namespace: intranet
spec:
entryPoints:
- websecure
routes:
- match: Host(`intranet.iamworkin.lan`)
kind: Rule
services:
- name: intranet-web
port: 5300
tls:
secretName: intranet-tls