lenaxia/k8s-mechanic

GitHub: lenaxia/k8s-mechanic

一个运行在集群内的 Kubernetes 智能故障修复控制器,通过 LLM agent 自动调查故障根因并在 GitOps 仓库中提交带修复建议的 Pull Request。

Stars: 36 | Forks: 1

# k8s-mechanic k8s-mechanic 是一个 Kubernetes 控制器,用于监控集群中的故障, 自动进行调查,并在您的 GitOps 仓库中创建带有修复建议的 Pull Request —— 这一切都无需离开您的集群。 当 Pod 发生 CrashLoopBackOff、Deployment 性能下降或节点进入 NotReady 状态时, mechanic 会生成一个集群内的 [OpenCode](https://opencode.ai) agent, 它会检查运行中的集群,在您的 GitOps 仓库中定位相关的 manifest, 确定根本原因,并开启一个 PR。您只需审查并合并即可。无需外部 operator, 无需外部数据库,也无需在集群外运行持久服务。 ## 功能概述 1. **检测故障** — 通过 Kubernetes API 原生监控 Pod、Deployment、StatefulSet、PVC、Node 和 Job 2. **按父资源去重** — 同一个 Deployment 的重复 Pod 重启只会触发一次调查,而不是每次重启触发一次 3. **稳定后再行动** — 可配置的时间窗口(默认:120秒)在分发任务前过滤掉瞬态故障 4. **集群内调查** — 一个具有只读 RBAC 权限的 agent Job 会克隆您的 GitOps 仓库,并检查运行中的集群 5. **开启 PR** — 包含结构化的 PR 正文:摘要、证据、根本原因、修复建议和置信度 **每次调用的三种可能结果:** | 结果 | 何时发生 | 动作 | |---|---|---| | 修复 PR | 确定了根本原因,置信度为中或高 | 开启一个带有针对性 manifest 更改的 PR | | 调查 PR | 根本原因不明或置信度低 | 开启一个带有调查报告并标记为 `needs-human-review` 的 PR | | 评论 | 该指纹已存在开启的 PR | 评论最新的发现;不创建新 PR | Agent prompt 中强制执行的硬性约束:永远不直接提交到 `main` 分支; 永远不触碰 GitOps 仓库中的 Kubernetes Secrets;每次调用只产生一个结果。 ## 功能特性 **[OpenCode Agentic 工作流](docs/WORKLOGS/0071_2026-02-23_epic08-pluggable-agent-complete.md)** — 调查由运行在您集群内的 [OpenCode](https://opencode.ai) 驱动。 支持任何 OpenAI 兼容的 LLM endpoint。计划推出更多 agent 后端。 **[检测](docs/WORKLOGS/0033_2026-02-22_epic09-native-provider-complete.md)** — 原生监控 Pod、Deployment、StatefulSet、PVC、Node 和 Job。 覆盖 `CrashLoopBackOff`、`ImagePullBackOff`、`OOMKilled`、降级的 Deployment、不可调度的 Pod、失败的 Job、PVC 供应失败以及不健康的 Node。 **[去重](docs/WORKLOGS/0011_2026-02-20_epic01-controller-core-logic.md)** — 发现的问题会根据父资源指纹 (`sha256(namespace + kind + parentObject + sorted errors)`) 进行去重。 同一个 Deployment 的重复 Pod 重启只会产生一次调查。 状态存储在 `RemediationJob` CRD 对象中 —— 可在 watcher 重启后保留,无需外部存储。 **[严重性分级](docs/WORKLOGS/0075_2026-02-24_epic24-severity-tiers-complete.md)** — 每个发现的问题都会根据检测到的状况被分类为 `critical`、`high`、`medium` 或 `low` (例如:CrashLoopBackOff 重启 >5 次 → critical;OOMKilled → high; 降级但可用的 Deployment → medium)。watcher Deployment 上的 `MIN_SEVERITY` 环境变量 将抑制低于配置阈值的发现。Agent 在运行时接收严重性 并相应地调整其调查深度 —— 对于 critical 级别达到最大的彻底性,对于 low 级别采取保守的 最小变更建议。 **[稳定窗口](docs/WORKLOGS/0030_2026-02-22_epic09-story12-stabilisation-window.md)** — 一个可配置的等待期(默认:120秒)在分发调查之前 抑制瞬态故障。 **[并发节流](docs/WORKLOGS/0011_2026-02-20_epic01-controller-core-logic.md)** — `maxConcurrentJobs`(默认:3)限制了同时运行的 agent Job。超出的发现会作为 `Pending` 排队,并在有可用槽位时分发。 **[可自定义的 Agent Prompt](docs/WORKLOGS/0071_2026-02-23_epic08-pluggable-agent-complete.md)** — 调查 prompt 从 ConfigMap 挂载, 并可以通过 `values.yaml` 中的 `prompt.coreOverride` / `prompt.agentOverride` 完全覆盖。 **[Prometheus 指标](docs/WORKLOGS/0038_2026-02-23_epic10-helm-chart-implementation.md)** — 可选的指标 Service 和 Prometheus Operator `ServiceMonitor`,用于 watcher 健康状况的可观测性。 **[自动关闭已解决的发现](docs/WORKLOGS/0091_2026-02-26_epic26-auto-close-resolved.md)** — 当 Kubernetes 发现的问题被清除时(Deployment 恢复、 PVC 供应完成、Node 恢复 Ready),watcher 会自动关闭 agent 开启的 GitHub PR。 适用于进行中的 Job(Pending/Dispatched/Running)以及集群自我修复后 PR 已过期的已成功 Job。 直接通过 REST API 使用 GitHub App 安装令牌 —— watcher 中不需要 `gh` CLI。 可通过 `watcher.prAutoClose: false` 选择退出。 **[感知 PR 合并的去重](https://github.com/lenaxia/k8s-mechanic/pull/23)** — 当 mechanic 开启的 PR 被合并时, `RemediationJob` 会以较短的 TTL(1小时)被标记为逻辑删除,而不是默认的 7 天 TTL。 这可以防止在 GitOps 协调器应用修复且集群稳定期间,相同的发现被立即重新调查。 **[Dry-run 模式](docs/WORKLOGS/0089_2026-02-25_epic20-dry-run-mode.md)** — 设置 `watcher.dryRun: true` 以运行完整的调查 管道而不开启任何 PR。Agent 会生成一份调查报告,写入到名为 `mechanic-dryrun-` 的 ConfigMap 中。适用于在 staging 环境中验证 mechanic 行为, 或在生产环境中启用新 LLM 模型之前进行验证。 **[GitHub App 令牌过期保护](docs/WORKLOGS/0088_2026-02-25_epic22-token-expiry-guard.md)** — 主 agent 容器在继续之前会检查 安装令牌的过期时间。如果令牌已过期或将在 60 秒内过期,Job 会快速失败并显示明确的错误, 而不是在调查深入时静默失败。 **[强制 Manifest 验证](docs/WORKLOGS/0087_2026-02-25_epic18-manifest-validation.md)** — 在向 GitOps 仓库提交任何更改之前, agent 会对每个修改过的 manifest 运行 `kubeconform`(对于 overlay 更改还会运行 `kustomize build`)。如果验证失败,agent 会开启一个标记为 `validation-failed` 的占位 PR, 其中包含完整的错误输出,而不是提交一个不符合 schema 的 manifest。 ### 安全性 **[Secret 脱敏](docs/WORKLOGS/0054_2026-02-23_story01-secret-redaction.md)** — 从集群状态(pod `Waiting.Message`、 节点状况消息等)提取的错误文本,在存储到 `RemediationJob` 或注入到 agent 之前, 会经过脱敏过滤器。模式包括 URL 凭证、 长度 ≥ 40 个字符的 base64 编码值,以及常见的 secret 密钥前缀(`password=`、 `token=`、`api-key=` 等)。 **[Prompt 注入检测](docs/WORKLOGS/0055_2026-02-23_story05-prompt-injection-defence.md)** — `Finding.Errors` 的每个字段限制为 500 个字符, 并在 prompt 中包装在显式的不可信数据信封中。注入 启发式规则(`ignore.*previous.*instructions`)会被检测并记录;可配置为 完全抑制该发现(`INJECTION_DETECTION_ACTION=suppress`)。 **[Agent 网络策略](docs/WORKLOGS/0057_2026-02-23_story02-network-policy.md)** — 可选的 `NetworkPolicy` 将 agent Job 的出站流量限制为 集群 API server、GitHub 和 LLM endpoint。通过 `values.yaml` 中的 `networkPolicy.enabled: true` 启用。需要支持 `NetworkPolicy` 的 CNI(Cilium、Calico 等)。 **[只读 Agent RBAC](docs/WORKLOGS/0016_2026-02-20_epic04-deploy-manifests.md)** — agent 仅在集群范围内持有 `get/list/watch` 权限。 它不能创建、修改或删除任何 Kubernetes 资源。所有集群更改都通过 Git 和您的 GitOps 协调器进行。 **[Namespace 作用域的 Agent RBAC](docs/WORKLOGS/0058_2026-02-23_story04-agent-rbac-scoping.md)** — `AGENT_RBAC_SCOPE=namespace` 将 agent 从 集群范围的 `ClusterRole` 切换为 namespace 作用域的 `Role`,从而限制 agent 只能读取您指定的 namespace。 **[结构化审计日志](docs/WORKLOGS/0056_2026-02-23_story03-audit-log.md)** — 所有抑制和分发决策都会发出带有 `audit: true` 的结构化日志行, 可从任何日志聚合系统(Loki、Elasticsearch、Datadog)查询,用于事后取证。 **[Trivy CVE 扫描](https://github.com/lenaxia/k8s-mechanic/actions)** — 每次发布时都会使用 [Trivy](https://trivy.dev) 扫描 `mechanic-watcher` 和 `mechanic-agent` 镜像 (`CRITICAL` 和 `HIGH`,忽略不可修复的)。如果检测到任何可修复的漏洞,构建将失败。上游预构建二进制文件中不可修复的 CVE(尚未使用所需 Go 版本发布的工具) 记录在 [`.trivyignore`](.trivyignore) 中,并带有用于重新评估的强制性到期日期。 **[短期 GitHub 凭证](docs/WORKLOGS/0014_2026-02-20_epic03-agent-image-complete.md)** — agent 永远不会持有长期有效的 PAT。在 init 容器中交换 GitHub App 安装令牌(1小时 TTL),并且永远不会暴露给主 agent 容器。 #### 强化模式 强化模式(`values.yaml` 中的 `agent.hardenKubectl: true`,默认关闭)在以下 始终开启的默认设置之上增加了额外的读取限制。 **始终开启(无论是否启用强化模式)** | 控制项 | 作用 | |---|---| | **kubectl 写入阻止** | `apply`、`create`、`delete`、`edit`、`patch`、`replace`、`scale`、`label`、`annotate`、`taint`、`drain`、`cordon`、`uncordon`、`rollout restart/undo` —— 全部以退出码 1 终止。所有集群更改都通过 Git 和您的 GitOps 协调器进行。 | | **kubectl 输出脱敏** | 所有 `kubectl` 输出都通过管道传递给 `redact` 二进制文件。任何匹配已知 secret 模式(`base64 ≥ 40 个字符`、`password=…`、`token=…` 等)的值都将被替换为 `[REDACTED]`。如果缺少 `redact`,wrapper 将硬性失败。 | | **工具输出脱敏** | `helm`、`flux`、`sops`、`talosctl`、`yq`、`stern`、`kubeconform`、`kustomize`、`age`、`age-keygen` 和 `gh` 都具有 PATH 覆盖包装器,通过管道将输出传递给 `redact`。包装器闭包失败 —— 如果 `redact` 二进制文件不存在,工具将以退出码 1 终止。 | | **环境变量中无 secret** | agent 进程环境中不存在任何凭证或 API 密钥。所有秘密材料在 agent 启动前写入文件,并从环境中完全移除。 | **仅在强化模式下** | 控制项 | 增加的功能 | |---|---| | **kubectl secret 阻止** | `get secret(s)`、`describe secret(s)` 和 `get all` 被阻止。Kubernetes Secrets 永远不会通过 `kubectl` 到达 LLM 上下文。 | | **kubectl exec / port-forward 阻止** | `exec` 和 `port-forward` 被阻止。agent 无法开启交互式会话或将端口转发到集群工作负载。 | **数据渗出测试** 安全控制措施在常规的红蓝对抗中得到了验证。结果和完整的渗出泄漏记录位于 [`docs/SECURITY/EXFIL_LEAK_REGISTRY.md`](docs/SECURITY/EXFIL_LEAK_REGISTRY.md)。 ## 快速开始 ### 前置条件 - Kubernetes >= 1.28 - Helm >= 3.14 - 一个安装在 GitOps 仓库上的 GitHub App,具有以下权限:Contents (write)、Pull Requests (write)、Issues (write) - 兼容 OpenAI 的 LLM API 密钥 #### GitHub App 权限 | 权限 | 级别 | 目的 | |---|---|---| | Contents | Write | 克隆仓库、创建分支、推送更改 | | Pull requests | Write | 创建和评论 Pull Request | | Issues | Write | 在 PR 描述中引用 issue | ### 1. 创建所需的 Secret ``` kubectl create namespace mechanic ``` #### github-app `github-app` Secret 必须包含三个键: ``` apiVersion: v1 kind: Secret metadata: name: github-app namespace: mechanic stringData: app-id: "" # numeric ID from https://github.com/settings/apps/ installation-id: "12345678" # numeric ID from the installation URL (see below) private-key: | ``` **App ID** 显示在您的 GitHub App 设置页面上,地址为 `https://github.com/settings/apps/`。 每个用户创建自己的 GitHub App;项目作者无法看到您的凭证、令牌或仓库。 **Installation ID** 是您查看应用安装情况时 URL 中的数字后缀: `https://github.com/organizations//settings/installations/` (个人账户:`https://github.com/settings/installations/`)。 它也可以通过 App JWT 认证的 `GET https://api.github.com/app/installations` 返回。 私钥仅在 agent Job 的 init 容器中用于交换短期安装令牌(1小时 TTL)。 它永远不会被注入到主 agent 容器中。 #### llm-credentials-opencode `llm-credentials-opencode` secret 将完整的 [OpenCode 配置](https://opencode.ai/docs) 作为其 `provider-config` 键保存。 正确的 schema 应将 `model` 作为**顶层**键(格式:`"/"`); `options` 属于 `provider.` **内部**,而不是在根级别。 OpenCode 是目前唯一可用的 agentic provider,更多选项将在稍后推出。 **原生 OpenAI (`api.openai.com`)** ``` apiVersion: v1 kind: Secret metadata: name: llm-credentials-opencode namespace: mechanic stringData: provider-config: | { "$schema": "https://opencode.ai/config.json", "provider": { "openai": { "apiKey": "sk-" } }, "model": "openai/gpt-4o" } ``` **自定义 OpenAI 兼容端点(自托管、Ollama、Azure 等)** 对于任何不是 `api.openai.com` 的端点,或者使用未在内置 OpenAI provider 中注册的模型名称, 您必须使用 `"npm": "@ai-sdk/openai-compatible"` 定义一个自定义 provider。 您不能将内置的 `openai` provider 用于不同的 base URL。 ``` apiVersion: v1 kind: Secret metadata: name: llm-credentials-opencode namespace: mechanic stringData: provider-config: | { "$schema": "https://opencode.ai/config.json", "provider": { "myprovider": { "npm": "@ai-sdk/openai-compatible", "name": "My Provider", "options": { "baseURL": "https://my-llm-endpoint/v1", "apiKey": "sk-" }, "models": { "my-model-id": { "name": "My Model Name" } } } }, "model": "myprovider/my-model-id" } ``` **其他 provider** OpenCode 支持 75 个以上的 provider。任何具有 OpenAI 兼容 API 的 provider (Ollama、LM Studio、llama.cpp、Azure OpenAI、Groq、Together AI、OpenRouter、 DeepSeek 等等)都可以使用上述自定义 provider 模式运行。 对于内置 provider(Anthropic、Amazon Bedrock、Google Vertex AI、GitHub Copilot 等),配置结构略有不同 —— 请查阅 OpenCode 文档中的完整 provider 目录: - **Provider 目录** — [opencode.ai/docs/providers](https://opencode.ai/docs/providers/) - **内置 provider**(Anthropic、Bedrock、Vertex、Groq 等)— 每个的配置示例 - **自定义 provider 模式** — [opencode.ai/docs/providers#custom-provider](https://opencode.ai/docs/providers/#custom-provider) ### 2. 使用 Helm 安装 ``` helm install mechanic oci://ghcr.io/lenaxia/charts/mechanic \ --namespace mechanic \ --create-namespace \ --set gitops.repo=myorg/my-gitops-repo \ --set gitops.manifestRoot=kubernetes ``` 或从本地克隆安装: ``` helm install mechanic charts/mechanic/ \ --namespace mechanic \ --set gitops.repo=myorg/my-gitops-repo \ --set gitops.manifestRoot=kubernetes ``` ### 3. 验证 ``` kubectl get deployment -n mechanic kubectl get rjob -n mechanic # 显示特定 RemediationJob 的 lifecycle events: kubectl describe rjob -n mechanic ``` ## 配置 ### Helm values 参考 所有 `values.yaml` 键及其默认值: | 键 | 默认值 | 描述 | |---|---|---| | `image.repository` | `ghcr.io/lenaxia/mechanic-watcher` | Watcher 镜像仓库 | | `image.tag` | `""` (使用 `Chart.appVersion`) | Watcher 镜像标签 | | `image.pullPolicy` | `IfNotPresent` | 镜像拉取策略 | | `agent.image.repository` | `ghcr.io/lenaxia/mechanic-agent` | Agent 镜像仓库 | | `agent.image.tag` | `""` (使用 `Chart.appVersion`) | Agent 镜像标签 | | `gitops.repo` | **必填** | GitOps 仓库,格式为 `org/repo` | | `gitops.manifestRoot` | **必填** | manifest 根目录在仓库中的路径 | | `watcher.stabilisationWindowSeconds` | `120` | 发现的问题在分发前必须持续的秒数 | | `watcher.maxConcurrentJobs` | `3` | 最大同时运行的 agent Job 数 | | `watcher.minSeverity` | `low` | 分发的最低严重性:`critical`、`high`、`medium` 或 `low` | | `watcher.remediationJobTTLSeconds` | `604800` | 已完成的 RemediationJob 对象的 TTL(7天) | | `watcher.sinkType` | `github` | 创建 PR 的接收器类型 | | `watcher.logLevel` | `info` | 日志级别:debug、info、warn、error | | `watcher.llmProvider` | `openai` | LLM 就绪门控:`openai` 启用;留空则禁用 | | `watcher.injectionDetectionAction` | `log` | 当提示注入启发式规则触发时要执行的操作:`log` 或 `suppress` | | `watcher.maxInvestigationRetries` | `3` | 每个 `RemediationJob` 在永久失败之前的最大 Job 重试次数 | | `watcher.agentRBACScope` | `cluster` | agent 的 RBAC 作用域:`cluster` 或 `namespace` | | `watcher.agentWatchNamespaces` | `""` | agent RBAC 作用域的逗号分隔命名空间。当 `agentRBACScope=namespace` 时为必填 | | `watcher.watchNamespaces` | `""` | watcher 监控故障的逗号分隔命名空间。留空 = 所有命名空间 | | `watcher.excludeNamespaces` | `""` | watcher 忽略的逗号分隔命名空间。留空 = 不排除 | | `agentType` | `opencode` | Agent 运行器类型:`opencode`(可用)或 `claude`(存根,尚不可用)。控制使用哪个 `llm-credentials-` Secret。Secret 名称是编译时常量 —— 它们不能通过 Helm values 覆盖。 | | `prompt.coreOverride` | `""` | 完整核心提示覆盖(替换内置的 `files/prompts/core.txt`) | | `prompt.agentOverride` | `""` | 完整 agent 提示覆盖(替换内置的 `files/prompts/.txt`) | | `rbac.create` | `true` | 创建 RBAC 资源 | | `createNamespace` | `false` | 如果 `Release.Namespace` 不存在则创建它 | | `metrics.enabled` | `false` | 在端口 8080 上暴露指标 Service | | `metrics.serviceMonitor.enabled` | `false` | 创建 Prometheus Operator ServiceMonitor | | `metrics.serviceMonitor.interval` | `30s` | Prometheus 抓取间隔 | | `metrics.serviceMonitor.scrapeTimeout` | `10s` | Prometheus 抓取超时 | | `metrics.serviceMonitor.labels` | `{}` | ServiceMonitor 的额外标签 | | `networkPolicy.enabled` | `false` | 将 agent Job 的出站流量限制为 API server、GitHub 和 LLM endpoint | | `networkPolicy.apiServerPort` | `6443` | Kubernetes API server 端口(某些发行版使用 `443`) | | `networkPolicy.additionalEgressRules` | `[]` | 逐字附加的额外出站规则(例如,通过 CIDR 限制 LLM endpoint) | | `watcher.prAutoClose` | `true` | 当底层发现的问题解决时自动关闭 GitHub PR。设置为 `false` 以保留 PR 等待手动审查 | | `watcher.dryRun` | `false` | 运行完整的调查管道而不开启 PR。报告将写入到名为 `mechanic-dryrun-` 的 ConfigMap 中 | | `agent.hardenKubectl` | `false` | 启用强化模式 —— 除了始终开启的写入阻止外,还阻止 `kubectl get/describe secret`、`get all`、`exec` 和 `port-forward` | ### 配置验证 Watcher 在启动时验证配置并显示明确的错误消息。 **数值验证:** - `MAX_CONCURRENT_JOBS`:必须 > 0 - `REMEDIATION_JOB_TTL_SECONDS`:必须 > 0 - `STABILISATION_WINDOW_SECONDS`:必须 ≥ 0 **枚举验证:** - `MIN_SEVERITY`:必须是 `critical`、`high`、`medium`、`low` 之一(如果不存在,默认为 `low`) **格式验证:** - `GITOPS_REPO`:必须是 `owner/repo` 格式 ## 工作原理 ``` %%{init: {'flowchart': {'curve': 'linear'}}}%% flowchart TD subgraph watcher["mechanic-watcher — Deployment"] SPR["SourceProviderReconcilers
one per resource type
─────────────────────
watches Pods, Deployments,
StatefulSets, PVCs, Nodes, Jobs
extracts findings
deduplicates by fingerprint"] RJR["RemediationJobReconciler
─────────────────────
watches RemediationJob CRDs
enforces MAX_CONCURRENT_JOBS
syncs Job status back"] end RJ["RemediationJob CRDs
rjob
─────────────────────
durable dedup state
survives restarts"] AJ["mechanic-agent Job
one per finding
─────────────────────
init: git clone repo
main: opencode run
kubectl read-only
gh pr create"] GH["GitOps repository
GitHub"] SPR -->|creates| RJ RJ -->|watched by| RJR RJR -->|creates| AJ AJ -->|opens PR| GH ``` ### Agent 的工作内容 Agent 在集群内以只读 RBAC 权限运行 [OpenCode](https://opencode.ai),并遵循结构化的调查流程: 1. 检查此指纹是否已有开启的 PR —— 如果找到,则在其上评论并退出 2. 对故障资源执行 `kubectl describe` 和 `kubectl get events` 3. 检查相关资源(所属 Deployment、Endpoints、PV 等) 4. 在克隆的 GitOps 仓库中定位相关的 manifest 5. 使用 `flux get all` 和 `helm list` 检查 Flux/Helm 状态 6. 确定根本原因并分配置信度(高 / 中 / 低) 7. 使用 `kubeconform` 和 `kustomize build` 验证建议的更改 8. 开启一个包含结构化正文的 pull request:摘要、证据、根本原因、修复建议、置信度 ### `RemediationJob` CRD 每个唯一的发现都由一个 `RemediationJob` 对象(`rjob`)跟踪。 ``` kubectl get rjob -n mechanic ``` ``` NAME PHASE KIND PARENT JOB AGE mechanic-a3f9c2b14d8e Succeeded Pod Deployment/my-app mechanic-agent-a3f9c2b14d8e 8m mechanic-7bc1d3e90f21 Dispatched Deployment Deployment/api-server mechanic-agent-7bc1d3e90f21 2m mechanic-f4e2a1c85b67 Failed Node Node/worker-03 1h ``` #### RemediationJob 生命周期 ``` stateDiagram-v2 [*] --> Pending : finding detected Pending --> Dispatched : concurrent-job slot available Pending --> Cancelled : source object deleted Dispatched --> Running : Job pod scheduled Running --> Succeeded : agent Job completed Running --> Failed : exit non-zero or deadline exceeded Running --> Cancelled : source object deleted Failed --> Dispatched : retry (RetryCount < MaxRetries) Failed --> PermanentlyFailed : RetryCount >= MaxRetries Succeeded --> [*] Cancelled --> [*] PermanentlyFailed --> [*] ``` - **Pending** — 已检测到发现的问题,正在等待并发 Job 槽位 - **Dispatched** — 已创建 `batch/v1 Job`,等待 Pod 调度 - **Running** — agent Pod 正在执行 - **Succeeded** — agent Job 已完成;如果开启了 PR,`status.prRef` 将包含 PR URL - **Failed** — agent Job 失败(退出码非零或超过截止时间);如果 `RetryCount < MaxRetries` 则重新排队 - **PermanentlyFailed** — `RetryCount` 已达到 `MaxRetries`;不再分发;可通过 `kubectl describe rjob ` 查看 - **Cancelled** — 调查进行期间源对象被删除 ### 按资源注释控制 三个注释控制着 mechanic 在任何受监控资源(Pod、Deployment、StatefulSet、PVC、Node、Job) 或整个 Namespace 上的行为: | 注释 | 值 | 效果 | |---|---|---| | `mechanic.io/enabled` | `"false"` | 永久抑制来自此资源的所有发现 | | `mechanic.io/skip-until` | `"YYYY-MM-DD"` | 抑制发现直到此日期的 UTC 当天结束 | | `mechanic.io/priority` | `"critical"` | 绕过稳定窗口 —— 立即分发 | **示例:** ``` # 永久禁用对某个 deployment 的 investigations kubectl annotate deployment my-app mechanic.io/enabled=false # 将吵闹的 node 静音至维护窗口之后 kubectl annotate node worker-03 mechanic.io/skip-until=2026-03-15 # 在一个关键的 deployment 上立即 dispatch(无 stabilisation window) kubectl annotate deployment api-server mechanic.io/priority=critical ``` **Namespace 级别控制:** 对 `Namespace` 对象本身进行注释将应用于该命名空间中的所有资源。 这将抑制每一个发现,而不管资源自身的注释如何: ``` # 禁用 kube-system namespace 中的所有 mechanic 活动 kubectl annotate namespace kube-system mechanic.io/enabled=false # 将 staging 中的所有 findings 抑制至指定日期 kubectl annotate namespace staging mechanic.io/skip-until=2026-04-01 ``` `skip-until` 日期是包含在内的:在指定日期*之后*的 UTC 午夜之前,发现都会被抑制。 ### 组件 | 组件 | 描述 | |---|---| | `mechanic-watcher` | Go 控制器(controller-runtime),监控 Kubernetes 资源、管理 `RemediationJob` CRD 并创建 agent Job | | `mechanic-agent` | 包含 opencode + kubectl + helm + flux + gh 及支持调查工具的 Docker 镜像 | ### Agent 镜像工具 | 工具 | 版本 | 目的 | |---|---|---| | `opencode` | `1.2.10` | AI agent 驱动程序 | | `kubectl` | `1.35.1` | 集群检查(只读) | | `helm` | `3.20.0` | Chart 元数据,模板渲染 | | `flux` | `2.8.0` | Flux 状态、追踪、差异对比 | | `kustomize` | `5.8.1` | 渲染并验证 Kustomize overlay | | `gh` | 最新稳定版 | PR 创建、列表、评论 | | `kubeconform` | `0.7.0` | Kubernetes manifest schema 验证 | | `yq` | `4.52.4` | YAML 处理 | | `jq` | apt | JSON 处理 | | `stern` | `1.33.1` | 多 Pod 日志尾部追踪 | | `sops` | `3.12.1` | 解密 SOPS 加密的 secret | | `age` | `1.3.1` | 解密 age 加密的文件 | | `talosctl` | `1.12.4` | Talos 节点检查(需要 `talosconfig` 挂载) | 所有二进制文件均从官方发布版本获取,并经过 SHA256 校验和验证。 Agent 以非 root 用户运行(`uid=1000`)。 ## 路线图 正在积极开发或计划中的功能: | 领域 | 功能 | 状态 | |---|---|---| | 可操作性 | `RemediationJob` 上的 Kubernetes Events(`kubectl describe rjob` 显示生命周期) | 已发布 | | 可操作性 | Dry-run 模式 —— 在不开启 PR 的情况下进行调查 | 已发布 | | 可靠性 | `PermanentlyFailed` 阶段 —— 具有死信逻辑删除的重试上限 | 已发布 | | 可靠性 | GitHub App 令牌过期快速失败保护 | 已 | | 准确性 | Namespace 作用域的 provider 过滤(`WATCH_NAMESPACES`、`EXCLUDE_NAMESPACES`) | 已发布 | | 准确性 | 按资源选择性退出注释(`mechanic.io/enabled`、`mechanic.io/skip-until`、`mechanic.io/priority`) | 已发布 | | 准确性 | 多信号关联(相关发现分组到一个调查中) | 已发布 | | 准确性 | 强制性 PR 前的 manifest 验证 | 已发布 | | 影响力 | 发现解决后自动关闭 PR | 已发布 | | 影响力 | PR 反馈迭代(回复审查者评论) | 已延期 | | 影响力 | 按需手动触发 | 已延期 | | 影响力 | GitLab 和 Gitea 接收器支持 | 已评估 | | 信号源 | Prometheus / Alertmanager 源 provider | 已评估 | | 信号源 | cert-manager 证书过期 provider | 已评估 | 有关带有价值/复杂性评级和实施说明的完整产品待办事项列表,请参阅 [`docs/BACKLOG/FEATURE_TRACKER.md`](docs/BACKLOG/FEATURE_TRACKER.md)。 ## 文档 - [`docs/DESIGN/HLD.md`](docs/DESIGN/HLD.md) — 架构和设计决策 - [`docs/DESIGN/lld/`](docs/DESIGN/lld/) — 组件级低级别设计 - [`docs/BACKLOG/`](docs/BACKLOG/) — 实施待办事项和功能跟踪器 - [`README-LLM.md`](README-LLM.md) — LLM 实施指南 ## 开发 ### 前置条件 - Go 1.24+ - [`golangci-lint`](https://golangci-lint.run/usage/install/) — 扩展的 linter 套件 - [`gitleaks`](https://github.com/zricethezav/gitleaks) — secret 扫描器 使用 `go install` 安装两者: ``` go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest go install github.com/zricethezav/gitleaks/v8@latest ``` ### Git hooks 克隆后,安装一次 pre-commit hook: ``` make install-hooks ``` 该 hook 在每次 `git commit` 时运行并执行两项检查: | 检查 | 工具 | 捕获内容 | |---|---|---| | Secret 扫描 | `gitleaks` | 暂存文件中的 API 密钥、令牌、凭证 | | Lint | `golangci-lint` | 类型错误、未使用的代码、安全问题、格式问题 | 要在紧急情况下绕过:`git commit --no-verify` ### 常用 make 目标 | 目标 | 描述 | |---|---| | `make lint` | 快速 `go vet` 检查 | | `make lint-full` | 完整的 `golangci-lint` 运行(与 pre-commit 相同) | | `make lint-secrets` | 使用 `gitleaks` 进行完整仓库 secret 扫描 | | `make lint-security` | `gosec` HIGH/CRITICAL 安全检查 | | `make test` | 带有竞态检测器的完整测试套件 | | `make install-hooks` | 克隆后(重新)安装 git hooks | ## 社区 - **GitHub Discussions** — [github.com/lenaxia/k8s-mechanic/discussions](https://github.com/lenaxia/k8s-mechanic/discussions) — 提问、想法、架构讨论和展示与分享 - **GitHub Issues** — 错误和功能请求 ### 贡献 有关开发环境设置、编码标准、DCO 要求以及如何寻找适合新手的 issue,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。 ### 治理 有关项目的贡献者阶梯、决策过程以及如何成为维护者的信息,请参阅 [GOVERNANCE.md](GOVERNANCE.md)。 当前维护者列表请见 [MAINTAINERS.md](MAINTAINERS.md)。 ### GitHub 仓库主题 此仓库上设置了以下主题以辅助发现。如果您正在维护分支或相关项目, 可能需要应用相同的集合: `kubernetes` `gitops` `devops` `cloud-native` `operator` `controller` `remediation` `self-healing` `argocd` `flux` `automation` 主题通过 GitHub Web UI 配置:仓库页面 → "About" 旁边的齿轮图标 → Topics。 ## 许可证 Apache 2.0 ## 开发实践 本项目始终遵循结构化的 SDLC(软件开发生命周期)实践: - **待办事项驱动** — 所有功能和史诗都记录在 [`docs/BACKLOG/`](docs/BACKLOG/) 中, 在开始实施之前,具有明确的用户故事拆分、验收标准和价值/复杂性评级。 - **经过安全审查** — [Epic 12](docs/BACKLOG/epic12-security-review/README.md) 针对 mechanic 的完整攻击面运行了 结构化安全审计:secret 脱敏、提示注入检测、网络策略、RBAC 作用域、结构化审计日志, 以及带有文档化发现的正式渗透测试计划。所有 HIGH/CRITICAL 级别的发现都在史诗关闭前 得到了修复。 - **文档齐全** — 每个重要的会话都记录在 [`docs/WORKLOGS/`](docs/WORKLOGS/) 中, 捕获了设计决策、实施说明以及发生更改背后的原因。 开发过程是 AI 加速的(主要是 [OpenCode](https://opencode.ai)),这使得 项目能够快速推进而不损害流程的严谨性。该流程确保了工作内容的可问责性。
标签:AIOps, CISA项目, DNS解析, EVTX分析, GitOps, Human-in-the-loop, K8s控制器, RBAC, StruQ, 安全防护, 容器编排, 开源项目, 持续部署, 故障排查, 故障自愈, 日志审计, 智能运维, 机密信息脱敏, 模块化设计, 自动化修复, 自动提交PR, 请求拦截, 集群监控