尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Friend desktop-backend 的 Cloud Run 生产所有权:独立发布向量、候选验收、事故恢复与 GKE 退役运维指南

Friend desktop-backend 的 Cloud Run 生产所有权:独立发布向量、候选验收、事故恢复与 GKE 退役运维指南 Friend desktop-backend 的 Cloud Run 生产所有权独立发布向量、候选验收、事故恢复与 GKE 退役运维指南【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend本指南以 backend/docs/runbooks/desktop-backend-cloud-run-ownership.md 为骨架完整解析 Friend 桌面端macOS后端服务desktop-backend在生产环境中的所有权边界它为何是一个独立于 Python 后端与 GKE listener 的 Cloud Run 发布向量、四个 GitHub Actions 工作流各自拥有的权限以及候选版本如何经过五步验收后以零流量起步、逐步接管 100% 流量并在失败时自动回滚。读完本文你将掌握 desktop-backend 从开发部署、生产 dispatch、事故恢复 hatch 到旧 GKE 平面安全退役的一整套运维操作流程与底层实现依据。desktop-backend 是谁为什么需要独立所有权Friend 的桌面端macOS 客户端对话与代理能力由一个独立的 Python FastAPI 服务提供其入口位于 backend/desktop_backend.py模块级app _build_app()挂载了desktop_core、auth、desktop_chat、desktop_proxy、desktop_realtime、desktop_screen_crisp、desktop_tts_updates等一组桌面专属路由并显式启用了默认拒绝的 CORS 策略CORS_ALLOWED_ORIGINS必须列出显式来源禁止*。该服务在生产中运行于 Google Cloud Run区域us-central1由 backend/Dockerfile.desktop_backend 构建镜像。runbook 明确要求不要把desktop-backend加进 Python 后端移动端 API 与 listener的 release-vector verifier。两个服务平面拥有完全不同的构建、回滚与发布生命周期唯一真实的耦合点是macOS Beta 资格验证与 Stable 提升要求正在服务的 desktop-backend 对外宣告的 desktop chat 契约版本与应用所期望的版本一致。也就是说兼容性只在应用 ↔ 后端 chat contract这一处被强制绑定其余生命周期互不干扰。发布权威矩阵四个工作流各司其职desktop-backend 的发布权威被刻意拆分为四个职责互不重叠的 GitHub Actions 工作流均位于 .github/workflows 目录工作流职责触发方式是否部署 Cloud Rundesktop_backend_auto_dev.yml开发环境based-hardware-dev持续交付仅接受main当前 HEAD推送main路径过滤或workflow_dispatch是desktop_backend_prod.yml生产环境受保护的手动部署权威只认一个已合并的 main SHAworkflow_dispatch需确认口令是desktop_backend_recover_prod.yml事故时仅做流量恢复的受保护 hatch只认一个保留的ReadyTrue旧 revisionworkflow_dispatch需确认口令仅切流量desktop_promote_prod.yml只推进已获资格的 macOS Stable 产物指针与遗留发布桥手动否永不部署 Cloud Run自动开发工作流auto_dev是唯一可被 push 触发的入口且其首个步骤就校验GITHUB_REF refs/heads/main并强制本次 checkout 的 SHA 必须等于origin/main的最新 SHA杜绝陈旧提交误入开发环境。开发与生产工作流都各自校验目标 GCP 项目 IDbased-hardware-dev/based-hardware以及 Cloud Run 服务 URL 是否等于预期的规范 URL用 fail-closed 的方式防止把候选版本部署到错误的项目或错误的服务上。候选验收与零流量部署镜像、revision 与五步证明两个部署工作流auto_dev 与 prod在发布路径上完全同构遵循先零流量、后验证、再切流的不可变 revision 模型从已准入的源码 SHA 派生不可变镜像 tagsource_sha前 12 位与 revision 后缀${image_tag}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}构建并推送digest-pinned镜像以--no-traffic零流量部署一个带候选 tag开发为desktop-dev-candidate生产为desktop-prod-candidate的精确 revision等待ReadyTrue并校验运行中的 revision 镜像 digest 与构建产物 digest 的镜像血缘一致——由于 Managed Prometheus sidecar 使候选 revision 变成双容器工作流会按容器名desktop-backend-1精确抽取镜像并断言唯一匹配防止单容器拓扑假设导致的校验失效在零流量候选上执行完整候选探测全部通过后才允许流量迁移。候选版本必须在 .github/scripts/desktop_backend_candidate_probe.py 中完成五步证明runbook 要求的五项验收对应源码中的probe_candidate/health报告准入的后端 SHA、发布 channeldevelopment/production与 chat contract 版本——validate_health逐一比对backend_release_sha、backend_release_channel、runtime_implementationpython、serviceomi-desktop-backend与chat_contract_version任何字段不匹配即拒绝/ready与只读遗留更新查询证明 Redis 与 Firestore 可访问——validate_readiness要求readiness.status ready且readiness.redis.status ready_require_firestore_read对/updates/latest发起只读请求并接受 200/404 两种合法结果一次流式 public-web turn 必须报告至少一个 provider web-search 请求、返回答案文本、并在有界响应预算内结束——探测脚本通过/v2/chat/completions发起流式 SSE 请求解析usage.web_search_requests并要求首事件在 20 秒内MAX_FIRST_EVENT_SECONDS、整轮在 70 秒内MAX_CHAT_SECONDS完成且必须收到[DONE]标记与终结 usage同一段消息历史中的普通 follow-up 完成且不再复用 web search——构造user → assistant → user三段消息验证路由状态不会被上一轮的 web 路由污染OpenAI 与 Gemini 两个托管 realtime-provider 探测全部完成——工作流对openai、gemini分别调用 scripts/voice-provider-probe.sh允许对可重试的上游失败退出码 75最多重试 3 次。探测脚本本身是有界且内容无关的它要求 Gemini 代理真实命中允许的 provider 路由vertex_ai、ai_studio、ai_studio_byok、llm_gateway并校验x-omi-provider与请求 ID 头但证据只记录 provider 路由、耗时与状态绝不保留生成内容Bearer token 必须来自权限 0600 的普通文件探测证据以 JSON 写入artifacts/desktop-backend-{dev,prod}-candidate.json并随 workflow artifact 上传开发保留 14 天、生产保留 30 天。runbook 特别强调realtime-provider 探测证明的是后端/provider 依赖边界不能替代 macOS push-to-talkPTT生命周期资格验证。应用侧的 PTT、麦克风、转写、冷启动、替换轮次与 UI 终结行为仍归 macOS 测试与资格验证通道负责。生产 dispatch 的前置条件确认口令、原因、SHA 与 Release Eligibility生产部署由 desktop_backend_prod.yml 手动触发其workflow_dispatch输入是一组强制约束release_sha必须是一个已合并进main的 40 位小写完整 commit SHA排除全零工作流会执行git merge-base --is-ancestor验证其是新鲜origin/main的祖先confirm必须精确输入deploy-desktop-backend-prodreason非空的运维原因其 SHA-256 摘要会被记录进 step summary不落明文原因默认要求一次成功的首次尝试first-attemptRelease Eligibility 证明通过 GitHub API 查询release-eligibility.yml针对该 SHA 的 push 触发、statuscompleted的运行记录并用 .github/scripts/verify_backend_release_admission.py 校验。标准仓库 break-glass 输入skip_eligibility_proofbreak_glass_confirmdeploy-without-proof 非空break_glass_reason只能豁免 Release Eligibility 证明永远不能豁免已合并 main SHA与候选验收两道准入。这体现了 runbook 的底线任何情况下都不能让未合入 main 的代码或未通过五步验收的 revision 进入生产流量。此外生产工作流还会把部署控制脚本从固定 SHA 检出后暂存到独立目录再执行确保控制逻辑本身不可变、不随最新 main 漂移部署前还会预检一组生产 Secret 资源名SERVICE_ACCOUNT_JSON、DESKTOP_GEMINI_API_KEY、DESKTOP_FIREBASE_API_KEY、DESKTOP_REDIS_DB_*等是否存在并把开发环境允许的PINECONE_API_KEY等从生产 revision 中显式移除保持两个环境的环境变量面互不泄漏。流量切换、验证与自动回滚只有当零流量候选通过全部五步证明后工作流才会重新解析候选 tag 并执行流量迁移gcloud run services update-traffic $SERVICE --project$PROJECT_ID \ --region$REGION --to-revisions$REVISION100 --quiet迁移前工作流已捕获当前 100% revisionprevious-traffic步骤要求恰好一个 100% serving revision否则直接失败并用 .github/scripts/check_desktop_backend_traffic_regression.py 拒绝任何会让服务在历史上回退的晋升。切流后立即执行 serving 侧健康检查/health重新校验 SHA 与契约版本。若切流后的 serving 检查失败工作流通过failure() 环境变量标记触发恢复先前流量步骤把 100% 流量切回旧的 100% revision并再次读回验证随后移除已接受的候选 tag--remove-tags保证候选 tag 只服务于未接管的诊断场景。开发环境额外支持candidate_only模式构建零流量候选后故意停在零流量只输出 warning 并保留 revision 供诊断不执行验收、不改变流量。该模式与 runbook开发候选运行有意停在零流量的描述完全一致。事故恢复 hatchdesktop_backend_recover_prodrunbook 明确指出Cloud Run 回滚步骤在 runner 完全丢失后无法执行因此事故场景的入口不是重跑生产部署而是单独派发 desktop_backend_recover_prod.yml。该工作流要求confirmrecover-desktop-backend-prod、非空reason以及一个精确的保留 revision 名正则^desktop-backend-[a-z0-9-]$校验项目 ID、规范服务 URL、revision 所有权serving.knative.dev/service desktop-backend、ReadyTrue在同一把不可取消cancel-in-progress: false的生产锁concurrency.group: desktop-backend-prod下执行流量恢复避免与正常部署并发打架切流后对$PRODUCTION_DESKTOP_BACKEND_URL/health做带超时的健康校验要求status healthy且service omi-desktop-backend并把backend_release_channel、backend_release_sha、chat_contract_version与恢复目标 revision 一起落成恢复证据 artifact若恢复后的健康验证失败再次把流量切回恢复前的 revision 并验证读回。注意恢复工作流与生产部署共享同一个并发组意味着恢复期间普通生产部署会被排队而不会被取消——这正是非取消生产锁的语义。运行时认证与本地开发分离生产/开发运行时使用 Cloud Run revision 的 service account 与 metadata server 完成 Google 认证Workload Identity工作流通过google-github-actions/auth以 OIDC 换取部署凭证运行时则把 Firebase 服务账号 JSON 以 Cloud Run secret 挂载方式提供/secrets/firebase/service-account.jsonSERVICE_ACCOUNT_JSON:latest。runbook 的硬性要求是service-account JSON 绝不拷贝进镜像层只能以 secret 挂载或环境注入同时 Firestore 访问与托管 Gemini 路径必须在零流量候选上先行验证之后才允许流量移动。本地 macOS 开发则刻意与 Cloud Run 完全解耦desktop/macos/run.sh在 localhost 上直接运行 Python 的desktop_backend:app默认端口 10201刻意避开 8080并支持OMI_SKIP_BACKEND1、OMI_SKIP_TUNNEL1、--yolo等模式把应用指向远端开发 Cloud Run。runbook 要求不要用 Cloud Run 依赖替换这套本地工作流——本地开发保持自包含、可离线、可调试。已退役的 GKE 平面禁止恢复backend/charts/desktop-backend/已退役当前仓库中该 Helm chart 目录已不存在与其retired状态一致。runbook 规定它不得被重新引入且desktop-api.omi.me不得再以 GKE Ingress、NEG、managed certificate、DNS target、Helm release、Deployment、Service 或 ServiceAccount 形式重建。生产数据面路由守卫会拒绝该 chart 的恢复。runbook 还给出了一条重要的审计原则不要因为仓库里检入了某个部署引用就推断它代表活的所有权。任何变更前必须先检查正在服务的 Cloud Run revision 与完整流量分配再单独检查命名的活 GKE 与 DNS 资源审计期间绝不读取 Secret 载荷。GKE 退役与回滚程序五步走与 30 分钟观察生产 GKE 退役是一次需要单独授权的操作且必须在本仓库的 source guard 合并之后才开始。删除任何资源前按序完成五步确认产物路由当前已签名的 Stable macOS 产物指向生产 Cloud Run desktop-backend URL已签名的 Beta 产物指向开发 Cloud Run desktop-backend URL而 Beta desktop-login OAuth 与 Firebase Auth/Firestore 仍留在生产客户身份平面确认双端健康生产与开发两个 Cloud Run desktop-backend 服务均 Ready、各自 100% 流量服务于预期 revision、公共健康检查通过并用部署证据 artifact 把 source SHA、镜像 digest、候选 tag、workflow run 与验收结果绑定检查流量日志查看desktop-api.omi.me最近一段有意义的 load-balancer 日志窗口仅汇总 route、status 与 user-agent 类别一旦发现受支持的桌面流量或可信客户端使用迹象立即停止确定 DNS 权威归属找到权威 DNS owner 与精确记录集只有证明记录仅指向退役中的 GKE load balancer 才能删除盘点并保留回滚材料清点 Helm release/资源、非 Helm Ingress、managed certificate、NEG/backend service 与 DNS 记录在变更前保留非 Secret 的回滚标识符与 manifest。删除时只使用每个资源的权威 owner只删除识别出的陈旧生产 GKE 平面不得改动Cloud Run 服务、本地开发工具链、共享 Secrets、IAM、无关 DNS、release 指针或桌面应用产物。若删除产生意外影响或所有权归属不明立即停止只用保留的回滚材料恢复退役的 GKE 路径。清理完成后观察真实流量至少 30 分钟确认Cloud Run 健康/流量、产物路由、macOS 结果聚合、Cloud Run 响应类别以及 GKE workload、ingress、certificate、NEG/backend service 与 DNS 记录的消失或删除完成。最后现有 watchdog 不得残留指向 desktop-backend 的陈旧告警——只能修改那些专属于这个退役平面的监控项。关联资料与进一步阅读本文依据的权威 runbookbackend/docs/runbooks/desktop-backend-cloud-run-ownership.mdGemini 超时与 provider 归因类事故专用 runbookbackend/docs/runbooks/desktop-gemini-proxy-incidents.md其中定义了/v1/proxy/gemini/*的终端事件维度、信号分类表与有界超时契约75 秒非流式逻辑截止、10 秒 connect、15 秒 write、70 秒 read、5 秒 pool wait、30 秒流式 idle-gap服务入口与路由挂载backend/desktop_backend.py候选探测实现五步验收的源码依据.github/scripts/desktop_backend_candidate_probe.py开发/生产/恢复/提升四个发布工作流desktop_backend_auto_dev.yml、desktop_backend_prod.yml、desktop_backend_recover_prod.yml、desktop_promote_prod.yml本地 macOS 开发启动器desktop/macos/run.sh【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表