Langfuse PR 预览环境(PR Preview)完整指南:从自动化构建、数据注入到 kubectl 调试
2026/9/10 2:44:53 网站建设 项目流程

Langfuse PR 预览环境(PR Preview)完整指南:从自动化构建、数据注入到 kubectl 调试

【免费下载链接】langfuse🪢 Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. 🍊YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse

每个合并到langfuse/langfuse主仓库的 Pull Request 都会自动获得一个一次性的全栈预览环境https://pr-<N>.preview.langfuse.com——web 与 worker 镜像随之构建,Argo CD 负责部署,PR 关闭即整体销毁。本文以仓库内 .agents/skills/langfuse-previews/SKILL.md 为骨架,结合.github/workflows/下的真实工作流与 seeder 源码,完整讲解预览的访问模型、使用流程、数据注入、故障排查与权限开通,帮助你(或你的 coding agent)把预览用成日常开发的一部分。

⚠️ 仅限合成数据(Synthetic data only):预览的登录是共享的、URL 是公开的——永远不要把真实凭据、API Key 或客户数据放进预览。把每个预览都当成一次性的。

访问模型:两道相互独立的门槛

Langfuse 的 PR 预览系统把「构建」与「部署」拆成两个独立决策,任何一道不过关都不会有可用的预览。

第一道:构建——任何拥有写权限的成员

每一个同仓库(same-repo)PR在打开时都会被自动打上preview标签,并构建 web + worker 两个镜像。这里的门槛是写(push)权限——打开同仓库 PR 本身就需要 push 权限。Fork 的 PR 永远不会构建或部署(公开仓库的 PR 无法铸造云凭据,OIDC 信任被限制在sub=repo:langfuse/langfuse:pull_requestref=refs/pull/*)。

从源码看,自动打标签由 .github/workflows/preview-autolabel.yml 完成:

  • 触发器使用普通的pull_request不是pull_request_target):不暴露云凭据、不 checkout、不执行 PR 代码,只做 GitHub API 调用;
  • if: vars.AWS_PREVIEW_ECR_PUSH_ROLE_ARN != ''——该变量同时充当整个预览系统的功能开关,未设置即表示系统关闭,不自动打标签;
  • 脚本第一件事就是检查pr.head.repo.full_name !==${owner}/${repo}``,Fork PR 直接 return,自动打标签仅限于同仓库分支
  • 该工作流还会根据改动文件自动追加api-specstorybook标签,触发 api-spec-preview.yml 与 storybook-preview.yml 两个额外的预览构建。

第二道:部署——基于作者的允许名单

一个预览只有在 PR作者位于部署允许名单上时才会得到真实可访问的 URL。允许名单是 Argo CD ApplicationSet 里的authorselector(位于私有仓库langfuse/infrastructure)。不在名单上?PR 仍然会构建镜像,但 URL 会 404——按下文 Getting access 把自己加进去即可。

构建与部署流水线

真正的构建在 .github/workflows/preview-build.yml 中实现,其设计与 SKILL.md 的描述一一对应:

  • 镜像标签pr-<n>-<full-40-char-sha>。注释明确警告:Argo 的 ApplicationSet 部署pr-<n>-{{.head_sha}}(Argo 的全长 40 位 SHA),所以推送的 tag 必须用完整 SHA,否则部署的镜像永远无法解析,形成永久ImagePullBackOff
  • 并行构建:web 与 worker 是两个独立工件、推送到两个独立 ECR 仓库、同一 tag 下,无顺序依赖,因此在不同 runner 上并行构建metajob 只解析 tag 并发布一次 "building" 评论,矩阵buildjob 并行构建两个镜像,notifyjob 在两者都完成后发布唯一的成功/失败评论。墙钟时间从「两者之和」降为「两者取 max」。
  • web 镜像的构建参数NEXT_PUBLIC_SIGN_UP_DISABLED=false(开放注册,Mailpit 捕获邮件且不转发)、NEXT_PUBLIC_LANGFUSE_CLOUD_REGION=DEV(云区域必须在构建期烘焙进客户端 bundle,预览才能渲染云专属 AI 功能)、NEXT_PUBLIC_PREVIEW_DEMO_AUTO_SIGN_IN=true(共享 demo 身份自动登录)。
  • 幂等性:预览 ECR 仓库是 tag 不可变(tag-immutable)的,重复推送同一 tag 会失败。因此先aws ecr describe-images检查——只有ImageNotFoundException才判定「缺失→构建」;其他任何 describe 失败都大声失败,而不是落入对不可变 tag 的硬失败。

预览环境本身的命名空间是langfuse-pr-<N>,chart 把一切组件都命名为<namespace>-<component>(如langfuse-pr-42-weblangfuse-pr-42-worker),这也是后续所有 kubectl 调试命令的推导基础。

使用一个预览

启动(Spin up)

打开一个同仓库 PR 即可,全自动:

  1. PR 打开即被自动打上preview标签并开始构建(约 5 分钟);
  2. 机器人评论发布预览 URL 与登录信息;
  3. 一行Live preview:会被钉在 PR 描述顶部(拆除时会移除);
  4. 共享的 GitHubPR Preview环境会为该 PR 生成一个View deployment按钮。

从 preview-build.yml 的notifyjob 可以看到三个发布面:marker-tagged 状态评论、原生 GitHub deployment("View deployment" 按钮)、钉在 PR 描述顶部的机器管理块(用<!-- aws-preview-pin:start -->/<!-- aws-preview-pin:end -->隐藏标记包裹,只动自己那段,从不触碰作者在下方写的正文)。

登录

预览会用共享 demo 用户自动登录,直接打开 URL 即可。若要走常规登录流程(例如测试 auth 相关改动),打开/auth/sign-in?autoSignIn=false,使用机器人 PR 评论(唯一事实来源)中的凭据;通过 UI 登出也会落到这个退出登录的表单,直到你下次打开受保护页面。

共享种子身份为demo@langfuse.com/password,API keys 为pk-lf-1234567890/sk-lf-1234567890。这些在源码 packages/shared/scripts/seeder/seed-postgres.ts 与 packages/shared/scripts/seeder/utils/postgres-seed-constants.ts 中都有定义——共享且合成,永远不要把预览当作私有环境。真正的加密机密(ENCRYPTION_KEY/SALT/NEXTAUTH、DB 密码)由 chart 的 pre-sync hook 在集群内随机生成,从不离开命名空间。

从 Linear 打开

任何关联到 PR 的 Linear issue 上,预览位于该 issue 的Preview快捷键之后。Linear 通过解析 PR 描述和机器人评论中标签以 "preview" 结尾的 markdown 链接来构建这个快捷键,所以两个预览面都把链接标成那样(pr-<N> app previewpr-<N> storybook preview)——编辑任一条评论时都要保留这个后缀,否则快捷键会消失。裸 URL 不会被匹配。

读取捕获的邮件

每个预览都有一个命名空间内的 Mailpit SMTP 接收端(邀请、密码重置、批量导出、消费告警、提及都走它),不发送真实邮件。UI 不公开,需要端口转发:

kubectl -n langfuse-pr-<N> port-forward svc/preview-mailpit 8025:8025

然后打开http://localhost:8025

知道你在哪

每个预览页面顶部都有一条条带,链接回对应的 PR,并显示作者与预览内容最后变更时间。这正是 preview-build.yml 在构建 web 镜像时通过NEXT_PUBLIC_PREVIEW_PR_URLNEXT_PUBLIC_PREVIEW_PR_AUTHORNEXT_PUBLIC_PREVIEW_LAST_UPDATED三个构建参数烘焙进客户端 bundle 的 PR 元数据。

更新

推送到 PR 即触发重建并滚动到新镜像(约 5 分钟,URL 不变、数据保留)。重建期间出现短暂的ImagePullBackOff是正常的,会自愈——工作流里的🟡 AWS preview building评论也预告了这一点。

拆除

关闭 PR,或移除preview标签;命名空间、数据与 DNS 记录全部删除。合并会关闭 PR,所以合并同样触发拆除。preview-deactivate.yml 在closed/unlabeled事件下清除该 PR 在共享PR Preview环境中的原生 GitHub deployment 记录,避免 GitHub 继续宣传一个死 URL;真正的资源拆除则由 Argo CD ApplicationSet(只对 open 且带标签的 PR 生成 Application)完成。

另外 preview-stale-cleanup.yml 每天 06:00 UTC 运行一次(也可workflow_dispatch手动触发),把超过stale_days(默认 2 天)无活动的 open PR 上的preview标签移除,从而回收空闲预览。

要点备忘(Good to know)

  • 非工作时间休眠:预览只在欧洲/柏林时间 周一至周五 08:00–24:00运行;夜间和周末缩容到零并保持(是调度驱动的——请求不会唤醒它们)。非工作时间要用,需要集群访问权限去唤醒:

    kubectl annotate ns langfuse-pr-<N> downscaler/force-uptime=true --overwrite

    副本约 60 秒恢复,就绪约 3–5 分钟;之后用尾带-的形式(downscaler/force-uptime-)撤销,让它重新按调度休眠。

  • 容量:同时运行的预览数量有限;集群满时,新预览的 pod 会停在Pending,直到旧预览被关闭。

  • 数据一次性:关闭 PR 即销毁其数据库;重新打开得到的是全新的环境,而不是旧的。

  • Fork 无法预览:外部 / fork PR 从不构建或部署。

在预览中注入或改进数据

预览启动时预置了 demo 项目和一些合成 trace。要注入你正在测试的特定形态——极深的 trace、巨大的 session、用于列表性能的批量 trace、v4 事件、畸形 payload——在你的本地 checkout 上运行确定性的seed CLI,通过port-forward指向预览的数据存储。

前提:需要集群访问权限(见 Getting access),以及一份可用的本地.env(即你正常的本地开发配置——它提供除 DB 连接以外的一切,DB 连接由下面的命令覆盖)。

NS=langfuse-pr-<N> # e.g. langfuse-pr-42 # 1. 把 Postgres + ClickHouse 隧道到 localhost(保持运行) kubectl -n $NS port-forward svc/$NS-postgresql 5432:5432 & CH=$(kubectl -n $NS get svc -o name | grep clickhouse | head -1) kubectl -n $NS port-forward "$CH" 8123:8123 & # 2. 每个预览生成的密码(合成、一次性) PGPW=$(kubectl -n $NS get secret langfuse-secrets -o jsonpath='{.data.postgres-password}' | base64 -d) CHPW=$(kubectl -n $NS get secret langfuse-secrets -o jsonpath='{.data.clickhouse-password}' | base64 -d) # 3. seed —— 只覆盖 DB 连接(其余由你的 .env 提供); # NEXTAUTH_URL 让 CLI 打印的深链指向预览 UI cd packages/shared DATABASE_URL="postgresql://postgres:$PGPW@localhost:5432/postgres_langfuse" \ CLICKHOUSE_URL="http://localhost:8123" CLICKHOUSE_PASSWORD="$CHPW" \ NEXTAUTH_URL="https://pr-<N>.preview.langfuse.com" \ pnpm run seed:scenario -- deep-chain --v4

命令seed:scenario在 packages/shared/package.json 中定义为dotenv -e ../../.env -- tsx scripts/seeder/cli.ts,场景代码位于 packages/shared/scripts/seeder/scenarios/(已有deep-chain.tsagent-timeline.tsmany-traces.tssession-shapes.tspayload.ts等 20 余个场景)。

使用要点:

  • pnpm run seed:scenario -- list列出所有场景和 flag;加--dry-run可预测计数且不写入任何数据。完整目录见 .agents/skills/seed-test-data/SKILL.md。
  • 最后一行 stdout 是一个 JSON 摘要,包含verified和可点击的links,直达预览 UI。
  • 从一个migrations 与 PR 匹配的 checkout 运行——场景代码与预览 DB 必须一致,所以要从 PR 的分支 seed(通常已 checkout),而不是过期的main
  • 仅合成数据——与预览中其他任何地方同样的规则。

调试一个预览

需要集群访问权限(见下)。先把 PR 的命名空间设置好——chart 把所有东西都命名为<namespace>-<component>,其余都能从它推导:

NS=langfuse-pr-<N> # e.g. langfuse-pr-42

在运行什么 / 健康吗?

kubectl -n $NS get pods # web, worker, postgresql, clickhouse, redis, minio kubectl -n $NS get pods,svc,ingress,pvc # 更全的视图

什么都没列出?大概是非工作时间睡着了——唤醒它(见下)。

应用日志——通常第一站:

kubectl -n $NS logs deploy/$NS-web --tail=200 -f # web: UI / API 服务器 kubectl -n $NS logs deploy/$NS-worker --tail=200 -f # worker: 摄取 + 异步任务

去掉-f是一次性转储;--since=15m按时间限定;-p/--previous显示重启后崩溃容器的日志(处理CrashLoopBackOff时用)。

数据存储日志(单节点;确切的 pod 名从get pods获取):

kubectl -n $NS logs sts/$NS-postgresql --tail=100 CH=$(kubectl -n $NS get pods -o name | grep clickhouse | head -1) kubectl -n $NS logs "$CH" --tail=100 # 单节点 ClickHouse —— 留意 OOM / 重启

pod 起不来(Pending / CrashLoopBackOff / ImagePullBackOff):

kubectl -n $NS describe pod <pod> # 底部的 Events 列表就是原因 kubectl -n $NS get events --sort-by=.lastTimestamp | tail -30

进入 shell / 重启 / 绕过 ALB 访问:

kubectl -n $NS exec -it deploy/$NS-web -- sh # 检查 env、curl 内部服务 kubectl -n $NS rollout restart deploy/$NS-web # 修复后重新滚动 kubectl -n $NS port-forward deploy/$NS-web 3000:3000 # 访问 localhost:3000,绕过 ALB

唤醒休眠中的预览(非工作时间):

kubectl annotate ns $NS downscaler/force-uptime=true --overwrite # 副本约 60 秒恢复,就绪约 3–5 分钟 kubectl annotate ns $NS downscaler/force-uptime- # 之后撤销,让它按调度休眠

症状 → 修复

症状可能原因 / 修复
预览环境不可用检查preview标签,并查看AWS preview build工作流。如果 PR 打开时带合并冲突,解决冲突;下一次更新会补上标签。其他 CI 检查不会阻塞预览构建。
🟢 构建评论已发,但 URL 404PR 作者不在部署允许名单上——镜像构建了,但什么都没部署。把自己加上(见 Getting access)。
构建后 URL 尚未就绪构建仍在收尾(约 5 分钟),或短暂的ImagePullBackOff——会自愈。
夜间 / 周末无响应非工作时间睡着了——唤醒它(见上)。
pod 一直Pending,无法调度集群达到预览容量上限——关闭一个旧预览。
ClickHouse pod 重启 / OOM单节点 ClickHouse 是最脆弱的一环——先查它的日志。

获取访问权限(Getting access)

  • 部署访问——自助服务:把自己的 GitHub 登录名加进k8s/preview/bootstrap/applicationset.yaml(私有仓库langfuse/infrastructure)的authorselector,开一个 PR 并合并到main。Argo 重新同步后,你的带标签 PR 就会部署——无需管理员。
  • 集群访问——所有 Langfuse 工程师可用(只有调试kubectl时需要,使用预览不需要):
    1. 打开~/.aws/config,从内部 tracker 文档"Connect to AWS instances (Aurora, Redis) from local machine"添加[sso-session langfuse]+[profile preview]两个块(保留你已有的[sso-session langfuse])。
    2. aws sso login --profile preview
    3. aws eks update-kubeconfig --name langfuse-preview --region eu-west-1 --profile preview不需要--role-arn——该 role 有自己的 EKS access entry)。

预览系统的架构边界

预览的基础设施——EKS 集群、Argo CD ApplicationSet、Helm chart、管理员入职 runbook——全部位于私有仓库langfuse/infrastructurek8s/preview/目录。SKILL.md 明确指出:要改预览系统,去那个仓库改,而不是在这里。当前仓库内的 .github/workflows/preview-autolabel.yml、preview-build.yml、preview-deactivate.yml、preview-stale-cleanup.yml 只负责构建、发布与 GitHub 侧的记录管理;预览环境的真实生命周期(创建命名空间、部署、缩容、休眠、级联删除)始终由 Argo CD 拥有。

从整体设计可以看出,这套预览体系把「写权限即可构建」「作者名单才能部署」「调度驱动休眠」「标签即生命周期开关」几个原则组合起来,在保证安全边界(Fork 不碰、合成数据、公开登录)的同时,把同仓库 PR 的体验压到了「开 PR 即得环境」的零门槛。对 Langfuse 的贡献者与 coding agent 来说,.agents/skills/langfuse-previews/SKILL.md 就是这套系统的操作手册,而.github/workflows/下的四个工作流则是它的可读实现。

【免费下载链接】langfuse🪢 Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. 🍊YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询