概述
本文整理了一套 Langfuse 基于 Kubernetes 与 Helm 的部署方法,覆盖以下主题:
- Helm Chart 自定义配置方式
- 中国区镜像拉取加速思路
- 内置 PostgreSQL、Redis、ClickHouse、MinIO 的配置逻辑
hostPath + PV/PVC持久化方案NodePort暴露方式- 基于节点主机名的调度约束
- 常见启动报错排查方法
- 无海外网络环境下的离线部署思路
内容基于单机或小规模测试环境展开。若用于生产环境,建议将数据库、对象存储与分析存储迁移为独立托管服务或可靠的分布式存储方案。
Helm Chart 的自定义方式
Langfuse 官方提供 Helm Chart 进行 Kubernetes 部署,主要自定义入口为 values.yaml。
常见配置分类如下:
langfuse.*:应用自身配置,例如nextauth、salt、encryptionKey、ingress、resourcespostgresql.*:内置 PostgreSQL 或外部 PostgreSQL 连接配置redis.*:内置 Valkey/Redis 或外部 Redis 配置clickhouse.*:内置或外部 ClickHouse 配置s3.*:内置 MinIO 或外部对象存储配置global.*:全局镜像、存储类等通用配置
基础安装命令如下:
helm repo add langfuse https://langfuse.github.io/langfuse-k8s
helm repo update
helm install langfuse langfuse/langfuse -n langfuse -f values.yaml
升级命令如下:
helm upgrade langfuse langfuse/langfuse -n langfuse -f values.yaml
若使用本地离线 Chart 目录,可改为:
helm upgrade --install langfuse . -n langfuse -f values.yaml
镜像源地址与中国区拉取加速
Langfuse Helm Chart 涉及多组镜像:
langfuse/langfuselangfuse/langfuse-workerbitnamilegacy/postgresqlbitnamilegacy/valkeybitnamilegacy/clickhousebitnamilegacy/miniobitnamilegacy/zookeeper(部分场景会出现)
推荐方案为:先将镜像同步到内网 Harbor、企业 ACR、TCR 或其他私有镜像仓库,再在 values.yaml 中覆盖镜像仓库地址。
示例:
langfuse:
web:
image:
repository: harbor.example.local/library/langfuse
tag: "3.169.0"
worker:
image:
repository: harbor.example.local/library/langfuse-worker
tag: "3.169.0"
postgresql:
image:
repository: harbor.example.local/library/postgresql
redis:
image:
repository: harbor.example.local/library/valkey
clickhouse:
image:
repository: harbor.example.local/library/clickhouse
zookeeper:
image:
repository: harbor.example.local/library/zookeeper
s3:
image:
repository: harbor.example.local/library/minio
如私有仓库需要认证,可创建 imagePullSecrets 并在 values.yaml 中引用。
values.yaml 中账号密码的作用
values.yaml 中的账号密码主要分为两类:
内置依赖组件的启动参数
当以下配置为 true 时,Helm Chart 会一并部署对应组件:
postgresql:
deploy: true
redis:
deploy: true
clickhouse:
deploy: true
s3:
deploy: true
此时配置的用户名、密码会被用于:
- 创建内置 PostgreSQL 用户与数据库
- 初始化内置 Valkey/Redis 密码
- 初始化内置 ClickHouse 用户密码
- 初始化内置 MinIO root 用户与密码
- 向 Langfuse Web 与 Worker 注入连接信息
外部依赖组件的连接参数
当 deploy: false 时,相关账号密码不再用于创建组件,而是用于连接外部服务。
例如:
postgresql.auth.password:外部 PostgreSQL 密码redis.auth.password:外部 Redis 密码s3.accessKeyId/s3.secretAccessKey:外部对象存储访问密钥
Langfuse 自身的重要密钥
以下配置不是数据库密码,而是 Langfuse 应用自身的关键安全参数:
langfuse.saltlangfuse.encryptionKeylangfuse.nextauth.secret
其中 encryptionKey 要求最严格,必须是 64 位十六进制字符串,生成方式如下:
openssl rand -hex 32
若格式不正确,web 或 worker 会直接启动失败,并出现类似以下报错:
ENCRYPTION_KEY must be 256 bits, 64 string characters in hex format
无 PVC 场景下的持久化方案
若集群中没有可直接使用的动态存储类,且部署场景为单机或测试环境,可采用 hostPath + PV/PVC 方案。
这一方案的核心逻辑不是在 Pod 里直接写 hostPath,而是:
- 创建
PersistentVolume - 使用
hostPath作为 PV 后端目录 - 创建
PersistentVolumeClaim - 在
values.yaml中通过existingClaim引用 PVC
示例:PostgreSQL 的 PV/PVC
apiVersion: v1
kind: PersistentVolume
metadata:
name: langfuse-postgres-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual-hostpath
hostPath:
path: /data/langfuse/postgresql
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: langfuse-postgres-pvc
namespace: langfuse
spec:
accessModes:
- ReadWriteOnce
storageClassName: manual-hostpath
resources:
requests:
storage: 20Gi
volumeName: langfuse-postgres-pv
在 values.yaml 中引用 PVC
postgresql:
primary:
persistence:
enabled: true
existingClaim: langfuse-postgres-pvc
Redis、ClickHouse、MinIO 的写法与此类似。
hostPath 的局限性
hostPath 的本质是节点本地磁盘目录,因此存在明显限制:
- Pod 在同一节点重建,数据仍可保留
- Pod 漂移到其他节点,本地数据不会随 Pod 迁移
- 多节点环境下,若未限制调度,极易出现“卷已绑定,但数据不在当前节点”的问题
因此,hostPath 仅适用于:
- 单机 Kubernetes
- 测试环境
- 明确固定状态组件到指定节点的场景
若需支持跨节点迁移,应使用网络存储、云盘 CSI、NFS、Longhorn、Ceph 等方案。
NodePort 部署方式
若不使用 Ingress,可将 Langfuse Web 服务改为 NodePort 暴露。
示例:
langfuse:
nextauth:
url: http://192.168.1.150:30080
secret:
value: "replace-with-a-random-secret"
salt:
value: "replace-with-a-random-salt"
encryptionKey:
value: "replace-with-64-hex-string"
web:
service:
type: NodePort
port: 3000
externalPort: 3000
nodePort: 30080
部署后可通过以下地址访问:
http://<节点IP>:30080
基于主机名的节点调度约束
由于 hostPath 与节点本地磁盘绑定,状态组件必须通过调度约束固定在同一台节点上。
推荐使用 nodeAffinity 的 matchExpressions + In 方式,按 kubernetes.io/hostname 约束。
示例:
postgresql:
primary:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
Redis、ClickHouse、MinIO 均建议增加类似约束。
特点如下:
- 目标节点可用时,Pod 固定落在指定节点
- 目标节点不可用时,Pod 会保持
Pending - 与其错误漂移到其他节点挂错数据盘,
Pending更安全
首次访问时的登录行为
Langfuse 页面中出现的登录界面并不是来自数据库或对象存储密码。
values.yaml 中配置的以下密码:
- PostgreSQL 密码
- Redis 密码
- ClickHouse 密码
- MinIO root 密码
仅用于后端组件初始化或连接,不用于 Web 登录。
Langfuse 默认不会预置管理员账号,首次使用通常需要通过页面注册创建账号。
若页面不允许注册,应检查:
langfuse:
features:
signUpDisabled: false
常见报错与排查方法
1. Redis/Valkey 启动失败
典型日志:
Can't open or create append-only dir appendonlydir: Permission denied
这类问题通常与 hostPath 目录权限有关。Bitnami Valkey 镜像默认以非 root 用户运行,宿主机目录若无写权限,容器会直接退出。
修复方法示例:
mkdir -p /data/langfuse/redis
chown -R 1001:1001 /data/langfuse/redis
chmod -R 755 /data/langfuse/redis
kubectl delete pod -n langfuse langfuse-redis-primary-0
测试环境中,为快速验证,也可临时使用:
chmod -R 777 /data/langfuse
2. Worker/Web 因 ENCRYPTION_KEY 格式错误启动失败
典型日志:
ENCRYPTION_KEY must be 256 bits, 64 string characters in hex format
修复方式:重新生成合法密钥,并更新 values.yaml。
openssl rand -hex 32
3. Zookeeper Pod 长期 Pending
典型事件:
pod has unbound immediate PersistentVolumeClaims
这通常说明:
- Zookeeper 仍被 Chart 拉起
- 对应 PVC 未准备完成
- 或
zookeeper.enabled未真正关闭
在单机、单副本 ClickHouse 场景下,通常无需额外运行 Zookeeper,应重点检查 values.yaml 是否真正关闭相关组件。
一个可工作的核心 values 结构
以下结构适用于单机测试环境的基本思路:
global:
security:
allowInsecureImages: true
langfuse:
nextauth:
url: http://192.168.1.150:30080
secret:
value: "replace-with-base64-secret"
salt:
value: "replace-with-base64-salt"
encryptionKey:
value: "replace-with-64-hex-string"
web:
service:
type: NodePort
port: 3000
externalPort: 3000
nodePort: 30080
postgresql:
deploy: true
auth:
username: langfuse
password: "replace-with-postgres-password"
database: langfuse
primary:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
persistence:
enabled: true
existingClaim: langfuse-postgres-pvc
redis:
deploy: true
auth:
username: langfuse
password: "replace-with-redis-password"
database: 0
primary:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
extraFlags:
- --maxmemory-policy noeviction
persistence:
enabled: true
existingClaim: langfuse-redis-pvc
clickhouse:
deploy: true
auth:
username: langfuse
password: "replace-with-clickhouse-password"
shards: 1
replicaCount: 1
clusterEnabled: false
keeper:
enabled: false
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
persistence:
enabled: true
existingClaim: langfuse-clickhouse-pvc
s3:
deploy: true
auth:
rootUser: minio
rootPassword: "replace-with-minio-password"
defaultBuckets: langfuse
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
persistence:
enabled: true
existingClaim: langfuse-minio-pvc
部署命令顺序
完整部署流程建议如下:
kubectl create namespace langfuse
kubectl apply -f storage.yaml
kubectl get pv
kubectl get pvc -n langfuse
helm upgrade --install langfuse . -n langfuse -f values.yaml
kubectl get pods -n langfuse -o wide
若需查看渲染结果,可先执行:
helm template langfuse . -n langfuse -f values.yaml
无海外网络环境下的离线部署方案
无海外网络权限时,Helm 与镜像拉取需分开处理。
1. 离线准备 Helm Chart
在可访问外网的中转环境执行:
helm repo add langfuse https://langfuse.github.io/langfuse-k8s
helm repo update
helm pull langfuse/langfuse --untar
helm dependency build ./langfuse
tar czf langfuse-chart-offline.tar.gz langfuse
将 langfuse-chart-offline.tar.gz 传入内网环境后解压。
若解压目录中已存在以下内容,通常说明 Chart 依赖已经准备齐全:
Chart.yamlChart.lockcharts/templates/
此时不必再次执行错误的命令:
helm dependency build langfuse
若当前目录已经是 Chart 根目录,正确写法应为:
helm dependency build .
或者直接安装:
helm upgrade --install langfuse . -n langfuse -f values.yaml
2. 离线准备镜像
即使本地 Chart 已经完整,若 Kubernetes 节点无法访问海外镜像仓库,Pod 仍然无法启动。因此必须提前准备镜像。
推荐方式如下:
- 在外网中转环境拉取所需镜像
- 同步到内网 Harbor 或其他私有镜像仓库
- 在
values.yaml中将镜像仓库地址全部替换为内网地址
需要重点处理的镜像通常包括:
langfuse/langfuselangfuse/langfuse-workerbitnamilegacy/postgresqlbitnamilegacy/valkeybitnamilegacy/clickhousebitnamilegacy/miniobitnamilegacy/zookeeper(若仍有该组件)
若集群已成功安装一次,可通过以下命令反查实际镜像列表:
kubectl get pods -n langfuse -o jsonpath="{..image}" | tr ' ' '\n' | sort -u
3. 离线机器上如何部署本地 Helm Chart
离线机器即使没有配置 Helm 仓库,也可以完成部署。前提是以下内容已经准备完成:
- Helm 二进制可正常使用
- 本地 Chart 目录或已打包的
.tgz文件可用 values.yaml已准备完成- Kubernetes 节点能够获取所需镜像
方式一:直接使用本地 Chart 目录部署
若离线环境中已有完整 Chart 目录,例如:
langfuse/
Chart.yaml
Chart.lock
charts/
templates/
values.yaml
则可直接执行:
helm upgrade --install langfuse ./langfuse -n langfuse -f ./langfuse/values.yaml
这种方式不会访问任何远程 Helm 仓库。
方式二:使用打包后的 tgz 文件部署
在有网环境中完成打包:
helm dependency build ./langfuse
helm package ./langfuse
打包后会得到类似文件:
langfuse-1.5.27.tgz
将 .tgz 文件与 values.yaml 一并传入离线环境后,可直接安装:
helm upgrade --install langfuse ./langfuse-1.5.27.tgz -n langfuse -f values.yaml
同样不会依赖 Helm 仓库。
Chart 依赖的正确前提
离线安装能否成功,关键在于 Chart 依赖是否已被提前打入本地包中。需要满足以下任一条件:
- Chart 目录中已存在
charts/子目录,并且其中包含依赖包 - 在有网环境中已经执行过
helm dependency build ./langfuse
若当前目录已经是 Chart 根目录,则不应执行错误命令:
helm dependency build langfuse
正确写法应为:
helm dependency build .
或者:
helm dependency build ./langfuse
推荐的离线交付内容
更适合内网传递的交付物通常包括:
langfuse-<version>.tgzvalues.yamlstorage.yaml
离线机器上的部署命令示例如下:
kubectl create namespace langfuse
kubectl apply -f storage.yaml
helm upgrade --install langfuse ./langfuse-1.5.27.tgz -n langfuse -f values.yaml
如何确认安装过程不依赖外网
可先在离线机器执行模板渲染:
helm template langfuse ./langfuse-1.5.27.tgz -n langfuse -f values.yaml
若模板渲染成功,说明 Chart 本体及其依赖已经准备完成。
需要注意的是,Chart 本地化仅解决 Helm 仓库问题,并不自动解决镜像拉取问题。若节点无法访问外部镜像仓库,仍需提前完成以下任一方案:
- 将镜像同步到内网 Harbor 或其他私有镜像仓库
- 将镜像直接导入各节点运行时
总结
Langfuse 的 Helm 部署并不复杂,难点主要集中在三处:
- 状态组件的持久化设计
hostPath场景下的节点固定与权限处理- 无海外网络环境下的镜像与 Chart 离线准备
在单机测试环境中,hostPath + PV/PVC + hostname affinity + NodePort 是一套可行方案。该方案部署简单、排错路径清晰,适合快速验证 Langfuse 的功能链路。
在生产环境中,更合理的做法是:
- 采用独立的 PostgreSQL、Redis、对象存储与分析存储
- 使用稳定的网络存储或云盘 CSI
- 使用企业内网镜像仓库统一管理镜像分发
- 通过 Secret 管理敏感配置,而非明文写入
values.yaml
至此,一套从在线部署到离线迁移的 Langfuse Kubernetes Helm 实践路径已基本完整。