Langfuse 部署指南(含生产 checklist)
面向测试/生产环境部署 Langfuse 自托管实例,让 Manager 的 trace 列表与 Hermes 引擎 trace 接入。本页沉淀了测试环境(43.107.54.223)部署踩过的全部坑与生产一次性 checklist,避免重复折腾。
排障要点(历史实录沉淀):
- 写入
api_keys的密钥必须是 bcrypt 哈希(bcrypt.hash(sk, 11)),手工 SQL 塞 sha256 hex 会导致bcrypt.compare必挂、接口 401。- 不要 curl
124.243.186.4——那是另一台也跑着 Langfuse 的机器,不是本 k3s 实例;本机公网 IP 是43.107.54.223。- MinIO 缺
langfuse-events/langfuse-mediabucket 会导致 POST trace 500(Failed to upload events to blob storage)。- Gateway 走
LANGFUSE_*env(无UA_前缀),改 key 后必须rollout restart才生效。
用途与架构
Langfuse 在 VeyraOS 中承担可观测性数据接入,分两套独立接线:
| 消费方 | 接线方式 | 认证 |
|---|---|---|
Manager(langfuse_client.list_traces) | UA_LANGFUSE_* → 读 veyraos/langfuse-secret | HTTP Basic Auth(pk:sk 对 /api/public/traces) |
| Gateway(链路追踪列表对外 trace 的唯一来源) | LANGFUSE_*(注意不是 UA_ 前缀)→ 读 veyraos/langfuse-secret | 同上 |
Hermes 引擎(observability/langfuse 插件) | veyraos-secret 的 hermes-langfuse-* → 注入 HERMES_LANGFUSE_* env → 插件自动启用 | 同上 |
| Dify 外接引擎用量采集 | 引擎详情页「可观测纳管」开关开启时,Manager 复用全局 UA_LANGFUSE_* 凭据拉取该引擎的 trace | 同上 |
- 测试环境集群内地址:
http://langfuse.monitoring:3000(ClusterIP),对外 NodePort30030(默认未对公网放行)。 - 引擎侧:Hermes 配置(
/root/.hermes/config.yaml)中plugins.enabled含observability/langfuse即启用;插件读取HERMES_LANGFUSE_*env。 - 版本:镜像 tag 用
langfuse/langfuse:3(浮动)实际拉取到具体版本(测试环境为 3.225.7)。
部署资源
deploy/k8s/infra/monitoring/ 下 4 个清单,按顺序 apply 到 monitoring 命名空间:
| 组件 | 清单 | 说明 |
|---|---|---|
| namespace | namespace.yaml | monitoring ns |
| Redis | redis.yaml | requirepass 硬编码在清单(本地开发占位,生产必须改) |
| ClickHouse | clickhouse.yaml | StatefulSet,20Gi PVC,密码走 langfuse-secret.clickhouse-password |
| Langfuse | langfuse.yaml | deploy/langfuse + deploy/langfuse-worker,NodePort 30030 |
镜像拉取坑(本地 k3s):官方
library/镜像直 pull 会insufficient_scope。先sudo k3s ctr images pull docker.m.daocloud.io/library/redis:7-alpine再 re-tag 成官方名。
Secrets 接线
真实凭据只放服务器 k8s Secret,仓库清单只留占位符:
| Secret | 关键 key | 消费方 |
|---|---|---|
monitoring/langfuse-secret | nextauth-secret / salt / encryption-key / langfuse-database-url / clickhouse-password / s3-access-key-id / s3-secret-access-key / redis-* | langfuse / langfuse-worker pod |
veyraos/langfuse-secret | langfuse-public-key / langfuse-secret-key | Manager(secretKeyRef) |
veyraos-secret | hermes-langfuse-base-url / hermes-langfuse-public-key / hermes-langfuse-secret-key | Hermes 引擎 pod(secretKeyRef) |
生产部署 checklist
阶段一:部署前
- [ ] pin 版本 tag:
langfuse/langfuse:3是浮动 tag,跨环境会漂移。生产用固定版本,如langfuse/langfuse:3.225.7,langfuse-worker同版本。 - [ ] 内存 limit ≥ 2Gi:
NODE_OPTIONS=--max-old-space-size=1536+ 1Gi limit 会 OOMKilled 崩溃循环。 - [ ] 强随机密钥:
nextauth-secret(64 位 hex)/salt(32 位 hex)/encryption-key(64 位 hex)/ Redis requirepass 全部用随机值,仓库只留占位符。 - [ ] 预建 MinIO bucket:
langfuse-events/langfuse-media。配了 S3 事件上传就必须有 bucket,否则 POST trace 500。- 不依赖对象存储的话,不设
LANGFUSE_S3_EVENT_UPLOAD_*env 即可(trace 直进 ClickHouse;代价:文件/媒体附件上传也不可用)。 - MinIO 必须
forcePathStyle=true+ regionus-east-1。
- 不依赖对象存储的话,不设
- [ ] NEXTAUTH_URL 指向真实对外地址:域名或公网 IP+端口,且该地址对浏览器/服务真实可达。
- [ ] 网络入口:生产建议 Ingress + TLS,优于裸 NodePort(测试环境 NodePort 未对公网放行,只能集群内访问)。
- [ ] ClickHouse PVC 容量:按 trace 量评估(测试用了 20Gi)。
- [ ] 依赖组件:确认 manager 的
prometheus.monitoring探测目标存在或可关闭(未部署 Prometheus 时 manager 会周期性打 DNS 告警,不影响 Langfuse)。
阶段二:初始化账号与 API Key
不要手搓 SQL 建 API key
api_keys.hashed_secret_key 必须是 bcrypt.hash(sk, 11)(bcryptjs@2.4.3,rounds=11),不是 sha256。Langfuse 校验走 bcrypt.compare,fast_hashed_secret_key = sha256(sk || hex(sha256(SALT))) 只是加速索引。手搓 SQL 必挂且难排查。
- [ ] 临时
AUTH_DISABLE_SIGNUP=false+kubectl rollout restart deploy/langfuse(放行注册)。 - [ ] 注册首个账号(self-hosted 无 SMTP 时本地注册即可):
- 浏览器走 UI 注册;或 curl 走 NextAuth:
GET /api/auth/csrf→POST /api/auth/signup→POST /api/auth/callback/credentials。
- 浏览器走 UI 注册;或 curl 走 NextAuth:
- [ ] 建 project + API key(二选一):
- 官方路径:UI → Settings → API Keys → New API Key(key 只显示一次,立即落 secret)。
- 脚本路径:pod 内 node 复刻
createAndAddApiKeysToDb(bcrypt.hash(sk,11) + fast hash + displaySecretKey),用应用自身 PrismaClient 建 org/project/key。参考脚本:测试会话~/.claude/jobs/6344f9ec/tmp/lf-create-keys.js(已验证可用)。 - ⚠️
POST /api/admin/organizations在 OSS self-hosted 被 plan 门控 → 403,不可依赖管理 API。
- [ ] key 写入两个 secret:
veyraos/langfuse-secret+veyraos-secret的hermes-langfuse-*。 - [ ]
kubectl rollout restart所有消费方:manager + gateway(LANGFUSE_*env,易漏)+ 所有engine-hermes-*deploy。- ⚠️ secretKeyRef env 只在 pod 启动时读取;且
optional:true时如果 key 当时不存在,pod 拿到空值且不会自动补——新增 key 后必须重启旧 pod。
- ⚠️ secretKeyRef env 只在 pod 启动时读取;且
- [ ] 恢复
AUTH_DISABLE_SIGNUP=true+rollout restartlangfuse(锁注册)。 - [ ] 移除临时
ADMIN_API_KEYenv(若加过)。
阶段三:验证(从集群内打 langfuse.monitoring:3000)
bash
# 健康(核对版本号,避免打错实例)
curl -s http://langfuse.monitoring:3000/api/public/health
# {"status":"OK","version":"3.225.7"}
# 认证冒烟(应 200)
curl -s -u "<pk>:<sk>" "http://langfuse.monitoring:3000/api/public/traces?limit=1"
# 注入冒烟(应 200 且能查回)
curl -s -u "<pk>:<sk>" -X POST "http://langfuse.monitoring:3000/api/public/traces" \
-H "Content-Type: application/json" \
-d '{"name":"smoke","input":"hello","output":"world"}'
sleep 5
curl -s -u "<pk>:<sk>" "http://langfuse.monitoring:3000/api/public/traces?limit=5"
# Manager 路径(进 manager pod 验证与 list_traces 同路径)
kubectl exec deploy/manager -n veyraos -- sh -c \
'curl -s -u "<pk>:<sk>" "http://langfuse.monitoring:3000/api/public/traces?limit=1"'
# Hermes 路径(确认插件已启用 + env 注入)
kubectl exec <engine-pod> -n veyraos -- sh -c 'env | grep -i langfuse'
kubectl exec <engine-pod> -n veyraos -- sh -c 'grep -A2 enabled /root/.hermes/config.yaml'- [ ] 以上全绿后,跑一次真实会话确认 Hermes trace 落库。
踩坑速查
| 坑 | 症状 | 根因 | 规避 |
|---|---|---|---|
| 手搓 SQL 建 key | 认证永远 401 | hashed_secret_key 非 bcrypt | 走官方注册/脚本路径 |
| 外网 IP 打错实例 | 本机 200 / "外网" 401 像抖动 | 目标 IP 是另一台机器 | 用健康响应版本号交叉验证目标 |
| 改 secret 不生效 | 服务还在用旧值 | secretKeyRef 只在 pod 启动读取 | 改完必 rollout restart |
| 新 key 注入空值 | engine env 变量存在但为空 | optional:true + key 当时不存在 | 重启旧 pod |
| 链路列表空但 Langfuse 有数据 | 对话有 "Hermes turn" 但链路列表无 | gateway 的 LANGFUSE_* key 为空(pod 创建于接线前未重启)——链路列表只展示 gateway 对外 trace | 重启所有消费方(含 gateway) |
| OOM 崩溃循环 | pod 反复 OOMKilled | heap 1536MB + 1Gi limit | limit ≥ 2Gi |
| 缺 MinIO bucket | POST trace 500 | S3 事件上传强依赖 bucket | 预建两个 bucket |
| 镜像拉取失败 | insufficient_scope | 官方镜像网络受限 | daocloud 代理拉取再 re-tag |
| signup 锁死 | 无法注册 | AUTH_DISABLE_SIGNUP=true | 初始化窗口临时 false |
DB 维护姿势
bash
# psql 脚本:host 侧重定向进 pod stdin,勿在 pod 里 -f /tmp/...
sudo kubectl exec -i postgres-0 -n veyraos -- env PGPASSWORD='<pg密码>' \
psql -U veyraos -d langfuse -f - < /tmp/xxx.sql
# DROP DATABASE 被占用:先缩容 worker,清连接,再 DROP
sudo kubectl scale deploy/langfuse-worker -n monitoring --replicas=0
# pg_terminate_backend 清连接后 DROP+CREATE相关文档
- 历史排障要点已沉淀在本文顶部「排障要点」处(原排查实录已归档,见 git 历史)
- 部署清单:
deploy/k8s/infra/monitoring/