# Production values for the `langfuse` ArgoCD Application (upstream # `langfuse/langfuse-k8s` chart, not this repo's own medical-chatbot chart). # # Runs in the `medical-chatbot-data` namespace deliberately, not its own — # that is the only namespace holding the K8s Secret with the shared Postgres # password, and Secrets don't cross namespaces. Langfuse never reads that # password directly: everything below points at the secret BY NAME/KEY # (`medical-chatbot-data-medical-chatbot-runtime` / `postgres-password`), the # same way infra/helm/medical-chatbot's own templates do it. # # Deliberately bundled rather than external: Redis and ClickHouse (personal- # scale traffic, no case for a managed service here). Deliberately external: # Postgres (reuse what already exists rather than a second instance) and S3 # (a real bucket, `duocthu-langfuse-blobs`, reached via the k3s node's IAM # instance role — no static access keys anywhere in this file or the cluster, # same pattern as ai-service's Bedrock access). # # SALT / ENCRYPTION_KEY / NEXTAUTH_SECRET are deliberately absent: the chart # auto-generates and persists them in a release-managed Secret on first # install when left unset. No manual secret entry needed for this file. langfuse: # 512Mi crashed both web and worker with "JavaScript heap out of memory" # right after a clean Postgres+ClickHouse connect and Next.js "Ready" -- # Node sizes its heap off the container memory limit, and 512Mi wasn't # enough headroom above the actual app. Bumped once, empirically, after # confirming live on 2026-08-21; revisit if it still OOMs under real load. resources: requests: { cpu: 200m, memory: 512Mi } limits: { cpu: "1", memory: 2Gi } ingress: enabled: true className: traefik hosts: - host: langfuse.realvuxbaro.me paths: - path: / pathType: ImplementationSpecific annotations: cert-manager.io/cluster-issuer: letsencrypt-prod traefik.ingress.kubernetes.io/router.entrypoints: websecure tls: enabled: true secretName: langfuse-tls nextauth: url: https://langfuse.realvuxbaro.me postgresql: deploy: false host: medical-chatbot-data-medical-chatbot-postgres.medical-chatbot-data.svc.cluster.local port: 5432 auth: username: duoc_thu existingSecret: medical-chatbot-data-medical-chatbot-runtime secretKeys: userPasswordKey: postgres-password database: langfuse redis: deploy: true resources: requests: { cpu: 50m, memory: 64Mi } limits: { cpu: 250m, memory: 256Mi } clickhouse: deploy: true cluster: enabled: false storage: size: 20Gi s3: deploy: false storageProvider: s3 bucket: duocthu-langfuse-blobs region: us-east-1 endpoint: https://s3.us-east-1.amazonaws.com forcePathStyle: false # Both left empty on purpose: falls back to the AWS SDK default credential # chain, which picks up the node's IAM instance role automatically. accessKeyId: value: "" secretAccessKey: value: "" # One-off Job that creates the `langfuse` database on the existing Postgres # instance before Langfuse's own migration runs. Idempotent (checks first). # Never touches infra/helm/medical-chatbot's own templates or its release. extraManifests: - apiVersion: batch/v1 kind: Job metadata: name: langfuse-db-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-weight": "-5" "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded spec: backoffLimit: 3 template: spec: restartPolicy: Never containers: - name: create-db image: postgres:16-alpine env: - name: PGPASSWORD valueFrom: secretKeyRef: name: medical-chatbot-data-medical-chatbot-runtime key: postgres-password command: ["sh", "-c"] args: - | set -e HOST=medical-chatbot-data-medical-chatbot-postgres.medical-chatbot-data.svc.cluster.local EXISTS=$(psql "postgresql://duoc_thu@$HOST:5432/duoc_thu" -tAc \ "SELECT 1 FROM pg_database WHERE datname = 'langfuse'") if [ "$EXISTS" != "1" ]; then psql "postgresql://duoc_thu@$HOST:5432/duoc_thu" -c "CREATE DATABASE langfuse OWNER duoc_thu" fi