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

资讯详情

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

k-skill 生产部署实战:k-skill-proxy 在 gpu01 上的 systemd、自动发布与服务看门狗全解析

k-skill 生产部署实战:k-skill-proxy 在 gpu01 上的 systemd、自动发布与服务看门狗全解析 k-skill 生产部署实战k-skill-proxy 在 gpu01 上的 systemd、自动发布与服务看门狗全解析【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill本文基于仓库文档 docs/deploy-k-skill-proxy.md 与 部署脚本、systemd 单元文件、代理服务端实现 展开讲解 k-skill-proxy 在生产机 gpu01 上的完整部署体系单跳 Cloudflare Tunnel 拓扑下KSKILL_PROXY_TRUST_PROXY_HOPS1的由来、每 5 分钟由 cron 驱动的自动发布与回滚流程、防止服务“安静死亡”的看门狗机制、运行时.env的密钥管理与轮换流程以及 Loki/Promtail/Grafana 用量统计面板的接入方式。读完后你可以理解这套“cron flock systemd user service”架构的每个环节为什么这样设计并能对同类 Fastify 公共代理做同样的部署审计。生产部署布局单跳 Tunnel 拓扑k-skill-proxy的生产环境运行在gpu01上而不是 Google Cloud Run。公共域名由 Cloudflare Tunnel 转发到绑定在127.0.0.1:8080的 Fastify 进程整条链路只有“一个本地 Tunnel 跳”。生产布局的关键项如下完整表格见 docs/deploy-k-skill-proxy.md项目值主机gpu01gpu01.nomadamas.orghostname -s为marker-multi-gpu-server-01公共 URLhttps://k-skill-proxy.nomadamas.org应用目录/data/home/jeffrey/apps/k-skill-proxy源码检出目录/data/home/jeffrey/apps/k-skill-proxy-repo代理服务systemctl --user status k-skill-proxy.serviceTunnel 服务systemctl --user status k-skill-proxy-tunnel.service运行时环境/data/home/jeffrey/apps/k-skill-proxy/.env已部署版本/data/home/jeffrey/apps/k-skill-proxy/deployed-sha部署脚本scripts/deploy-k-skill-proxy-gpu01.sh生产监听器绑定127.0.0.1公共流量只能通过这一个本地 Cloudflare Tunnel 跳进入。文档对此有一个明确的安全约束只有当部署脚本以KSKILL_PROXY_DEPLOY_ENVIRONMENTproduction且生产主机KSKILL_PROXY_DEPLOY_HOSTgpu01或hostname -s为gpu01/marker-multi-gpu-server-01运行时脚本才会确保运行时环境包含KSKILL_PROXY_TRUST_PROXY_HOPS1并重启服务cron 中应显式设置KSKILL_PROXY_DEPLOY_HOSTgpu01。非 production 或非 gpu01 的执行保持应用默认值0。运维人员显式设置的值会被保留KSKILL_PROXY_ENV_FILE可以把脚本指向非默认的环境文件路径。文档还特别警告不要对直接暴露的监听器使用此设置。信任一跳之所以在这里安全是因为 Fastify 端口只监听 loopback一旦该端口对外可达客户端就能提供伪造的X-Forwarded-For值。从源码看这一约束是硬编码在脚本里的deploy-k-skill-proxy-gpu01.sh 中的is_gpu01_production先检查KSKILL_PROXY_DEPLOY_ENVIRONMENT是否为production再用case匹配gpu01|marker-multi-gpu-server-01两种主机名只有通过双重校验ensure_gpu01_production_defaults才会调用ensure_env_default向.env追加缺失的KSKILL_PROXY_TRUST_PROXY_HOPS1。ensure_env_default第 36-52 行先grep检查键是否已存在存在则直接返回——这正是“显式运维值被保留”的实现。为什么 TRUST_PROXY_HOPS1限流识别的源码原理生产环境必须设置KSKILL_PROXY_TRUST_PROXY_HOPS1的原因在 packages/k-skill-proxy/src/server.js 中可以找到第 288 行将KSKILL_PROXY_TRUST_PROXY_HOPS解析为trustProxyHops取Math.max(0, ...)非法值回退 0第 2214 行把它传给 Fastify 构造参数trustProxy: config.trustProxyHops || false。如果不信任这一跳Fastify 的request.ip会一直是127.0.0.1所有外部客户端会共享同一个限流桶限流形同虚设。更进一步的防伪造逻辑在clientRateLimitKeyserver.js当trustProxyHops 0时限流键优先取CF-Connecting-IP请求头而不是X-Forwarded-For——X-Forwarded-For是客户端可以随意追加的而CF-Connecting-IP由 Cloudflare 在出口重写客户端无法通过伪造额外 XFF 条目来绕过限流。对应的行为测试在 server.test.js 中覆盖了KSKILL_PROXY_TRUST_PROXY_HOPS为1和2的场景。同样地路由用量日志routeUsage行里的clientIp字段也仅在trustProxyHops 0时写入server.js否则记录的全是127.0.0.1统计失去意义。默认值与限流相关参数的完整定义见 packages/k-skill-proxy/README.mdKSKILL_PROXY_RATE_LIMIT_WINDOW_MS默认60000、KSKILL_PROXY_RATE_LIMIT_MAX默认60、KSKILL_PROXY_RATE_LIMIT_MAX_CLIENTS默认10000、KSKILL_PROXY_CACHE_TTL_MS默认300000、KSKILL_PROXY_HOST默认127.0.0.1。自动发布流程cron flock SHA 幂等gpu01用户的 crontab 在flock保护下每 5 分钟运行一次部署脚本。脚本先fetch origin/main如果记录的 SHA 与目标一致则直接退出否则依次执行在源码检出目录 checkout 目标 SHA运行npm ci、proxy lint 和全部 proxy 测试为当前应用创建带时间戳的备份同步 proxy 及其本地 workspace 依赖安装生产依赖并重启 systemd user service检查本地与公共的/health和/privacy所有检查通过后才记录deployed-sha。只要main上有新合并、且新 proxy 测试与冒烟检查通过就会在一个 cron 周期内完成部署。备份之后的任何失败都会触发自动回滚恢复上一版文件并重启旧服务。对照 deploy-k-skill-proxy-gpu01.sh 的实现几个值得注意的细节cron 环境的 systemd 会话总线第 4-6 行显式导出XDG_RUNTIME_DIR和DBUS_SESSION_BUS_ADDRESS因为 cron 没有 user-session bus否则systemctl --user无法工作验证先于变更第 146-150 行在目标 SHA 上依次执行checkout --detach --force、npm ci --no-audit --no-fund、npm run lint --workspace k-skill-proxy、npm run test --workspace k-skill-proxy——测试失败发生在备份之前此时还没有任何变更无需回滚备份内容与回滚陷阱第 152-159 行用tar备份packages/k-skill-proxy、packages/parking-lot-searchproxy 的本地 workspace 依赖、deployed-sha和根package.json/package-lock.json第 161-168 行用trap rollback ERR注册回滚回滚动作是解压备份 npm ci --omitdevsystemctl --user restart同步范围第 170-173 行rsync -a --delete --exclude node_modules同步 proxy 与parking-lot-search两个包第 174-175 行用install -m 0644覆盖根 workspace 清单带重试的冒烟检查第 182-187 行对http://127.0.0.1:8080/health做 5 次、每次间隔 2 秒的重试之后第 188-191 行对本地与公共两个端点各做一次/health与/privacy检查。health_check用node -e断言响应 JSON 的ok trueprivacy_check第 115-124 行则断言/privacy页面包含固定版本的 meta 标签namek-skill-privacy-policy-version content2026-08-18——这意味着隐私政策页面内容被纳入了发布冒烟测试脚本自举第 193 行把仓库中的部署脚本install -m 0755到$APP_DIR/deploy-k-skill-proxy-gpu01.sh。因此首次包含该脚本的main部署之后cron 实际执行的是应用目录里的自拷贝版本。cron 条目安装或修复时用*/5 * * * * KSKILL_PROXY_DEPLOY_HOSTgpu01 flock -n /tmp/k-skill-proxy-deploy.lock /data/home/jeffrey/apps/k-skill-proxy/deploy-k-skill-proxy-gpu01.sh /data/home/jeffrey/apps/k-skill-proxy/deploy.log 21注意flock -n已有部署在跑时新触发的 cron 直接放弃而不是排队。SSH 别名是gpu01而机器上hostname -s是marker-multi-gpu-server-01——部署脚本两者都视为生产但文档仍要求在 cron 中显式设置KSKILL_PROXY_DEPLOY_HOSTgpu01避免主机名变更悄悄禁用看门狗。自举之前需要手动安装一次install -m 0755 /data/home/jeffrey/apps/k-skill-proxy-repo/scripts/deploy-k-skill-proxy-gpu01.sh \ /data/home/jeffrey/apps/k-skill-proxy/deploy-k-skill-proxy-gpu01.sh服务看门狗一次重启事故催生的设计脚本的第一件事早于任何部署逻辑是服务看门狗每次 cron 运行——包括因deployed-sha已匹配而提前退出的运行——都会先确保生产服务处于 active 状态第 130 行ensure_production_services。已安装但不 active 的服务会被systemctl --user start拉起第 82-99 行ensure_service_active先list-unit-files确认单元存在再is-active --quiet判断。这个设计源于一次真实事故2026-08-29 gpu01 重启后Cloudflare tunnel 与 Loki/Grafana/Promtail 仪表盘栈挂了约 10 天才被人工发现。根因是这些单元使用Restarton-failure——它不会恢复一次“干净的 SIGTERM”而除了这个 cron 之外没有任何东西会再启动它们。proxy 之所以活了下来纯属巧合这个 cron 每次运行都会restart它。被看门狗监视的服务仅限生产 gpu01可通过KSKILL_PROXY_WATCHED_SERVICES覆盖默认列表见 脚本第 20 行服务角色k-skill-proxy.serviceFastify 代理k-skill-proxy-tunnel.service两个公共主机名的 cloudflared tunnelk-skill-proxy-loki.service日志存储k-skill-proxy-promtail.service日志采集k-skill-proxy-grafana.service仪表盘 UI所有 5 个单元都使用Restartalways加StartLimitIntervalSec0保证干净停止或反复失败都不会让重启机制被永久禁用。规范单元文件都在仓库 infra/k-skill-proxy-dashboard/systemd/ 目录下单元仓库来源proxyinfra/k-skill-proxy-dashboard/systemd/k-skill-proxy.servicetunnelinfra/k-skill-proxy-dashboard/systemd/k-skill-proxy-tunnel.serviceloki / promtail / grafanainfra/k-skill-proxy-dashboard/systemd/从单元文件内容看两个关键实现k-skill-proxy.service 以EnvironmentFile/data/home/jeffrey/apps/k-skill-proxy/.env注入运行时密钥RestartalwaysRestartSec3stdout/stderr 直接 append 到proxy.logk-skill-proxy-tunnel.service 额外携带RequiresMountsFor分别指向 cloudflared 二进制、其配置和应用目录——这三者都在gpu02:/dataNFS 挂载上必须等挂载就绪后才能 exec否则开机时会直接 crash-loop。proxy 单元同样对应用目录设置了RequiresMountsFor。手动操作与验证命令日常巡检与手动触发部署完整命令清单见 docs/deploy-k-skill-proxy.mdmosh gpu01 /data/home/jeffrey/apps/k-skill-proxy/deploy-k-skill-proxy-gpu01.sh curl -fsS http://127.0.0.1:8080/health curl -fsS https://k-skill-proxy.nomadamas.org/health curl -fsS http://127.0.0.1:8080/privacy curl -fsS https://k-skill-proxy.nomadamas.org/privacy cat /data/home/jeffrey/apps/k-skill-proxy/deployed-sha日志与服务状态tail -f /data/home/jeffrey/apps/k-skill-proxy/deploy.log tail -f /data/home/jeffrey/apps/k-skill-proxy/proxy.log systemctl --user status k-skill-proxy.service systemctl --user status k-skill-proxy-tunnel.service验证 trust-proxy 设置时不要打印整个带密钥的 env 文件只 grep 目标键grep ^KSKILL_PROXY_TRUST_PROXY_HOPS /data/home/jeffrey/apps/k-skill-proxy/.env生产环境期望值为KSKILL_PROXY_TRUST_PROXY_HOPS1。如果该键缺失下一次 gpu01 生产部署会补上并重启服务staging、本地或其他主机执行则不会添加。拓扑变化时只有重新清点可信反向代理跳数之后才应更新显式值。.env文件留在gpu01上绝不能复制进仓库。必需运行时环境变量gpu01由于 Cloudflare Tunnel 转发到127.0.0.1:8080Fastify 必须信任这一跳否则所有外部客户端共享同一个限流桶。以下键应保留在/data/home/jeffrey/apps/k-skill-proxy/.env中KSKILL_PROXY_TRUST_PROXY_HOPS1 KSKILL_PROXY_RATE_LIMIT_WINDOW_MS60000 KSKILL_PROXY_RATE_LIMIT_MAX60 COUPANG_ACCESS_KEYcoupang-partners-access-key COUPANG_SECRET_KEYcoupang-partners-secret-key KOMSA_MTIS_API_KEYkomsa-mtis-service-key可选的 BC Card eat.pl 中转键仅在启用 Lightsail 固定出口中转时配置。同一个随机 token 在 Lightsail 侧存为EATPL_RELAY_TOKEN。token 永远不要放进 Git、聊天或客户端请求BCCARD_EATPL_INST_NMpartner-institution-code BCCARD_EATPL_API_BASE_URLhttps://api.paybooc.ai/api/mer BCCARD_EATPL_RELAY_URLhttps://eatpl-relay.nomadamas.org/v1/search BCCARD_EATPL_RELAY_TOKENsame-token-as-lightsailKSKILL_PROXY_TRUST_PROXY_HOPS1在生产必需只有“本地绑定、且不在反向代理之后”的进程才保持不设默认0。信任跳数大于 0 时限流器优先取CF-Connecting-IP而非X-Forwarded-For客户端无法伪造额外 XFF 条目实现见 server.js 第 443-451 行。两类密钥的启用方式与验证路径CoupangCOUPANG_ACCESS_KEYCOUPANG_SECRET_KEY启用GET /v1/coupang/products/search。密钥只存在 gpu01 运行时.env绝不经过 query string、shell 参数、issue 或日志。通过/health→upstreams.coupangConfiguredtrue验证启用。KOMSA MTISKOMSA_MTIS_API_KEY启用GET /v1/komsa/ferry/:dataset。同样只存 gpu01 运行时.env通过/health→upstreams.komsaConfiguredtrue验证后再执行一次只读渡轮查询演练。ASK Seoul 天气风险路由的密钥交接部署seoul-weather-risk代理路由前ASK Seoul 必须先签发专用的、可吊销的服务密钥不得使用维护者或贡献者的个人 Marketplace 密钥。Marketplace 将该密钥注册为以下固定服务主体与作用域字段固定值service principalk-skill-proxy:seoul-weather-riskscopeskill:seoul-weather-risk:read允许的 Marketplace APIGET /skill/v1/bundles/seoul-weather-risk、GET /skill/v1/products/weather_place_risk_window、GET /skill/v1/products/weather_place_risk_window/data排除的 API所有/api/v1/*API 与其他所有/skill/v1/*产品只在既有 gpu01 运行时.env中存放这两个值ASK_SEOUL_SKILL_API_BASE_URLhttps://ask-seoul-skill-origin ASK_SEOUL_KSKILL_API_KEYdedicated-service-key该密钥不是用户凭据它只从代理进程发往固定的 ASK Seoul/skill/v1路径。在 Marketplace 完成服务密钥 scope 迁移并注册该主体之前不要部署这条路由代理 README 中askSeoulWeatherRiskConfigured健康标志的含义——仅当 origin 与专用服务键同时设置才为true——见 packages/k-skill-proxy/README.md。密钥轮换流程注册同 scope 的替代密钥 → 只替换 gpu01 运行时密钥 → 重启/冒烟测试代理 → 吊销旧密钥。若代理被禁用或疑似失陷立即吊销其密钥Marketplace 必须在任何每日配额核算之前拒绝该密钥。永远不要把密钥粘贴进 issue、PR、shell 参数、URL 或日志。用量统计面板Loki Promtail Grafana端点调用统计routeUsage日志行由 Promtail 采集进 Loki再在 Grafana 中可视化。从 server.js 第 2233-2266 行 可以看到日志生产端的设计onResponsehook 对每个匹配路由计数并输出一条结构化日志/health被排除健康检查是运维噪声而非使用量所有未匹配请求聚合到单一__unmatched__键下404 的原始路径先经过normalizeUnmatchedPath归一化且 map 上限 100 条——文档注释明确说明这是为了防止任意输入无限撑大内存 map 和 Loki 标签基数。面板栈的细节90 天日志保留、{jobk-skill-proxy, route!}查询约定、setup-gpu01.sh安装步骤、Grafana 绑定127.0.0.1:3200并复用同一个 cloudflared tunnel 暴露k-skill-proxy-dashboard.nomadamas.org见 infra/k-skill-proxy-dashboard/README.md。栈以 systemd user service 形式运行k-skill-proxy-{loki,promtail,grafana}.service由infra/k-skill-proxy-dashboard/setup-gpu01.sh安装。Grafana 登录即访问控制禁用匿名、仅管理员账户管理凭据存放在grafana.envmode 600绝不提交。一个时序注意点route标签以及按端点划分的面板只有在产出routeUsage日志行的代理构建部署到main之后才会出现——即部署了带routeUsage统计逻辑的版本前面板上不会有按端点的数据。小结这套部署体系的三条经验幂等 看门狗合并进同一条 cron部署脚本既是发布器又是保活器flock -n防并发、SHA 对比防重复、每次运行先拉起死掉的服务用一个 5 分钟周期同时解决“部署”和“活着”两个问题安全默认值写进发布流程而非文档口头约定TRUST_PROXY_HOPS1由脚本在严格的双条件production gpu01 主机下自动补齐且保留运维显式值防止误配在 staging/本地扩散发布冒烟测试覆盖到隐私政策版本/privacy的 meta 标签版本被privacy_check断言内容回归同样会阻断发布并触发回滚。延伸阅读packages/k-skill-proxy/README.md端点与全部环境变量、/health上游标志语义、infra/k-skill-proxy-dashboard/README.md仪表盘栈完整布局、docs/deploy-eatpl-relay-lightsail.mdBC Card eat.pl Lightsail 中转的部署文档。【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表