WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s

This commit is contained in:
yawan
2026-09-22 16:19:06 +08:00
commit f7fc992f57
3929 changed files with 1006607 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
Post-installation notes for WeKnora Helm chart.
Ref: https://github.com/argoproj/argo-helm/blob/main/charts/argo-cd/templates/NOTES.txt
*/}}
================================================================================
WeKnora has been installed successfully!
================================================================================
Release: {{ .Release.Name }}
Namespace: {{ .Release.Namespace }}
Version: {{ .Chart.AppVersion }}
--------------------------------------------------------------------------------
ACCESSING WEKNORA
--------------------------------------------------------------------------------
{{- if .Values.ingress.enabled }}
WeKnora is accessible via Ingress:
URL: {{ if .Values.ingress.tls.enabled }}https{{ else }}http{{ end }}://{{ .Values.ingress.host }}
{{- else }}
To access WeKnora, use port-forwarding:
# Frontend (Web UI)
kubectl port-forward svc/frontend -n {{ .Release.Namespace }} 8080:80
# Then open: http://localhost:8080
{{- end }}
{{- if not .Values.ingress.enabled }}
To expose WeKnora externally, enable Ingress:
helm upgrade {{ .Release.Name }} ./helm \
--set ingress.enabled=true \
--set ingress.host=weknora.example.com
{{- end }}
--------------------------------------------------------------------------------
CONFIGURATION
--------------------------------------------------------------------------------
Components deployed:
{{- if .Values.app.enabled }}
- Backend API ({{ include "weknora.app.image" . }})
{{- end }}
{{- if .Values.frontend.enabled }}
- Frontend UI ({{ include "weknora.frontend.image" . }})
{{- end }}
{{- if .Values.docreader.enabled }}
- Document Reader ({{ include "weknora.docreader.image" . }})
{{- end }}
{{- if .Values.postgresql.enabled }}
- PostgreSQL/ParadeDB ({{ include "weknora.postgresql.image" . }})
{{- end }}
{{- if .Values.redis.enabled }}
- Redis ({{ include "weknora.redis.image" . }})
{{- end }}
{{- if or .Values.minio.enabled .Values.neo4j.enabled .Values.qdrant.enabled }}
Optional components enabled:
{{- if .Values.minio.enabled }}
- MinIO (S3-compatible storage)
{{- end }}
{{- if .Values.neo4j.enabled }}
- Neo4j (Knowledge Graph)
{{- end }}
{{- if .Values.qdrant.enabled }}
- Qdrant (Vector Database)
{{- end }}
{{- end }}
--------------------------------------------------------------------------------
CONNECTING TO LLM
--------------------------------------------------------------------------------
WeKnora requires an LLM backend. Configure via environment variables:
helm upgrade {{ .Release.Name }} ./helm \
--set app.extraEnv[0].name=OLLAMA_BASE_URL \
--set app.extraEnv[0].value=http://ollama:11434 \
--set app.extraEnv[1].name=INIT_LLM_MODEL_NAME \
--set app.extraEnv[1].value=qwen2.5:7b
Supported LLM backends:
- Ollama (local)
- OpenAI API compatible endpoints
- Qwen, DeepSeek, and other Chinese LLMs
{{- if .Values.neo4j.enabled }}
--------------------------------------------------------------------------------
GRAPHRAG (KNOWLEDGE GRAPH)
--------------------------------------------------------------------------------
Neo4j is enabled for GraphRAG feature.
To use GraphRAG, enable Neo4j. NEO4J_ENABLE is the sole graph switch and is
injected automatically when neo4j.enabled=true (no need to set ENABLE_GRAPH_RAG,
which is deprecated and no longer read by the app):
helm upgrade {{ .Release.Name }} ./helm \
--set neo4j.enabled=true \
--set neo4j.password=<your-secure-password>
Access Neo4j Browser:
kubectl port-forward svc/neo4j -n {{ .Release.Namespace }} 7474:7474 7687:7687
# Open: http://localhost:7474
{{- end }}
--------------------------------------------------------------------------------
DOCUMENTATION
--------------------------------------------------------------------------------
GitHub: https://github.com/Tencent/WeKnora
API Docs: https://github.com/Tencent/WeKnora/blob/main/docs/api/README.md
FAQ: https://github.com/Tencent/WeKnora/blob/main/docs/QA.md
--------------------------------------------------------------------------------
TROUBLESHOOTING
--------------------------------------------------------------------------------
Check pod status:
kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }}
View logs:
kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/component=app -f
kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/component=frontend -f
================================================================================
+195
View File
@@ -0,0 +1,195 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
WeKnora Helm Chart Template Helpers
Best Practices References:
- https://helm.sh/docs/chart_best_practices/templates/
- https://github.com/argoproj/argo-helm/blob/main/charts/argo-cd/templates/_helpers.tpl
*/}}
{{/*
Expand the name of the chart.
*/}}
{{- define "weknora.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "weknora.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
Ref: https://helm.sh/docs/chart_best_practices/labels/
*/}}
{{- define "weknora.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels following Kubernetes recommended labels.
Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
*/}}
{{- define "weknora.labels" -}}
helm.sh/chart: {{ include "weknora.chart" . }}
{{ include "weknora.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: weknora
{{- end }}
{{/*
Selector labels
*/}}
{{- define "weknora.selectorLabels" -}}
app.kubernetes.io/name: {{ include "weknora.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Component labels - use for individual components
Usage: {{ include "weknora.componentLabels" (dict "component" "app" "context" .) }}
*/}}
{{- define "weknora.componentLabels" -}}
{{ include "weknora.labels" .context }}
app.kubernetes.io/component: {{ .component }}
{{- end }}
{{/*
Component selector labels
Usage: {{ include "weknora.componentSelectorLabels" (dict "component" "app" "context" .) }}
*/}}
{{- define "weknora.componentSelectorLabels" -}}
{{ include "weknora.selectorLabels" .context }}
app.kubernetes.io/component: {{ .component }}
{{- end }}
{{/*
Create the name of the service account to use.
Ref: https://helm.sh/docs/chart_best_practices/rbac/
*/}}
{{- define "weknora.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "weknora.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Secret name - supports existing secret
*/}}
{{- define "weknora.secretName" -}}
{{- if .Values.secrets.existingSecret }}
{{- .Values.secrets.existingSecret }}
{{- else }}
{{- include "weknora.fullname" . }}-secrets
{{- end }}
{{- end }}
{{/*
Return the app image with tag.
Defaults to Chart.appVersion if tag is not specified.
*/}}
{{- define "weknora.app.image" -}}
{{- $tag := default .Chart.AppVersion .Values.app.image.tag }}
{{- printf "%s:%s" .Values.app.image.repository $tag }}
{{- end }}
{{/*
Return the frontend image with tag.
*/}}
{{- define "weknora.frontend.image" -}}
{{- printf "%s:%s" .Values.frontend.image.repository .Values.frontend.image.tag }}
{{- end }}
{{/*
Return the docreader image with tag.
*/}}
{{- define "weknora.docreader.image" -}}
{{- printf "%s:%s" .Values.docreader.image.repository .Values.docreader.image.tag }}
{{- end }}
{{/*
Return the PostgreSQL image with tag.
*/}}
{{- define "weknora.postgresql.image" -}}
{{- printf "%s:%s" .Values.postgresql.image.repository .Values.postgresql.image.tag }}
{{- end }}
{{/*
Return the Redis image with tag.
*/}}
{{- define "weknora.redis.image" -}}
{{- printf "%s:%s" .Values.redis.image.repository .Values.redis.image.tag }}
{{- end }}
{{/*
Return the Neo4j image with tag.
*/}}
{{- define "weknora.neo4j.image" -}}
{{- printf "%s:%s" .Values.neo4j.image.repository .Values.neo4j.image.tag }}
{{- end }}
{{/*
Create image pull secrets list.
*/}}
{{- define "weknora.imagePullSecrets" -}}
{{- with .Values.global.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end }}
{{/*
Return the storage class name.
*/}}
{{- define "weknora.storageClass" -}}
{{- if .Values.global.storageClass }}
{{- if eq .Values.global.storageClass "-" }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.global.storageClass | quote }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Pod security context.
Merges global defaults with component-specific overrides.
*/}}
{{- define "weknora.podSecurityContext" -}}
{{- $global := .Values.global.podSecurityContext | default dict }}
{{- $component := .componentSecurityContext | default dict }}
{{- $merged := merge $component $global }}
{{- if $merged }}
securityContext:
{{- toYaml $merged | nindent 2 }}
{{- end }}
{{- end }}
{{/*
Container security context.
*/}}
{{- define "weknora.containerSecurityContext" -}}
{{- if . }}
securityContext:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end }}
+201
View File
@@ -0,0 +1,201 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
WeKnora Backend API Server Deployment and Service.
*/}}
{{- if .Values.app.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "weknora.fullname" . }}-app
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "app" "context" .) | nindent 4 }}
spec:
replicas: {{ .Values.app.replicaCount }}
selector:
matchLabels:
{{- include "weknora.componentSelectorLabels" (dict "component" "app" "context" .) | nindent 6 }}
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
{{- include "weknora.componentSelectorLabels" (dict "component" "app" "context" .) | nindent 8 }}
spec:
{{- include "weknora.imagePullSecrets" . | nindent 6 }}
serviceAccountName: {{ include "weknora.serviceAccountName" . }}
{{- with .Values.app.podSecurityContext | default .Values.global.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: app
image: {{ include "weknora.app.image" . }}
imagePullPolicy: {{ .Values.app.image.pullPolicy }}
{{- with .Values.app.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- containerPort: 8080
name: http
protocol: TCP
env:
# Application settings
- name: GIN_MODE
value: {{ .Values.app.env.GIN_MODE | quote }}
- name: TZ
value: {{ .Values.app.env.TZ | quote }}
# Database configuration
- name: DB_DRIVER
value: "postgres"
- name: DB_HOST
value: "postgres"
- name: DB_PORT
value: "5432"
- name: DB_USER
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: DB_PASSWORD
- name: DB_NAME
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: DB_NAME
# Redis configuration
- name: REDIS_ADDR
value: "redis:6379"
- name: REDIS_USERNAME
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: REDIS_USERNAME
optional: true
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: REDIS_PASSWORD
- name: REDIS_DB
value: "0"
- name: REDIS_PREFIX
value: "stream:"
- name: STREAM_MANAGER_TYPE
value: {{ .Values.app.env.STREAM_MANAGER_TYPE | quote }}
# Security
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: JWT_SECRET
- name: SYSTEM_AES_KEY
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: SYSTEM_AES_KEY
# Retrieval & Storage
- name: RETRIEVE_DRIVER
value: {{ .Values.app.env.RETRIEVE_DRIVER | quote }}
- name: STORAGE_TYPE
value: {{ .Values.app.env.STORAGE_TYPE | quote }}
- name: LOCAL_STORAGE_BASE_DIR
value: {{ .Values.app.env.LOCAL_STORAGE_BASE_DIR | quote }}
# Document reader
- name: DOCREADER_ADDR
value: "docreader:50051"
# Processing
- name: AUTO_RECOVER_DIRTY
value: {{ .Values.app.env.AUTO_RECOVER_DIRTY | quote }}
- name: CONCURRENCY_POOL_SIZE
value: {{ .Values.app.env.CONCURRENCY_POOL_SIZE | quote }}
# Docker sandbox is off unless the deployer opts in. A workspace
# admin who can save a Docker config can create containers on
# whatever Engine API this process can reach (often host root).
- name: WEKNORA_SANDBOX_DOCKER_ENABLED
value: {{ .Values.app.env.WEKNORA_SANDBOX_DOCKER_ENABLED | default "false" | quote }}
{{- if .Values.neo4j.enabled }}
# Neo4j configuration (for GraphRAG)
# NEO4J_ENABLE 是知识图谱的唯一开关(Go 代码认它,不认 ENABLE_GRAPH_RAG)。
# neo4j.enabled=true 时自动注入,无需用户单独设置。
- name: NEO4J_ENABLE
value: "true"
- name: NEO4J_URI
value: "bolt://neo4j:7687"
- name: NEO4J_USERNAME
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: NEO4J_USERNAME
- name: NEO4J_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: NEO4J_PASSWORD
{{- end }}
{{- with .Values.app.extraEnv }}
# Additional environment variables
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: data-files
mountPath: /data/files
resources:
{{- toYaml .Values.app.resources | nindent 12 }}
{{- with .Values.app.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.app.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: data-files
{{- if .Values.dataFiles.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.dataFiles.persistence.existingClaim | default (printf "%s-data-files" (include "weknora.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- with .Values.app.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.app.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.app.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
# Service name must be "app" - frontend nginx config hardcodes this
name: app
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "app" "context" .) | nindent 4 }}
spec:
type: {{ .Values.app.service.type }}
selector:
{{- include "weknora.componentSelectorLabels" (dict "component" "app" "context" .) | nindent 4 }}
ports:
- name: http
port: {{ .Values.app.service.port }}
targetPort: http
protocol: TCP
{{- end }}
+102
View File
@@ -0,0 +1,102 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
WeKnora Document Reader (gRPC) Deployment and Service.
*/}}
{{- if .Values.docreader.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "weknora.fullname" . }}-docreader
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "docreader" "context" .) | nindent 4 }}
spec:
replicas: {{ .Values.docreader.replicaCount }}
selector:
matchLabels:
{{- include "weknora.componentSelectorLabels" (dict "component" "docreader" "context" .) | nindent 6 }}
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
{{- include "weknora.componentSelectorLabels" (dict "component" "docreader" "context" .) | nindent 8 }}
spec:
{{- include "weknora.imagePullSecrets" . | nindent 6 }}
serviceAccountName: {{ include "weknora.serviceAccountName" . }}
{{- with .Values.global.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: docreader
image: {{ include "weknora.docreader.image" . }}
imagePullPolicy: {{ .Values.docreader.image.pullPolicy }}
{{- with .Values.docreader.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- containerPort: 50051
name: grpc
protocol: TCP
env:
- name: STORAGE_TYPE
value: {{ .Values.docreader.env.STORAGE_TYPE | quote }}
resources:
{{- toYaml .Values.docreader.resources | nindent 12 }}
# gRPC health check using grpc_health_probe
livenessProbe:
exec:
command:
- grpc_health_probe
- -addr=localhost:50051
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- grpc_health_probe
- -addr=localhost:50051
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
{{- with .Values.docreader.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.docreader.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.docreader.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
# Service name must be "docreader" - app references this
name: docreader
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "docreader" "context" .) | nindent 4 }}
spec:
type: {{ .Values.docreader.service.type }}
selector:
{{- include "weknora.componentSelectorLabels" (dict "component" "docreader" "context" .) | nindent 4 }}
ports:
- name: grpc
port: {{ .Values.docreader.service.port }}
targetPort: grpc
protocol: TCP
{{- end }}
+112
View File
@@ -0,0 +1,112 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
WeKnora Frontend Web UI Deployment and Service.
*/}}
{{- if .Values.frontend.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "weknora.fullname" . }}-frontend
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "frontend" "context" .) | nindent 4 }}
spec:
replicas: {{ .Values.frontend.replicaCount }}
selector:
matchLabels:
{{- include "weknora.componentSelectorLabels" (dict "component" "frontend" "context" .) | nindent 6 }}
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
{{- include "weknora.componentSelectorLabels" (dict "component" "frontend" "context" .) | nindent 8 }}
spec:
{{- include "weknora.imagePullSecrets" . | nindent 6 }}
serviceAccountName: {{ include "weknora.serviceAccountName" . }}
{{- with .Values.global.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: frontend
image: {{ include "weknora.frontend.image" . }}
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
{{- with .Values.frontend.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
- name: APP_HOST
value: {{ .Values.frontend.appHost | default "app" | quote }}
- name: APP_PORT
value: {{ .Values.frontend.appPort | default .Values.app.service.port | quote }}
ports:
- containerPort: 80
name: http
protocol: TCP
resources:
{{- toYaml .Values.frontend.resources | nindent 12 }}
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# nginx requires writable directories for temp files
volumeMounts:
- name: nginx-cache
mountPath: /var/cache/nginx
- name: nginx-run
mountPath: /var/run
volumes:
- name: nginx-cache
emptyDir: {}
- name: nginx-run
emptyDir: {}
{{- with .Values.frontend.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.frontend.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.frontend.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
# Service name must be "frontend" - ingress references this
name: frontend
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "frontend" "context" .) | nindent 4 }}
spec:
type: {{ .Values.frontend.service.type }}
selector:
{{- include "weknora.componentSelectorLabels" (dict "component" "frontend" "context" .) | nindent 4 }}
ports:
- name: http
port: {{ .Values.frontend.service.port }}
targetPort: http
protocol: TCP
{{- end }}
+52
View File
@@ -0,0 +1,52 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
Ingress resource for WeKnora.
Routes /api to backend, / to frontend.
*/}}
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "weknora.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "ingress" "context" .) | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls.enabled }}
tls:
- hosts:
- {{ .Values.ingress.host | quote }}
{{- if .Values.ingress.tls.secretName }}
secretName: {{ .Values.ingress.tls.secretName }}
{{- end }}
{{- end }}
rules:
- host: {{ .Values.ingress.host | quote }}
http:
paths:
# API routes - must come first (more specific path)
- path: /api
pathType: Prefix
backend:
service:
name: app
port:
name: http
# Frontend routes - catch-all
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
name: http
{{- end }}
+136
View File
@@ -0,0 +1,136 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
Neo4j Graph Database Deployment and Service.
Neo4j is used for GraphRAG feature - knowledge graph storage and querying.
Equivalent to: docker compose --profile neo4j
*/}}
{{- if .Values.neo4j.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "weknora.fullname" . }}-neo4j
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "graph" "context" .) | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
{{- include "weknora.componentSelectorLabels" (dict "component" "graph" "context" .) | nindent 6 }}
# Use Recreate strategy for database to avoid data corruption
strategy:
type: Recreate
template:
metadata:
labels:
{{- include "weknora.componentSelectorLabels" (dict "component" "graph" "context" .) | nindent 8 }}
spec:
{{- include "weknora.imagePullSecrets" . | nindent 6 }}
serviceAccountName: {{ include "weknora.serviceAccountName" . }}
{{- with .Values.global.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: neo4j
image: {{ include "weknora.neo4j.image" . }}
imagePullPolicy: IfNotPresent
{{- with .Values.neo4j.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- containerPort: 7474
name: http
protocol: TCP
- containerPort: 7687
name: bolt
protocol: TCP
env:
# Neo4j 5.0+ requires admin username to be "neo4j"
- name: NEO4J_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: NEO4J_PASSWORD
- name: NEO4J_AUTH
value: "neo4j/$(NEO4J_PASSWORD)"
# Disable strict validation to avoid conflict with K8s injected env vars
# (K8s injects NEO4J_PORT_* from Service named "neo4j")
- name: NEO4J_server_config_strict__validation_enabled
value: "false"
# APOC plugin configuration
- name: NEO4J_apoc_export_file_enabled
value: "true"
- name: NEO4J_apoc_import_file_enabled
value: "true"
- name: NEO4J_apoc_import_file_use__neo4j__config
value: "true"
- name: NEO4J_PLUGINS
value: '["apoc"]'
volumeMounts:
- name: neo4j-data
mountPath: /data
resources:
{{- toYaml .Values.neo4j.resources | nindent 12 }}
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumes:
- name: neo4j-data
{{- if .Values.neo4j.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.neo4j.persistence.existingClaim | default (printf "%s-neo4j" (include "weknora.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- with .Values.neo4j.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.neo4j.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.neo4j.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
# Service name must be "neo4j" - app references this
name: neo4j
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "graph" "context" .) | nindent 4 }}
spec:
type: ClusterIP
selector:
{{- include "weknora.componentSelectorLabels" (dict "component" "graph" "context" .) | nindent 4 }}
ports:
- name: http
port: 7474
targetPort: http
protocol: TCP
- name: bolt
port: 7687
targetPort: bolt
protocol: TCP
{{- end }}
+128
View File
@@ -0,0 +1,128 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
PostgreSQL (ParadeDB) Deployment and Service.
ParadeDB provides vector search and BM25 full-text search capabilities.
*/}}
{{- if .Values.postgresql.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "weknora.fullname" . }}-postgres
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "database" "context" .) | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
{{- include "weknora.componentSelectorLabels" (dict "component" "database" "context" .) | nindent 6 }}
# Use Recreate strategy for database to avoid data corruption
strategy:
type: Recreate
template:
metadata:
labels:
{{- include "weknora.componentSelectorLabels" (dict "component" "database" "context" .) | nindent 8 }}
spec:
{{- include "weknora.imagePullSecrets" . | nindent 6 }}
serviceAccountName: {{ include "weknora.serviceAccountName" . }}
{{- with .Values.global.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: postgres
image: {{ include "weknora.postgresql.image" . }}
imagePullPolicy: IfNotPresent
{{- with .Values.postgresql.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- containerPort: 5432
name: postgresql
protocol: TCP
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: DB_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: DB_PASSWORD
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: DB_NAME
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
{{- toYaml .Values.postgresql.resources | nindent 12 }}
livenessProbe:
exec:
command:
- pg_isready
- -U
- postgres
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
readinessProbe:
exec:
command:
- pg_isready
- -U
- postgres
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumes:
- name: postgres-data
{{- if .Values.postgresql.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.postgresql.persistence.existingClaim | default (printf "%s-postgres" (include "weknora.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- with .Values.postgresql.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.postgresql.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.postgresql.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
# Service name must be "postgres" - app references this
name: postgres
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "database" "context" .) | nindent 4 }}
spec:
type: ClusterIP
selector:
{{- include "weknora.componentSelectorLabels" (dict "component" "database" "context" .) | nindent 4 }}
ports:
- name: postgresql
port: 5432
targetPort: postgresql
protocol: TCP
{{- end }}
+81
View File
@@ -0,0 +1,81 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
Persistent Volume Claims for stateful components.
*/}}
{{/* PostgreSQL PVC */}}
{{- if and .Values.postgresql.enabled .Values.postgresql.persistence.enabled (not .Values.postgresql.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "weknora.fullname" . }}-postgres
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "database" "context" .) | nindent 4 }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.postgresql.persistence.size }}
{{- include "weknora.storageClass" . | nindent 2 }}
---
{{- end }}
{{/* Redis PVC */}}
{{- if and .Values.redis.enabled .Values.redis.persistence.enabled (not .Values.redis.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "weknora.fullname" . }}-redis
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "cache" "context" .) | nindent 4 }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.redis.persistence.size }}
{{- include "weknora.storageClass" . | nindent 2 }}
---
{{- end }}
{{/* Neo4j PVC */}}
{{- if and .Values.neo4j.enabled .Values.neo4j.persistence.enabled (not .Values.neo4j.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "weknora.fullname" . }}-neo4j
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "graph" "context" .) | nindent 4 }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.neo4j.persistence.size }}
{{- include "weknora.storageClass" . | nindent 2 }}
---
{{- end }}
{{/* Data Files PVC */}}
{{- if and .Values.dataFiles.persistence.enabled (not .Values.dataFiles.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "weknora.fullname" . }}-data-files
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "storage" "context" .) | nindent 4 }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.dataFiles.persistence.size }}
{{- include "weknora.storageClass" . | nindent 2 }}
{{- end }}
+124
View File
@@ -0,0 +1,124 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
Redis Deployment and Service.
Redis is used for stream management and async task queuing.
*/}}
{{- if .Values.redis.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "weknora.fullname" . }}-redis
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "cache" "context" .) | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
{{- include "weknora.componentSelectorLabels" (dict "component" "cache" "context" .) | nindent 6 }}
# Use Recreate strategy to avoid data corruption
strategy:
type: Recreate
template:
metadata:
labels:
{{- include "weknora.componentSelectorLabels" (dict "component" "cache" "context" .) | nindent 8 }}
spec:
{{- include "weknora.imagePullSecrets" . | nindent 6 }}
serviceAccountName: {{ include "weknora.serviceAccountName" . }}
{{- with .Values.global.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: redis
image: {{ include "weknora.redis.image" . }}
imagePullPolicy: IfNotPresent
{{- with .Values.redis.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
command:
- redis-server
- --requirepass
- $(REDIS_PASSWORD)
- --appendonly
- "yes"
- --dir
- /data
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "weknora.secretName" . }}
key: REDIS_PASSWORD
ports:
- containerPort: 6379
name: redis
protocol: TCP
volumeMounts:
- name: redis-data
mountPath: /data
resources:
{{- toYaml .Values.redis.resources | nindent 12 }}
livenessProbe:
exec:
command:
- sh
- -c
- redis-cli -a $REDIS_PASSWORD ping | grep PONG
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- sh
- -c
- redis-cli -a $REDIS_PASSWORD ping | grep PONG
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumes:
- name: redis-data
{{- if .Values.redis.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.redis.persistence.existingClaim | default (printf "%s-redis" (include "weknora.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- with .Values.redis.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.redis.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.redis.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
# Service name must be "redis" - app references this
name: redis
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.componentLabels" (dict "component" "cache" "context" .) | nindent 4 }}
spec:
type: ClusterIP
selector:
{{- include "weknora.componentSelectorLabels" (dict "component" "cache" "context" .) | nindent 4 }}
ports:
- name: redis
port: 6379
targetPort: redis
protocol: TCP
{{- end }}
+56
View File
@@ -0,0 +1,56 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
Secrets for WeKnora components.
IMPORTANT: For production deployments, use one of these approaches:
1. Set values via --set flags during installation
2. Use External Secrets Operator with cloud secret managers
3. Use sealed-secrets for GitOps workflows
4. Provide an existing secret via secrets.existingSecret
*/}}
{{- if not .Values.secrets.existingSecret }}
{{/*
Reuse the previously generated random keys on upgrade. Without this lookup,
randAlphaNum would re-roll on every `helm upgrade` and rotate SYSTEM_AES_KEY,
making any data encrypted with the old key unreadable
(e.g. tenants.api_key would surface as enc:v1:... in the UI).
*/}}
{{- $secretName := include "weknora.secretName" . }}
{{- $existing := lookup "v1" "Secret" .Release.Namespace $secretName }}
{{- $existingSystemKey := "" }}
{{- if and $existing $existing.data }}
{{- if index $existing.data "SYSTEM_AES_KEY" }}
{{- $existingSystemKey = index $existing.data "SYSTEM_AES_KEY" | b64dec }}
{{- end }}
{{- end }}
{{- $systemAesKey := .Values.secrets.systemAesKey | default $existingSystemKey | default (randAlphaNum 32) }}
apiVersion: v1
kind: Secret
metadata:
name: {{ $secretName }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.labels" . | nindent 4 }}
type: Opaque
stringData:
# Database credentials
DB_USER: {{ .Values.secrets.dbUser | quote }}
DB_PASSWORD: {{ required "secrets.dbPassword is required" .Values.secrets.dbPassword | quote }}
DB_NAME: {{ .Values.secrets.dbName | quote }}
# Redis credentials
REDIS_USERNAME: {{ .Values.secrets.redisUsername | default "" | quote }}
REDIS_PASSWORD: {{ required "secrets.redisPassword is required" .Values.secrets.redisPassword | quote }}
# Application secrets
JWT_SECRET: {{ required "secrets.jwtSecret is required" .Values.secrets.jwtSecret | quote }}
# SYSTEM_AES_KEY 加密:tenants.api_key、模型 API key、向量库凭证、web search provider key、
# WeKnoraCloud.AppSecret 等。(TENANT_AES_KEY 已废弃:v0.4.0 起加密统一用 SYSTEM_AES_KEY,
# Go 主应用不再读取 TENANT_AES_KEY,已从 Secret 中移除。)
SYSTEM_AES_KEY: {{ $systemAesKey | quote }}
{{- if .Values.neo4j.enabled }}
# Neo4j credentials (for GraphRAG)
NEO4J_USERNAME: {{ .Values.neo4j.username | quote }}
NEO4J_PASSWORD: {{ required "neo4j.password is required when neo4j is enabled" .Values.neo4j.password | quote }}
{{- end }}
{{- end }}
+24
View File
@@ -0,0 +1,24 @@
{{/*
Copyright 2025 Tencent
SPDX-License-Identifier: MIT
ServiceAccount for WeKnora components.
Ref: https://helm.sh/docs/chart_best_practices/rbac/
*/}}
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "weknora.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "weknora.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}