一键导入
add-k8s-service
在 home-ops 仓库中为 k3s 集群新增服务的完整流程:设计→创建代码→提交审查→部署观测。按 Flux GitOps 双层结构(infra.yml 与 apps.yml)组织文件与依赖。使用当用户要求部署新应用、添加新服务、补齐 app 目录资源时。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
在 home-ops 仓库中为 k3s 集群新增服务的完整流程:设计→创建代码→提交审查→部署观测。按 Flux GitOps 双层结构(infra.yml 与 apps.yml)组织文件与依赖。使用当用户要求部署新应用、添加新服务、补齐 app 目录资源时。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when 部署/更新 VPS 或 sakamoto
Kubernetes 事故取证流程。Use when 服务离线但没告警、升级后异常、K8s 应用/入口/备份链路失败、Gatus/Prometheus/Alertmanager 异常、Envoy Gateway 403/GeoIP/RBAC 异常、audit log 追溯手动操作、router-dns-proxy 延迟/失败、外部访问抖动,或需要统一时间线定位故障断点。
在 containers 仓库创建无后端轻量前端应用,并串起 home-ops GitOps 部署流程。Use when 用户要求创建简单应用、轻量前端服务、小工具、展示页、SPA、simple-service,或提到“复制模板到 apps 并部署”。
从 home-ops 的 Docker Compose 服务补齐 Gatus outside 健康检查,并选择轻量、可从集群内验证的探测方式。Use when 用户要求对比 compose 与 Gatus、补充 outside endpoints、检查集群外 VPS/sakamoto 服务监控、或调整 Gatus health check 轻量化。
shelken/home-ops 项目的目录结构与资源组织规范。在涉及该项目的文件放置、模块拆分、资源归属判断时使用。
当用户提到审核 PR、review PR、检查开放 PR、判断升级能否合并时使用。逐个读取 PR 信息与首个评论,提炼亮点更新和破坏更新,对照当前仓库/集群配置判断是否需要同步变更,并给出简洁结论与代码引用。
| name | add-k8s-service |
| description | 在 home-ops 仓库中为 k3s 集群新增服务的完整流程:设计→创建代码→提交审查→部署观测。按 Flux GitOps 双层结构(infra.yml 与 apps.yml)组织文件与依赖。使用当用户要求部署新应用、添加新服务、补齐 app 目录资源时。 |
<parent-dir>/<app-name>/
├── ks.yaml # Flux 入口
└── app/
├── kustomization.yaml
├── helmrelease.yaml # app-template chart
├── externalsecret.yaml # 需要密钥时创建
└── resources/ # 需要配置文件时创建
<parent-dir> 按服务归属决定(见创建代码第 1 步)。
kustomization.yaml。kustomize build 验证 app、对应中间层、staging 三层。复杂服务先写设计文档到 docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md,提交后等用户审查。审查通过再写代码。
对于需求尚不明确的服务,可用 brainstorming skill 逐条澄清设计后再写代码。
识别形态与归属 — 先判断服务属于 apps 还是 infra:
k8s/apps/common/<app>/k8s/infra/common/<category>/<app>/k8s/infra/common/network/external/<app>/然后判断技术特征:HTTP? DB? 密钥? 持久化? route? 选参考目录。
写 ks.yaml — dependsOn 只写真实前置,components 只写用到的能力。
写 helmrelease.yaml — 优先 app-template。镜像、env、service、route、persistence、probes、resources 按需补齐。
写 kustomization.yaml — 只引用真实存在的文件。有配置文件需要生成 ConfigMap 再加 configMapGenerator。
写 externalsecret.yaml — 按 Secret 注入决策(见下文)判断用哪种方式,确认后再创建。dataFrom.extract.key 用真实的 Azure KeyVault secret 名,target.template.data 只暴露服务实际消费的键。
写入 KeyVault — 用 task secret:set-key 写入,task secret:keys 验证。agent 不得读取 secret 值。
注册 — 加进对应层的 kustomization.yaml:
k8s/apps/common/kustomization.yamlk8s/infra/common/network/external/kustomization.yaml
保持排序风格。验证 — kustomize build 跑三层:
app/ → k8s/apps/common/ → k8s/apps/staging/app/ → <category>/ → k8s/infra/staging/代码写完不自行提交。等用户审查同意后,再提 PR。
PR 合并后,触发 Flux 部署链并确认服务正常运行。
部署链路(详见 docs/ARCHITECTURE.md §8):
GitHub (main branch)
│
▼ flux bootstrap
k8s/clusters/staging/
├── repos.yaml → OCIRepository: app-template
│
├── infra.yml (Flux Kustomization, wait: true)
│ │ patches: sops + subst → 全部子级
│ ▼
│ k8s/infra/staging/ (kustomize build)
│ │ imports: ../common/{network, database, ...}
│ ▼
│ k8s/infra/common/{category}/kustomization.yaml
│ │
│ ▼
│ <app>/ks.yaml (子级 Flux Kustomization CRD)
│ │ sourceRef: GitRepository flux-system
│ │ path: ./app/
│ ▼
│ app/ → HelmRelease → Pod
│
└── apps.yml (Flux Kustomization, dependsOn: infra, wait: false)
│ patches: sops + subst → 全部子级
▼
k8s/apps/staging/ (kustomize build)
│ imports: ../common/
▼
k8s/apps/common/kustomization.yaml
│
▼
<app>/ks.yaml (子级 Flux Kustomization CRD)
│ sourceRef: GitRepository flux-system
│ path: ./app/
▼
app/ → HelmRelease → Pod
操作:
# 触发对应层
flux reconcile ks infra -n flux-system # infra 服务
flux reconcile ks apps -n flux-system # apps 服务
# 等具体 app 就绪
# apps 服务(通常是 Deployment)
kubectl rollout status deployment/<app> -n <namespace> --timeout=5m
# infra 服务(部分不是 Deployment,如 DaemonSet/StatefulSet)
kubectl get pods -n <namespace> -l app.kubernetes.io/name=<app> -w
Pod 未就绪时检查日志定位问题。
引入新服务时,根据服务消费 secret 的方式从三种模式中选一种:
新服务来了
│
├─ 1. 是不是公共值(多服务共享、极少变)?
│ ├─ MAIN_DOMAIN / CLOUDFLARE_TUNNEL_ID 等 → SOPS cluster-secrets
│ │ Flux 已自动通过 postBuild.substituteFrom 注入所有子 Kustomization
│ │ 直接写 ${MAIN_DOMAIN} 即可
│ └─ 服务私有 secret → 下一步
│
├─ 2. 服务只认 env var(如 karakeep)
│ └─ ExternalSecret + envFrom
│ ES 映射 key → 整包注入容器,服务工作不涉及配置
│
├─ 3. 服务要配置文件
│ ├─ 3a. 配置文件支持运行时 ${ENV_VAR}(如 go2rtc)
│ │ ├─ ConfigMap 存纯文本配置(git 版本管理)
│ │ ├─ ExternalSecret 只给 env var
│ │ ├─ 容器同时挂载 ConfigMap + envFrom Secret
│ │ └─ 运行时自解析 ${} → 优先选这种
│ │
│ ├─ 3b. 不支持运行时 ${},但配置量大/结构复杂
│ │ └─ ExternalSecret + templateFrom.configMap(如 cli-proxy-api)
│ │ ConfigMap 模板含 {{ .xxx }} 占位符
│ │ ES 引擎渲染后写入最终 Secret
│ │ 配置结构在 git 可追溯
│ │
│ └─ 3c. 配置小、和 secret 紧耦合
│ └─ ExternalSecret 内联模板(如 immich)
│ 配置直接写在 ES 的 template.data 里
│ 非敏感配置变更也需摸 KeyVault
│
└─ 4. 两种都行 → 优先 env var。env 太多(>10 个)退 3a/3b
${} 冲突 — 当配置文件的 ${ENV_VAR} 被 Flux 提前替换时(因为 Flux 在构建阶段对所有 YAML 做 ${VAR} 替换),有两种解法:
kustomize.toolkit.fluxcd.io/substitute: disabled 注解:加在 ks.yaml 的 metadata.annotations 上,禁用整个 Kustomization 的变量替换。代价是所有 ${VAR}(包括 ${TIMEZONE} 等)都失效,需在 HelmRelease 中用 YAML anchor 或硬编码替代。$$ 转义:在 YAML 值里用 $${VAR},kustomize 输出时转成 ${VAR},运行时程序自己解析。不影响 Kustomization 其他 ${VAR} 的替换。这个 Kustomization 还用到 ${TIMEZONE} 等其他变量时优先用这种方式。
选择原则:Kustomization 没有其他 ${VAR} 依赖 → 用 annotation;还有其他 ${VAR} 依赖 → 用 $$ 转义。extract(如 authelia 同时 extract authelia + mail + cloudnative-pg)。labels)、mergePolicy。ks.yaml → app/。path 指向正确(apps → ./k8s/apps/common/<app>/app,infra → ./k8s/infra/common/<category>/<app>/app)?kustomization.yaml 只引真实存在的文件?.agents/skills/home-ops-conventions/SKILL.md