286 lines
9.6 KiB
YAML
286 lines
9.6 KiB
YAML
# FlowerCore.Knowledge.Web — fleet vector indexing & RAG hub.
|
|
#
|
|
# Phase 2.4 of the Knowledge service plan. REST + MCP service that scans
|
|
# *.db files under /data/vector-stores and exposes:
|
|
# - REST: /api/v1/editions, /api/v1/corpus/search, /healthz
|
|
# - MCP: list_editions, describe_edition, corpus_search
|
|
# - Static OpenAPI/Scalar via UseFlowerCoreApi
|
|
#
|
|
# Architecture:
|
|
# Plan: FlowerCore.Notes/docs/ai-agents/flowercore-knowledge-service-plan.md
|
|
# Sprint: FlowerCore.Notes/docs/ai-station/sprint-e-xxl-plan.md (Track B)
|
|
# Repo: D:\git\FlowerCore\FlowerCore.Knowledge\
|
|
# Shared: FlowerCore.Common -> FlowerCore.Shared.Indexing (chunkers, vector
|
|
# stores, edition profiles, ICorpusSearchService facade)
|
|
#
|
|
# Deployment order (see apps/knowledge/README.md and the bluejay-infra/README.md
|
|
# top-level checklist):
|
|
# 1. FlowerCore.DNS public A record knowledge.iamworkin.lan -> 10.0.56.200
|
|
# MUST exist BEFORE the Certificate is created, or cert-manager HTTP-01
|
|
# backs off ~2h. Memory: feedback_pfsense_dns_required_for_acme.
|
|
# 2. Build + import the image to ALL RKE2 nodes (server + both agents) since
|
|
# the Pod uses a Longhorn PVC and may schedule anywhere.
|
|
# Memory: feedback_rke2_localhost_imagepullpolicy.
|
|
# 3. Bump the image tag in this file, git push.
|
|
# 4. ArgoCD ApplicationSet picks up within ~3 minutes and creates
|
|
# infra-knowledge.
|
|
#
|
|
# Initial-deploy state:
|
|
# The Longhorn PVC is empty on first deploy. Knowledge.Web's filesystem
|
|
# catalog will report zero editions until vector-store *.db files are
|
|
# pushed into /data/vector-stores. Initial population is a follow-up step
|
|
# (Phase 2.5+, Blazor admin UI's "Rebuild" button); for the first deploy
|
|
# the goal is just to prove the pod boots, /healthz returns 200, and the
|
|
# Traefik IngressRoute serves the Scalar UI.
|
|
---
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: knowledge
|
|
labels:
|
|
app.kubernetes.io/part-of: bluejay-infra
|
|
---
|
|
# MCP bearer token for the read-only Agent Zero Phase 1 lane. The 1Password
|
|
# item currently stores the raw token in its concealed PASSWORD field, which
|
|
# the operator syncs into the namespaced Secret key `password`.
|
|
apiVersion: onepassword.com/v1
|
|
kind: OnePasswordItem
|
|
metadata:
|
|
name: knowledge-mcp-tokens
|
|
namespace: knowledge
|
|
spec:
|
|
itemPath: "vaults/IAmWorkin/items/FlowerCore Knowledge MCP Tokens"
|
|
---
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: knowledge-vector-store
|
|
namespace: knowledge
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
storageClassName: longhorn
|
|
resources:
|
|
requests:
|
|
storage: 20Gi
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: knowledge-web
|
|
namespace: knowledge
|
|
labels:
|
|
app: knowledge-web
|
|
app.kubernetes.io/name: knowledge-web
|
|
app.kubernetes.io/part-of: bluejay-infra
|
|
spec:
|
|
replicas: 1
|
|
revisionHistoryLimit: 3
|
|
# RWO Longhorn PVC blocks rolling updates (multi-attach error). Recreate
|
|
# is the canonical pattern (memory: feedback_rwo_pvc_blocks_rolling).
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app: knowledge-web
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: knowledge-web
|
|
app.kubernetes.io/name: knowledge-web
|
|
app.kubernetes.io/part-of: bluejay-infra
|
|
annotations:
|
|
prometheus.io/scrape: "true"
|
|
prometheus.io/port: "8080"
|
|
prometheus.io/path: "/metrics"
|
|
spec:
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
fsGroup: 1654
|
|
fsGroupChangePolicy: OnRootMismatch
|
|
containers:
|
|
- name: web
|
|
# Placeholder tag — bump to the image you built + imported to ALL
|
|
# RKE2 nodes via scripts/deploy-knowledge.sh before applying.
|
|
image: localhost/fc-knowledge-web:v20260603-oidc-authentik
|
|
imagePullPolicy: Never
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
args:
|
|
- |
|
|
if [ -n "${KNOWLEDGE_MCP_BEARER_TOKEN:-}" ]; then
|
|
export FlowerCore__Mcp__ApiKey__Key="Bearer ${KNOWLEDGE_MCP_BEARER_TOKEN}"
|
|
fi
|
|
exec dotnet FlowerCore.Knowledge.Web.dll
|
|
ports:
|
|
- containerPort: 8080
|
|
name: http
|
|
env:
|
|
- name: ASPNETCORE_URLS
|
|
value: "http://+:8080"
|
|
- name: ASPNETCORE_ENVIRONMENT
|
|
value: "Production"
|
|
- name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
|
|
value: "false"
|
|
# AuthentiK/OIDC is wired but not enforced until the
|
|
# knowledge-oidc-client Secret is provisioned and
|
|
# FlowerCore__Auth__Enabled is flipped to true.
|
|
- name: FlowerCore__Auth__Enabled
|
|
value: "false"
|
|
- name: FlowerCore__Auth__Oidc__Enabled
|
|
value: "true"
|
|
- name: FlowerCore__Auth__Oidc__Authority
|
|
value: "https://id.iamworkin.lan/application/o/knowledge/"
|
|
- name: FlowerCore__Auth__Oidc__Audience
|
|
value: "knowledge"
|
|
- name: FlowerCore__Auth__Oidc__ClientId
|
|
value: "knowledge"
|
|
- name: FlowerCore__Auth__Oidc__ClientSecret
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: knowledge-oidc-client
|
|
key: client_secret
|
|
optional: true
|
|
# Vector-store directory + embedding model + edition profile dir.
|
|
# Profile JSON is baked into the image at /home/app/editions via the
|
|
# csproj Content-link from FlowerCore.Common/editions/.
|
|
- name: Knowledge__VectorStoresDirectory
|
|
value: "/data/vector-stores"
|
|
- name: Knowledge__EmbeddingModel
|
|
value: "nomic-embed-text"
|
|
- name: Knowledge__DefaultLimit
|
|
value: "5"
|
|
- name: Knowledge__MaxLimit
|
|
value: "50"
|
|
- name: FlowerCore__Editions__ProfileDirectory
|
|
value: "/home/app/editions"
|
|
# Embed via edge1 Pi 5 + AI HAT+ (10.0.57.17:11434). Cluster
|
|
# services do not depend on BLUEJAY-WS (private dev hardware) per
|
|
# bluejay-infra@0f9d56e. Query-time embedding is fast enough on
|
|
# edge1 (~ms per query); bulk index rebuilds (Phase 2.5+) will
|
|
# need a separate ingestion lane that can opt into the
|
|
# workstation GPU when present.
|
|
- name: FlowerCore__Ollama__BaseUrl
|
|
value: "http://10.0.57.17:11434"
|
|
- name: FlowerCore__Mcp__ApiKey__Key
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: knowledge-mcp-tokens
|
|
key: password
|
|
- name: FlowerCore__Mcp__ApiKey__HeaderName
|
|
value: "Authorization"
|
|
- name: KNOWLEDGE_MCP_BEARER_TOKEN
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: knowledge-mcp-tokens
|
|
key: password
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 256Mi
|
|
limits:
|
|
cpu: 1000m
|
|
memory: 1Gi
|
|
# /healthz is mapped by HealthController (controller-based route).
|
|
# tcpSocket liveness is the defensive fallback in case middleware
|
|
# later gates /healthz behind auth (memory:
|
|
# feedback_k8s_probes_behind_auth_middleware).
|
|
startupProbe:
|
|
httpGet:
|
|
path: /healthz
|
|
port: 8080
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
failureThreshold: 30
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /healthz
|
|
port: 8080
|
|
periodSeconds: 10
|
|
failureThreshold: 3
|
|
livenessProbe:
|
|
tcpSocket:
|
|
port: 8080
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 30
|
|
failureThreshold: 3
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1654
|
|
runAsGroup: 1654
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
volumeMounts:
|
|
- name: vector-store
|
|
mountPath: /data/vector-stores
|
|
- name: tmp
|
|
mountPath: /tmp
|
|
- name: logs
|
|
mountPath: /home/app/logs
|
|
volumes:
|
|
- name: vector-store
|
|
persistentVolumeClaim:
|
|
claimName: knowledge-vector-store
|
|
- name: tmp
|
|
emptyDir: {}
|
|
- name: logs
|
|
emptyDir: {}
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: knowledge-web
|
|
namespace: knowledge
|
|
labels:
|
|
app: knowledge-web
|
|
app.kubernetes.io/name: knowledge-web
|
|
app.kubernetes.io/part-of: bluejay-infra
|
|
spec:
|
|
type: ClusterIP
|
|
selector:
|
|
app: knowledge-web
|
|
ports:
|
|
- name: http
|
|
port: 80
|
|
targetPort: 8080
|
|
---
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Certificate
|
|
metadata:
|
|
name: knowledge-tls
|
|
namespace: knowledge
|
|
spec:
|
|
secretName: knowledge-tls
|
|
issuerRef:
|
|
name: step-ca-acme
|
|
kind: ClusterIssuer
|
|
dnsNames:
|
|
- knowledge.iamworkin.lan
|
|
# step-ca ACME caps lifetime at 30d; requesting 90d silently capped
|
|
# made renewBefore=cert-lifetime → perpetual renewal loop (10888+ CRs
|
|
# in 18h on 2026-05-07). Match working 720h/240h pattern from other
|
|
# FC services.
|
|
duration: 720h # 30d (step-ca cap)
|
|
renewBefore: 240h # 10d
|
|
---
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: knowledge
|
|
namespace: knowledge
|
|
spec:
|
|
entryPoints:
|
|
- websecure
|
|
routes:
|
|
- match: Host(`knowledge.iamworkin.lan`)
|
|
kind: Rule
|
|
services:
|
|
- name: knowledge-web
|
|
port: 80
|
|
tls:
|
|
secretName: knowledge-tls
|