Author SHA1 Message Date
panxiao81 fee5bbccb3 记录 iam-login 浏览器交互与前后端交付边界
docs / check (pull_request) Successful in 10m26s
2026-09-25 19:46:00 +00:00
panxiao81 409e350c83 记录 DRBD quorum 事故复盘与 sandbox 恢复流程
docs / check (push) Successful in 15s
2026-09-25 18:09:49 +00:00
panxiao81 a8479178f3 补充告警 Source 与 Grafana Alertmanager 使用入口
docs / check (push) Successful in 40s
2026-09-25 18:06:56 +00:00
panxiao81 d5ad5ee568 记录基础监控上线与 Prometheus CRD 优先约定
docs / check (push) Successful in 31s
2026-09-25 17:55:12 +00:00
panxiao81 9bd67a36ba 盘点监控实际覆盖与告警缺口并明确补齐顺序
docs / check (push) Successful in 4m41s
2026-09-25 17:32:36 +00:00
panxiao81 39db8406f8 记录 kubelet 采集上限与旧 Docker 目标清理
docs / check (push) Successful in 13m4s
2026-09-25 17:24:02 +00:00
panxiao81 cad034148f 记录 Telegram 告警接入与触发恢复链路验证
docs / check (push) Failing after 13m30s
2026-09-25 17:18:58 +00:00
panxiao81 90764def8a 记录 iam-login 独立仓库与 Spring Native 实现方向
docs / check (push) Successful in 53s
2026-09-25 16:47:18 +00:00
panxiao81 045c28b5c2 明确人类认证状态机边界并比较 ZITADEL 与 Kratos
docs / check (push) Successful in 1m32s
2026-09-25 15:55:17 +00:00
panxiao81 1dee295639 docs: 同步 Instance 合并与应用凭据存储切片
docs / check (push) Successful in 33s
2026-09-25 15:45:14 +00:00
panxiao81 040b68cc25 docs: 确认 Hydra 人类登录 PoC 验收通过
docs / check (push) Successful in 15s
2026-09-25 14:02:55 +00:00
panxiao81 d8a18793f2 docs: 记录 Hydra 人类登录 PoC 部署与验收边界
docs / check (push) Successful in 16s
2026-09-25 14:01:03 +00:00
panxiao81 3b0ca2245a docs: 关联 Instance 观测 PR 与源码
docs / check (push) Failing after 12m23s
2026-09-25 13:35:02 +00:00
panxiao81 6c0fdc7ecb docs: 记录独立 IAM 与 AI agent 身份架构草案
docs / check (push) Successful in 18s
2026-09-25 13:18:15 +00:00
panxiao81 c1a00cc28e docs: 记录 Instance 观测实现的本地提交
docs / check (push) Successful in 22s
2026-09-25 11:35:38 +00:00
panxiao81 388e3f86f4 docs: 同步 Database API 合并与原生管理权限方案
docs / check (push) Successful in 13s
2026-09-25 11:34:14 +00:00
panxiao81 106fc29001 docs: 合入 Ayatori 设计并改为文档直接更新 main
docs / check (push) Successful in 1m2s
2026-09-25 04:14:40 +00:00
panxiao81 2d408906b4 docs: 关联 Ayatori Database PR #10
docs / check (pull_request) Successful in 26s
2026-09-25 04:12:04 +00:00
panxiao81 eed96d3494 docs: 同步 Database API 与绑定分层合同
关联 Ayatori 本地提交 7e9e8e828bfcbdc8d4e2fcb6bc3d13727712a82c;记录已确认设计、绑定测试与尚未实现的供应和删除清理边界。两仓库尚未推送,远端来源待补齐。
2026-09-25 04:10:26 +00:00
panxiao81 de13ab813c docs: 确认 Database 设计与 CI 去重已合并
docs / check (pull_request) Successful in 9s
2026-09-24 17:23:27 +00:00
panxiao81 7ba880cb71 docs: 记录 Ayatori PR 验证与手动复验约定
docs / check (pull_request) Successful in 5m23s
2026-09-24 16:59:18 +00:00
panxiao81 78d0a8c03b docs: 更新 registry 撤除状态与已推送来源
docs / check (pull_request) Successful in 20s
2026-09-24 16:33:24 +00:00
panxiao81 d8f20c017e docs: 同步 Database 资源与申请分离设计
关联 Ayatori 本地提交 6db8a495fb9f8981d336c9e6288253628ab478b6;两仓库均未推送。
2026-09-24 16:21:53 +00:00
panxiao81 4f6b916ae5 docs: 更新 runner 默认提供 Docker 的接口约定
docs / check (pull_request) Successful in 24s
2026-09-24 08:29:55 +00:00
panxiao81 172c17bfa3 docs: 固定已合并的 Ayatori Database ADR 来源
docs / check (pull_request) Successful in 14s
2026-09-21 06:34:31 +00:00
panxiao81 8a6ce1d1b1 Merge pull request '记录 CI Actions 身份与依赖入口' (#6) from docs/ci-actions into main
docs / check (push) Failing after 34s
2026-09-21 03:32:37 +00:00
panxiao81 bf74d55813 记录 CI Actions 身份与依赖入口
docs / check (pull_request) Failing after 41s
2026-09-21 03:32:09 +00:00
panxiao81 0dbabe9ccd Merge pull request '记录 Nexus OCI 与 BuildKit 验收' (#5) from docs/nexus-oci-verification into main
docs / check (push) Successful in 20s
2026-09-20 20:48:23 +00:00
panxiao81 aae6138fa5 记录 Nexus OCI 与 BuildKit 验收
docs / check (pull_request) Successful in 22s
2026-09-20 20:48:05 +00:00
panxiao81 e37957f12d 修正 Ayatori DBaaS 设计来源链接
docs / check (pull_request) Successful in 38s
2026-09-20 20:44:03 +00:00
panxiao81 42bcf8190e Merge pull request '记录 Nexus POC 现场验收结果' (#4) from docs/nexus-live-verification into main
docs / check (push) Successful in 46s
2026-09-20 20:32:46 +00:00
panxiao81 0aaf689e2b 明确 DBaaS 完整设计合同直接复用
docs / check (pull_request) Successful in 34s
2026-09-20 20:30:35 +00:00
panxiao81 0eb3f81726 记录 Nexus POC 现场验收结果
docs / check (pull_request) Successful in 10s
2026-09-20 20:28:24 +00:00
panxiao81 6d614d8d08 记录 Database API 统一到 Ayatori 域
docs / check (pull_request) Successful in 17s
2026-09-20 20:20:38 +00:00
panxiao81 6863474c01 明确 DBaaS 可无兼容负担重构
docs / check (pull_request) Successful in 36s
2026-09-20 20:11:57 +00:00
panxiao81 e43442c266 记录 Compute 方向与 DBaaS 合并决定
docs / check (pull_request) Successful in 39s
2026-09-20 20:02:10 +00:00
panxiao81 adf2812767 记录内置 API 与实现组件解耦原则
docs / check (pull_request) Successful in 27s
2026-09-20 19:52:58 +00:00
panxiao81 ceb58eb42b 补充 Ayatori 需求驱动的产品边界 2026-09-20 19:52:58 +00:00
panxiao81 8d0992f039 记录 Ayatori 控制面架构边界 2026-09-20 19:52:57 +00:00
panxiao81 7fdc97e02b Merge pull request '记录 Nexus 制品仓库 POC' (#2) from docs/nexus-poc into main
docs / check (push) Successful in 28s
Reviewed-on: #2
2026-09-20 19:49:16 +00:00
panxiao81 23ec3f4f5c 记录 Nexus 制品仓库 POC
docs / check (pull_request) Failing after 0s
2026-09-18 19:11:28 +00:00
panxiao81 56cf76a358 Merge pull request '迁移旧工作区的 DHCP 与 Samba 维护记录' (#1) from docs/migrate-old-workspace-notes into main
docs / check (push) Successful in 14s
Reviewed-on: #1
2026-09-17 13:27:32 +00:00
panxiao81 4f27e2c69e 迁移 DHCP 与 Samba 现场维护记录
docs / check (pull_request) Successful in 19s
2026-09-17 13:20:39 +00:00
panxiao81 1e24987e4f 在动态 Pod 内直接运行文档检查,避免依赖 Docker socket
docs / check (push) Successful in 19s
2026-09-16 18:52:03 +00:00
panxiao81 e394b2612d 添加文档自动检查、Actions 工作流与 PR 维护模板
docs / check (push) Failing after 0s
2026-09-16 18:50:57 +00:00
panxiao81 cf4430526a 整理任务导航与源码版本追溯并暂缓原仓库文档同步 2026-09-16 18:45:34 +00:00
panxiao81 b177741efb 补充基础设施使用入口并明确 IaC 配置优先规则 2026-09-16 18:41:38 +00:00
panxiao81 64ca735822 补充新服务的 DNS、证书与网关发布指南 2026-09-16 18:35:47 +00:00
panxiao81 38530404a6 补充文档转换、上下文检索与应用发信指南 2026-09-16 18:26:04 +00:00
panxiao81 a50c66960d 补充秘密投射、本地存储与集群 DNS 使用指南 2026-09-16 18:21:46 +00:00
panxiao81 e6cd82e606 补充网关与远程客户端指南并归档 codex-proxy 状态 2026-09-16 18:17:09 +00:00
panxiao81 c2c3a2d74b 补充共享 PostgreSQL 应用接入与使用指南 2026-09-16 18:09:16 +00:00
panxiao81 8f71414f5c 补充 OpenBao 与 NetBox 日常使用指南 2026-09-16 16:35:17 +00:00
panxiao81 1bf081672c 补充 zot 镜像发布与 SeaweedFS S3 客户端使用指南 2026-09-16 16:19:47 +00:00
panxiao81 71225289c9 更新动态 runner 启用阶段与总并发并调整入门 workflow 2026-09-16 16:16:46 +00:00
panxiao81 f19c568817 补充 Gitea Actions 与 Grafana 面向使用者的入门指南 2026-09-16 16:11:19 +00:00
panxiao81 2076deb40f 确认旧监控清理 PR #73 已合并并移除交付待办 2026-09-16 16:06:19 +00:00
panxiao81 f5bb60e2ac 同步旧监控清理分支已推送的交付状态 2026-09-16 15:53:51 +00:00
panxiao81 46aac5344b 结束首轮状态核实并分离后续文档完善事项 2026-09-16 15:52:01 +00:00
panxiao81 3b3c67c48a 记录旧监控配置与数据卷已按维护者要求删除 2026-09-16 15:50:53 +00:00
50 changed files with 3956 additions and 135 deletions
+20
View File
@@ -0,0 +1,20 @@
## 改了什么
说明具体问题、修改后的使用方法或事实;纯文字修正可简写。
## 依据
关联源码 commit/PR、ticket 或带日期的维护者说明。若来自未提交工作区,明确标注。
## 验证与范围
填写本地检查/CI 结果。现场是否查询、验证了什么、哪些示例未执行?
没有现场验证时,不因编辑文字而刷新 last_verified。
## 文档同步
- [ ] 涉及的服务页已更新;新增/退役服务已同步服务总览。
- [ ] 入口或设计变化已更新相关任务导航/架构约束(不适用可注明)。
- [ ] 已注明来源与尚未完成的部分,未包含实际凭据。
原仓库 README 同步目前暂缓,不是本 PR 的必做项。
+26
View File
@@ -0,0 +1,26 @@
name: docs
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
check:
runs-on: [self-hosted, pod]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install checker dependencies
run: |
python3 -m venv .venv
.venv/bin/python -m pip install --disable-pip-version-check -r requirements-docs.txt
- name: Test checker
run: .venv/bin/python -m unittest discover -s tests -v
- name: Check documentation
run: .venv/bin/python scripts/check_docs.py
- name: Check whitespace
run: git show --format= --check HEAD
+3
View File
@@ -6,3 +6,6 @@ node_modules/
.env
.env.*
!.env.example
.venv/
__pycache__/
*.pyc
+5 -1
View File
@@ -1,13 +1,16 @@
# 人与 AI 共用的知识库
先读 README.md,按任务从 services/index.md 和 architecture/constraints.md 查找资料,
先读 README.md,按 guides/task-index.md 定位所需服务,再读 services/index.md 和 architecture/constraints.md,
并检查 verification.md 中的相关冲突。不要求把整个仓库一次性放入上下文。
- 原仓库 README 同步已按维护者要求暂缓;当前优先维护 wiki,不将源码文档同步作为其他工作的前置步骤。
- 原仓库来源的固定版本与工作区差异见 sources.md;不能把基线链接当成未提交内容已经合并的证据。
- 正式知识写给人和 AI 共同阅读;本文件只放工作规则,不另存一份服务事实。
- 以中文维护正文、commit、PR;配置键、命令和上游专有名称保留原文。
- 区分设计、配置、部署记录与现场验证。没有访问现场,不得写“运行正常”。
- 查询服务或项目状态前先问维护者:哪些工作正在动态进行、由哪个 ticket 跟踪、哪些现状尚未记录。已有明确授权的范围无需重复询问;不能从一个项目扩大到其他项目或现场查询。
- 维护者指定 ticket 为依据时,先读正文和讨论,区分已完成阶段与开放的后续范围。issue open 不等于尚未部署,README 与 ticket 不同也不能立即认定为运行异常。
- Samba AD、OCI、Proxmox 已获维护者明确指定为 IaC 优先:以 Ansible/Terraform 代码为配置依据,README 为解释。此范围内读取仓库配置无需再次询问;现场查询仍按授权范围处理,不能把代码声明当作部署验收。
- 修改前读取对应源码 README/runbook;需要现场核实时先取得维护者对范围的确认。发现差异先记录来源,不能自行把计划升级为事实。
- 新增服务同时补用途、入口、登录方式、第一次使用示例、依赖和故障入口。
- 改变行为、入口、依赖、状态或恢复方法时,在同一任务更新对应文档与服务索引。
@@ -16,4 +19,5 @@
- 每项当前事实注明来源;last_verified 只在完成所述现场验证后更新,不随文字编辑刷新。
- 凭据只记录取得方式和受管位置,不复制实际密码、token、私钥、state 或含敏感值的输出。
- 不复制 apps/tailscale/helm.sh 的内容。迁移旧文档前先审查敏感内容,不能整库直接发布。
- 提交前运行 `python3 scripts/check_docs.py`;修改检查器时运行 `python3 -m unittest discover -s tests -v`。依赖与本地环境见 CONTRIBUTING.md。
- 遵守 CONTRIBUTING.md;不把临时检查日志和个人 agent memory 当成正式文档。
+56
View File
@@ -7,6 +7,9 @@
2026-09-16 维护者指定 SPIFFE/SPIRE 基本以 homelab-infra #34 的记录为依据;
本轮仅查该 ticket 及其直接引用的 runbook,没有查询现场。其他项目仍需先询问。
2026-09-16 维护者指定 Samba AD、OCI、Proxmox 优先 IaC、以代码为准。
可直接核对其仓库中的配置与任务,README 与代码不一致时优先解释代码;此授权不等于现场变更或验收。
稳定设计与使用方法放知识库,动态进度链接到 ticket。知识库只保留注明查阅日期的阶段摘要,
不复制维护第二份实时任务列表。issue open 可能表示后续阶段未完成,不能据此推断基础服务未部署。
@@ -49,3 +52,56 @@ accepted 不代表部署完成,implemented 必须附实现和验收依据。
使用普通 Markdown 链接、相对附件路径和文字说明;关键事实直接写入正文。
可选 Obsidian 编辑,个人布局、缓存、插件和同步配置不提交。对外分享前检查敏感内容。
提交前检查相对链接、服务目录覆盖,以及新增内容是否混淆计划和运行事实。
## 一次服务变更应更新哪里
| 变化 | 必须查看的文档 |
|---|---|
| 使用入口、认证、权限、客户端参数 | 对应 `services/` 页面;入口变化同时更新服务总览 |
| 新增或退役组件 | 服务页、`services/index.md`;任务入口变化再改 `guides/task-index.md` |
| 跨服务设计或边界 | `architecture/constraints.md` 及受影响指南 |
| 只有开发进度变化 | 原项目 ticket;wiki 仅在阶段摘要需要变化时更新并注明日期 |
| 取得新的验证结果 | 服务页说明日期与验证范围,据实更新 `last_verified` |
| 工作区来源已合并 | 核对实际内容后更新 `sources.md` 的固定链接及差异标记 |
先修改最接近事实的页面,再同步导航,避免把同一套操作复制到多份文档。
无需每次修改都更新首页、所有服务页或整个来源索引。
原仓库 README 同步按维护者要求暂缓,不阻塞 wiki 的维护。
按维护者于 2026-09-25 的约定,纯文档变更检查通过后直接提交并推送 main,不另开 PR。
含代码、配置或检查器行为变更时仍使用 PR;PR 使用
[.gitea/PULL_REQUEST_TEMPLATE.md](.gitea/PULL_REQUEST_TEMPLATE.md),简述问题、最终变化、依据与验证。
直接提交仍遵循相同的检查与证据规则,不跳过检查或覆盖 main 上的其他更新。
## 本地与 CI 检查
需要 Python 3.10 或更新版本;首次在 wiki 根目录准备环境:
```bash
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-docs.txt
.venv/bin/python -m unittest discover -s tests -v
.venv/bin/python scripts/check_docs.py
git diff --check
```
依赖版本固定在 [requirements-docs.txt](requirements-docs.txt)。安装依赖需要网络,检查器本身离线运行。
Gitea 工作流 [.gitea/workflows/docs.yml](.gitea/workflows/docs.yml) 在 main push、PR 和手动触发时运行,
使用 `[self-hosted, pod]` 的 Python 虚拟环境;无需业务秘密或集群权限。
不设置 job `container`:此次 Pod runner 日志确认没有 Docker socket,额外启动 job 容器会在检查前失败。
CI 获取 checkout action 和依赖仍需要对应网络可用。
检查范围:
- Markdown 的相对文件链接、图片、引用式链接及本地标题锚点;不探测远端 URL。
- frontmatter 的类型、重复键、状态枚举、日期与 `live-verified` 必须有验证日期的约束。
- `services/` 下的服务页必须有完整状态字段,并由服务总览链接;总览及外部消费者范围页除外。
- 已有 frontmatter 的其他页面校验 title 和审阅日期;`templates/` 允许日期占位为 null。
标题锚点按常见 Gitea/GitHub 规则处理中文、字母、数字、连字符和重复标题。
需要特殊字符锚点时可声明 HTML `id`,不要依赖 Obsidian 插件或非标准 heading 属性。
代码块和行内代码里的路径是示例或说明,不当链接执行或检查;源码路径的存在性由 `sources.md` 的明确核对维护。
检查错误带文件与行号,但不打印原始 frontmatter 内容。
检查器不证明命令正确、外链可达、事实最新或服务健康,也不自动获取凭据或执行文档中的示例。
+15 -16
View File
@@ -4,20 +4,17 @@
## 从这里开始
- [服务总览](services/index.md):有什么、有什么用、在哪里、状态依据是什么。
- [SPIFFE/SPIRE](services/spire.md):按 #34 整理的阶段状态、使用与 runbook 入口。
- [PostgreSQL Tenant Operator](services/postgresql-tenant-operator.md):计划在共享 PostgreSQL 上提供的 DBaaS 中间层。
- [Gitea Dynamic Runner](services/gitea-dynamic-runner.md):原 microVM runner,现支持 Pod/VM 两种一次性执行环境。
- [NATS](services/nats.md):已部署的集群共享消息服务,目前仅 Dynamic Runner 消费。
- [旧 VictoriaMetrics 栈](services/victoriametrics-legacy.md):运行栈已停用,历史数据卷保留。
- [LAN DNS](services/lan-dns.md):Blocky 主 DNS、路由器上游与备用、Samba AD 域 DNS 的现状。
- [Authelia](services/authelia.md):active 的唯一主 OIDC broker 与登录入口。
- [待核实与文档缺口](verification.md):互相矛盾的记录、缺少使用说明的服务、下一步核实方法。
- [架构约束](architecture/constraints.md):修改环境前必须遵守的设计及原始依据。
- [workload-sts 设计历史](architecture/workload-sts-history.md):已归档的早期身份方案及 SPIRE 替代决策。
- [文档维护规则](CONTRIBUTING.md):人和 AI 如何共同维护知识。
- [服务文档模板](templates/service.md):新服务必须同时提供使用说明。
- [AI 工作入口](AGENTS.md):新上下文按任务查找资料。
- [按任务查找文档](guides/task-index.md):接入服务、写 CI、查日志、取秘密或接续 AI 任务。
- [服务总览](services/index.md):组件、用途、入口和状态依据。
- [发布新服务](guides/publish-service.md):LAN DNS、证书、HTTPRoute、认证与 GitOps。
- [架构约束](architecture/constraints.md):修改环境前必须遵守的设计。
- [来源追溯](sources.md):固定源码版本,以及与工作区的差异。
- [文档维护规则](CONTRIBUTING.md)、[服务模板](templates/service.md)、[AI 工作入口](AGENTS.md):如何共同维护知识。
- [首轮状态对齐记录](verification.md):已完成的澄清与历史处置。
- [文档完善清单](documentation-backlog.md):已补指南与暂缓事项。
设计历史与范围外项目见[workload-sts](architecture/workload-sts-history.md)、
[旧监控栈](services/victoriametrics-legacy.md)及[外部消费者](services/external-consumers.md)。
## 当前证据边界
@@ -25,11 +22,13 @@
`ebe0ec154dab557598075b5cf6d3629c3c23fe2a`。该工作区包含未提交修改和未跟踪文件。
后续按维护者提供的线索补读了 SPIFFE/SPIRE #34 与 runbook、workload-sts 归档决策、
PostgreSQL Tenant Operator 的 README 与架构文档,以及 Gitea Dynamic Runner README。
具体来源和查阅范围见各页;其余条目仍以初轮工作区证据为限。
具体来源和查阅范围见各页;后续使用指南已按对应源码和上游接口文档逐项补充。
未补充的状态仍以初轮证据为限;来源文件与已提交版本的比较见[来源追溯](sources.md)。
LAN DNS 已按维护者于 2026-09-16 提供的现状更新,未查询现场。
Authelia 同日由维护者明确为 active、唯一的主 OIDC broker,已同步到服务总览。
后续状态查询先向维护者确认动态工作与资料来源,授权范围内不重复询问。
初轮没有查询运行环境;后续仅对旧 VictoriaMetrics 栈做了维护者明确授权的有限只读检查,
初轮没有查询运行环境;后续对旧 VictoriaMetrics 栈做了维护者明确授权的有限只读检查,
随后按明确要求删除旧配置和数据卷,
检查范围和结果见对应页面。“文档记录已部署”不等于今天已验证健康。
本库中的入口地址来自原有记录,也尚未逐一验证可达性。
+64
View File
@@ -0,0 +1,64 @@
---
title: Ayatori 控制面边界
last_reviewed: 2026-09-24
---
# Ayatori 控制面边界
Ayatori 是规划和早期实现中的 homelab 基础设施控制平面。它使用 kube-apiserver、etcd、CRD
和 Kubernetes API machinery 作为版本化 API 与状态协调平面,主要复用对象并发控制、
list/watch、informer、RBAC、admission、审计和 API 版本机制,而不是复用 Kubernetes 的容器
编排产品边界。
Ayatori controller-manager 负责领域资源的调度、生命周期、故障恢复、垃圾回收和后端收敛。
这部分职责近似 Kubernetes 的 controller-manager,但面向 VM、LB、数据库、对象存储、任务、
托管 Kubernetes 和人工操作等 Ayatori 领域。
Kubernetes workload 集群只是与 OpenSandbox、Proxmox 等并列的 backend/executor,可能位于
远端,也可能在某个部署 profile 中不存在。除 Flux、Ayatori controllers 等管理组件的部署外,
领域 API 不得默认依赖同集群 Pod、Job、Service、NetworkPolicy、namespace 共置或 owner
reference;跨后端能力必须由领域 API 和 adapter 契约明确表达。
Kubernetes 内置资源也只是可选择复用的 API contract,不绑定其传统实现组件。例如 Ayatori
可以让 Compute Agent 更新 `core/v1 Node` 和 Lease,并由自有 controller 调度 VM,而不部署
kubelet、Pod、CRI 或 kube-scheduler。每个复用资源都必须单独明确 producer、consumer、
ownership、采用字段和有意舍弃的上游语义。
当前选择继续使用 kube-apiserver + CRD。generic-apiserver 或聚合 API Server 不会替代领域
controller,只会让项目额外接管资源服务端、watch、RBAC、API 兼容和存储迁移责任。只有 CRD
或 kube-apiserver 的限制形成经过验证的阻碍时,才重新评估自建 API Server。
Ayatori 不按传统私有云产品目录建设。当前已确认的首要管理缺口是 Database、LoadBalancer 与
Bucket/Object Storage;VirtualMachine 同样具有明确价值,但需要组合 Proxmox API、节点受限
Agent/CLI 和人工任务。当前 Job controller 是控制循环与 adapter 的验证切片,长期只可能收敛为
内部 Run 能力,不构成 FaaS、Cloud Run 或应用托管承诺。KaaS 只有出现实际需求时才评估,不是
产品路线的必达终点。
Compute 方向已被记录但延后实施:选择性复用 `core/v1 Node` 与 Lease,由 Ayatori Compute Agent
实现节点状态并由自有 controller 调度,不引入 kubelet、Pod 或 kube-scheduler。长期 VM 主路径
可以是普通 Linux 节点上的 libvirt/QEMU;Proxmox 用于 brownfield adopt 和过渡。OpenSandbox/Kata
microVM 属于 Run/Sandbox 的隔离实现,不因此成为 VirtualMachine 资源。
Database 资源模型于 2026-09-24 明确采用官方 PV/PVC 的资源/申请分离模式:Instance 提供
管理入口,独立 Database 表示实际资源,Tenant 表示用户申请。Retain 保留资源对象,支持
人工导入和明确授权后的重新绑定;不维护 PostgreSQL ownership registry,不为创建结果不确定
提供自动认领保证。详见 [DBaaS 设计](../services/postgresql-tenant-operator.md#当前资源模型2026-09-24-已确认)。
新增 Kubernetes 资源生命周期前须核对官方设计方式,记录采用与偏离的语义;参考模式不意味着
部署对应上游组件,也不意味着复制全部字段与抽象。
详细设计以 Ayatori 仓库的
[ADR-0001](https://git.ddupan.top/panxiao81/ayatori/src/branch/main/docs/decisions/0001-kubernetes-api-machinery.md)
、[ADR-0006](https://git.ddupan.top/panxiao81/ayatori/src/branch/main/docs/decisions/0006-demand-driven-resource-scope.md)
和[总体架构](https://git.ddupan.top/panxiao81/ayatori/src/branch/main/docs/architecture/overview.md)为准。
本页记录跨 homelab 的稳定边界,不表示 Ayatori 已部署或达到生产可用状态。
## CI 验证约定
2026-09-24 维护者决定:全量验证自动在 PR 执行,main push 不再重复运行;保留手动入口。
直接推送 main 不会自动验证,常规变更仍应经 PR;基线有实质变化时需更新分支并重验,
不能把分支 head 的成功当成任何合并结果的成功。测试项目未减少,不修改分支保护设置。
配置与边界见 Ayatori
[f347ee5 的环境文档](https://git.ddupan.top/panxiao81/ayatori/src/commit/f347ee5292ecf39ac0ecbb21e162ee406d8ce382/docs/concepts/environments.md),
已随 [PR #9](https://git.ddupan.top/panxiao81/ayatori/pulls/9) 合并 main;合并后未触发重复全量验证。
这不是整个 homelab 的统一 CI 策略。
+18 -3
View File
@@ -1,15 +1,23 @@
# 架构约束索引
审阅日期:2026-09-16。以下是现有仓库明确记录的约束摘要,不是本轮新增的架构决策。
来源路径相对于 homelab-infra;修改时必须读原文和对应代码,冲突进入[核实清单](../verification.md)。
审阅日期:2026-09-25。以下是现有仓库明确记录的约束摘要;Ayatori 条目来自其独立项目的
已接受设计,其余来源路径相对于 homelab-infra。修改时必须读原文和对应代码,新出现的差异
先向维护者确认;[首轮状态对齐](../verification.md)已完成。
| 约束 | 原因与边界 | 来源 |
|---|---|---|
| 新增监控配置优先使用 ServiceMonitor、PodMonitor、PrometheusRule | VictoriaMetrics Operator 负责转换,避免同一目标/规则维护两套声明;历史 VM 配置按需另行迁移 | 维护者 2026-09-25 明确要求;[基础监控运维](../guides/monitoring-foundation.md) |
| Ayatori 复用 Kubernetes API machinery,不复用其容器编排产品边界 | kube-apiserver/etcd 提供 API、watch、RBAC 与状态协调;领域调度、生命周期、恢复和 GC 属于 Ayatori controllers;Kubernetes workload 只是可替换 backend | [Ayatori 控制面边界](ayatori-control-plane.md) |
| Kubernetes 内置资源不绑定上游实现组件 | 可由 Ayatori Agent/controller 实现和消费 Node、Lease 等 API;使用 Node 不推导必须部署 kubelet、Pod 或 kube-scheduler | [Ayatori 控制面边界](ayatori-control-plane.md) |
| Ayatori 只为已验证的管理缺口新增北向资源 | 当前优先 Database、LoadBalancer、Bucket/Object Storage;VM 价值已确认但南向较重;Run 是内部切片,KaaS 按需,FaaS/PaaS 默认不做 | [Ayatori 控制面边界](ayatori-control-plane.md) |
| Ayatori Compute 复用 Node/Lease API,但不引入 Kubernetes workload plane | Compute Agent 实现 Node 状态;libvirt 是长期候选主路径,PVE 是 brownfield 过渡;Kata microVM 属于 Sandbox backend | [Ayatori 控制面边界](ayatori-control-plane.md) |
| Database 采用独立资源与用户申请分离 | Instance → Database → Tenant;Retain 保留资源并人工回收,显式导入,不维护 PG registry;替代旧所有权持久化合同 | [DBaaS 设计修订](../services/postgresql-tenant-operator.md#当前资源模型2026-09-24-已确认) |
| Samba AD、OCI、Proxmox 优先 IaC,以代码为准 | Ansible/Terraform 声明及任务优先于旧 README;声明不等于已验证部署 | 维护者于 2026-09-16 明确、各服务使用指南 |
| 服务独立部署,Terraform root/state 按服务隔离 | 避免认证和变更影响范围绑在一起 | `AGENTS.md`、`CLAUDE.md` |
| OpenBao 恢复不能依赖 k3s 或读取自己内部的恢复凭据 | 先恢复信任根,再恢复消费者 | `infrastructure/openbao/README.md`、`CLAUDE.md` |
| Terraform 管 API 配置,Ansible 管主机及不能安全纳管的密钥材料 | 不可读回秘密和根密钥不能靠反复重建实现收敛 | `infrastructure/openbao/README.md` |
| LAN HTTP 入口为 Envoy Gateway;新增服务核对 parentRefs、DNS 和认证 | 不直接套用 archive 中的 Gateway 示例 | `platform/envoy-gateway/README.md`、`AGENTS.md` |
| 人类身份由 Samba AD / Authelia 提供,Authelia 是 active 的唯一主 OIDC broker;workload 身份由 SPIRE 提供 | 身份签发不等于资源授权;SPIRE 基础设施与最小 PoC 已完成,后续集成以 #34 为准 | [Authelia](../services/authelia.md)、[SPIRE 状态与依据](../services/spire.md) |
| 人类认证仍由 Samba AD / Authelia 提供;Hydra 作为 Gitea 的实验性签发入口,通过 OIDC 复用 Authelia;workload 身份由 SPIRE 提供 | 2026-09-25 第一轮人类 PoC 扩展了原单 broker 接入边界,未迁移主入口、机器身份或应用权限 | [Authelia](../services/authelia.md)、[Hydra PoC](../services/hydra.md)、[SPIRE](../services/spire.md) |
| SPIFFE 提供跨基础设施的统一机器身份入口,替代 workload-sts 统一 IAM 平台方案 | 服务信任 SPIFFE 身份、签发自己的 token 并维护自身权限;非 Kubernetes 身份不依赖 Kubernetes ServiceAccount,优先复用服务现有接入机制 | [核心设计与取舍](../services/spire.md#核心设计与取舍),维护者于 2026-09-16 补充 |
| 已由 Flux 接管的资源通过 Git 修改;brownfield 不全局开启 prune | 防止漂移回滚与误删;未接管资源不能假定受 Flux 管理 | `clusters/homelab/README.md` |
| DNS 各视图保留权威边界;只管理明确声明的 RRset | 不清理 Samba 自动维护的域记录;LAN 现状按维护者说明对齐,旧源码文档待同步 | `infrastructure/dns/README.md`、[LAN DNS](../services/lan-dns.md) |
@@ -23,3 +31,10 @@
通用变更约束:先做适用的 plan/check/diff,再操作现场;不将凭据和 Terraform state
写入知识库;不更新 homelab-infra 的冻结 `CHANGELOG.md`。
## 待评估草案
[独立 IAM 与 agent 身份草案](independent-iam-draft.md)(2026-09-25,draft)提出以 Hydra
解耦认证与签发,通过 OIDC 接入人类、machine 和 agent,并作为 Ayatori 的独立外部依赖。
完整方案仍为草案。2026-09-25 已按维护者要求先实施人类登录 PoC,上表显式记录其有限
变更;SPIFFE、agent 动态授权、组模型及 DNS 迁移未随之实施。
+249
View File
@@ -0,0 +1,249 @@
---
title: 独立 IAM 草案:人类、机器与 AI Agent 的统一应用接入
status: draft
last_reviewed: 2026-09-25
last_verified: null
sources:
- https://git.ddupan.top/panxiao81/iam-login/pulls/3
- https://git.ddupan.top/panxiao81/iam-login/commit/9cf2d235dff0cd33f98012b0a114f14a8f9bfcda
- 维护者于 2026-09-25 的架构讨论与草案记录要求
---
# 独立 IAM 草案:人类、机器与 AI Agent 的统一应用接入
本页记录完整 IAM 的设计意图,状态仍为 **draft**。2026-09-25 维护者随后选择先实施
[Hydra 人类登录 PoC](../services/hydra.md):通用 OIDC 上游适配器暂用 Authelia,Gitea
新增 Hydra 登录源;维护者已确认成功返回原账号且仓库权限正常,第一轮人类 PoC
验收通过。这不表示完整方案已采纳或开始全面迁移。
长期名称、资源模型及 agent 接口尚未确定。
## 动机与首要目标
首要目标是降低下游应用集成成本。原生接入 SPIFFE 的应用覆盖有限,OIDC/OAuth 则已有
广泛的应用与 CLI 生态。通过独立 IAM 集中处理身份验证,让应用沿用标准登录和授权流程,
即可接入人类、传统机器账户和 AI agent,无需每个应用自行验证 SVID 或集成 SPIRE。
维护者认为,现有方案缺少好用的、真正区分 AI agent 与传统 service account 的身份及
授权模型,这是考虑自行建设的主要原因。拟自建的是主体语义、认证编排与授权能力,
OAuth2/OIDC 协议和 token 签发优先交给 Hydra。
Hydra 的核心价值是把“如何验证身份”与“如何完成标准授权流程并签发 token”解耦。
统一 token 格式不是主要目标,也不要求所有应用 API 直接接受 Hydra token。
## 独立服务边界
IAM 应当能够独立部署、运行和恢复,不依赖 Ayatori 的 API、CRD、controller 或领域资源。
Ayatori 是其消费者,依赖关系类似 OpenStack 其他服务对 Keystone 的依赖;这一类比
不意味着复刻 Keystone 的全部 API 或功能。即使未来命名为 Ayatori IAM,也不改变边界。
| 部分 | 拟承担的职责 |
|---|---|
| 人类认证后端 | 人类登录与 MFA;已选择 Spring Native 方向,首轮 AD 仍为用户与组权威 |
| SPIRE | workload 身份证明与 SVID 签发,可辅助 machine 或 agent 认证 |
| Login / Consent 与身份授权服务 | 验证不同主体的证明,映射稳定身份,处理登录、授权、组和必要的动态审批 |
| Hydra | OAuth2/OIDC 流程、client 与 token 签发 |
| 下游应用 | 关联本地账号,执行应用自身权限,按原有机制签发或使用应用凭据 |
```text
人类:交互登录 / 上游 IdP ──────┐
机器:SPIFFE 等预配置身份 ─────┼→ 独立身份验证与授权 → Hydra → OIDC/OAuth 消费者
Agent:人类授权 / SPIFFE / │ ├→ Gitea 等应用
后续专门认证方式 ──────┘ └→ Ayatori API server
```
Ayatori 使用裁剪的 kube-apiserver,目标是让它信任 Hydra 签发的 token 来验证身份,
再由自身 RBAC 执行资源授权。具体 token 类型、claims、audience 与 JWT authenticator
兼容性需要验证;不能预先把任意 Hydra access token 都视为 API server 可用凭据。
## 主体类型与认证方式分离
人类、machine、agent 是不同的主体类型,不能按所用认证协议决定分类。
Agent 可以使用 SPIFFE 辅助证明执行环境,而仍然是 agent 主体,不必冒充传统机器账户。
Agent 的负责人、委托人及当前执行实例也不应与 agent 自身身份混为一谈。
| 维度 | 传统机器账户 / CI | AI agent |
|---|---|---|
| 任务特征 | 预定义流程与资源范围 | 能理解任务、作出决策,可能跨应用并在执行中改变操作路径 |
| 权限需求 | 通常可以预先配置 | 潜在范围更广,可能执行中动态申请 |
| 授权方式 | 审核配置后按固定规则授予 | 基础权限与任务、会话或限时授权组合,由策略或人类批准 |
| 交互能力 | 固定程序处理约定流程 | 可使用 CLI、MCP 和 skills,自主组织请求并在需要时请求批准 |
| 审计语义 | 哪个 workload 执行了操作 | 哪个 agent、哪次执行、代表谁、依据哪次授权执行 |
更广的潜在权限不等于常驻全权。动态批准应转化为服务端认可的授权和适当凭据,
不能由 agent 自报身份或声明 scope 就自动生效。申请、批准、期限、撤销以及下游已有
会话和 token 的失效语义需要明确设计,不能假设 Hydra 自动提供完整实现。
认证入口保持可扩展:
- Remote MCP 的 OAuth 可提供人类参与的授权入口。设计上允许人类在流程中确认或选择
agent 身份、委托关系与权限,再由服务端绑定凭据。普通 MCP OAuth 并不自动定义
agent 主体语义;具体绑定属于本方案要实现的能力。
- SPIFFE 路径以经人类审核的 workload/身份绑定规则为信任来源,运行时验证证明是否
满足规则。交互批准和预配置批准都是可用的信任建立方式。
- MCP 和 skills 是 agent 参与流程的工具及操作约定,本身不替代可验证凭据。
后续可以增加专门的 agent 认证方式,不必现在锁定一个唯一协议。
Agent 可以独立使用自身权限,也可以接受人类委托。人类授权 agent 不等于 agent
变成人类账号;需要时保留“agent A,经用户 B 授权”的关系与审计信息。
## 无浏览器的标准登录与 Gitea 示例
Authorization code flow 不要求必须使用图形浏览器。对于可通过 HTTP 完成的流程,
agent 可以用 curl/CLI 保存 cookies、跟随重定向、提交表单和身份证明,并到达 callback。
必须保留 state、nonce、PKCE 等协议绑定;以 HTTP 客户端执行不意味着跳过这些校验。
专用登录 helper 可以作为便利工具,但不是架构前提。
关键是 Login 服务支持 machine/agent 的身份证明,而不强迫它们完成人类密码、
交互 MFA 等认证。Consent 按已有授权策略处理,必要时请求人类批准。
Gitea 的目标路径包含内外两层授权:
```text
官方 tea CLI 发起 Gitea OAuth 授权
→ Gitea 经 OIDC 请求 Hydra 登录
→ Login 服务验证 agent 或 machine 的身份
→ 接受 login challenge,按策略完成 Hydra consent
→ Hydra 回调 Gitea,Gitea 关联对应 bot 账号
→ 完成 Gitea 自身对 tea 的授权确认
→ Gitea 回调 tea,由 tea 完成 code 交换并取得 Gitea token
→ tea 按 bot 的 Gitea 权限调用 API
```
这里 Hydra token 用于 Gitea 的身份登录,Gitea token 用于 CLI 调用应用 API。
因此不要求 Gitea API 直接接受 Hydra bearer token,也不以自建 PAT 分发 broker 为前提。
Bot 是下游账号映射,不代表所有 agent 共享一个万能 bot。
该路径尚未端到端验证。需要验证官方 CLI 的授权 URL/callback 交接、Gitea 本地会话与
首次授权确认、账号关联和 scope,以及刷新与重新登录。其他应用可复用相同思路,
但支持 OIDC 不等于所有应用的无交互授权路径均已兼容,须按具体流程验收。
## 统一组与下游授权
集中维护较统一的粗粒度用户组,避免每个应用都独立维护一套 admins 成员关系。
应用仍保留自身角色、team 和资源权限,由明确映射决定中央组在应用内的权限。
统一组不等于一个全局 admins 自动拥有所有服务的管理权。
Agent 的动态授权需要落到应用可识别的 scope、角色、账号权限或其他已有授权机制上。
仅在 Hydra token 中增加一个 claim,不意味着下游会自动执行或撤销相应权限。
具体组名、角色模型及同步方式尚未确定。
## 人类后端、Samba AD 与 DNS 演进
### 人类认证后端的接口边界
2026-09-25 维护者明确:考虑 ZITADEL 是为了复用认证会话与登录状态机,而不是把它作为
另一个 OIDC 上游。下一阶段目标是由人类认证后端处理认证因素与会话,适配层验证结果、
映射稳定主体并接受 Hydra login challenge;面向下游的 OAuth2/OIDC 仍由 Hydra 提供。
第一轮通过 Authelia OIDC 的 PoC 保留为已验收基线,尚未部署此替代路径。
早期上游接口与源码评估曾形成以下两个候选;后续决定见下方“已确定的实现方向”:
| 候选 | 可复用能力 | 尚需承担的接入工作 |
|---|---|---|
| ZITADEL Session API + Login V2 | 逐步验证认证因素、会话、账号管理;Login V2 有登录编排与 UI | 将登录事务绑定到 Hydra challenge,服务端验证认证结果并接回 Hydra;按选定版本验证 LDAP、MFA 与完整恢复流程 |
| Ory Kratos + self-service UI | 登录、MFA、恢复与会话流程;上游已有 Hydra login challenge 集成 | 部署和维护独立 UI,保留主体映射与 consent;Samba AD 不能假设存在开箱即用的 LDAP 认证接入 |
早期评估认为 Kratos 在认证与签发的职责分离上更直接;但若必须继续使用
Samba AD 密码登录,LDAP 过渡成本可能使 ZITADEL 更合适。Kratos 本身是 headless 服务,
现成参考 UI 不等于无需维护的内置管理门户,亦不能把 Ory Network 的功能直接视为自托管
开源版能力。此判断是方案评估,不是新的部署决定。
ZITADEL Session API 返回会话不等于已完成全部认证;需要确认已验证因素、有效期、用户
状态和所需 MFA。官方 Login V2 的流程编排包含这些判断。无 OIDC 上下文登录及默认完成
跳转可用,但普通跳转不是传给 Hydra 的认证证明,也不自动绑定原始 login challenge。
查阅时上游文档与开发分支存在差异:Hosted Login 文档仍列出 LDAP 限制,而
[Login V2 固定源码](https://github.com/zitadel/zitadel/blob/5ca0b54ca311c4be535589e7c375f9bea50e3ec2/apps/login/src/lib/server/idp.ts)
已有 LDAP 认证实现;不能据此宣称某个发布版本已经验收。部署前需锁定发行版本再验证。
参考:[ZITADEL Session API](https://zitadel.com/docs/reference/api/session/zitadel.session.v2.SessionService.CreateSession)、
[Login App](https://zitadel.com/docs/guides/integrate/login-ui/login-app)、
[Hosted Login 限制](https://zitadel.com/docs/guides/integrate/login/hosted-login)、
[Kratos Hydra 集成源码](https://github.com/ory/kratos/blob/master/selfservice/flow/login/handler.go)、
[Kratos self-service UI](https://github.com/ory/kratos-selfservice-ui-node)、
[LDAP 功能请求](https://github.com/ory/kratos/issues/274)。
### 已确定的实现方向
维护者已选择 Java、Spring Security 与 GraalVM Native。阻碍 Java 的是 JVM 部署和运行
开销;能够通过 Native 功能与资源验收时,Java 仍是优先选择,不引入 Kotlin。
Quarkus、Micronaut 也有相应生态支持;最终选择 Spring 同时考虑了维护者的熟悉程度。
Keycloak 可参考认证实现,但其服务端模型与 SPI 不直接复用,采用 Quarkus 也不证明
Keycloak 有 Native 发行或完整原生兼容性。
原先薄 OIDC 适配器在 homelab-infra 内维护;现在直接承担 AD、MFA、认证状态与 Native
构建测试,因此按维护者决定拆为独立 [iam-login](https://git.ddupan.top/panxiao81/iam-login)
仓库,独立于 Ayatori。环境部署仍归 homelab-infra。
已按维护者提供的 start.spring.io 配置生成 Java 25、Spring Boot 4.1.1、Gradle 与 YAML
项目骨架,包含 LDAP、WebAuthn、校验、Actuator/Prometheus、OpenTelemetry/追踪、
Testcontainers、UnboundID、Lombok、配置处理器、DevTools 与 Native 插件。依赖存在不表示认证流程已实现;首次实现及 Native
验证由 [issue #1](https://git.ddupan.top/panxiao81/iam-login/issues/1) 跟踪。需在原生二进制上
验证 AD、MFA、Hydra、持久化及监控,实测资源成本;不能把编译成功等同完整验收。
首轮保持 AD 用户与组权威并直接映射组名。LDAP 与 MFA 绑定同一稳定主体;切换前需要
明确现役 issuer/sub 哈希主体到新主体的连续性映射。MFA 首先验证官方 WebAuthn 集成,
恢复与已有凭据迁移方式仍待实现。维护者接受必要时并存多个登录前端。
现役 Go/Authelia PoC 保留为已验收基线,尚未切换生产认证路径。
### 人类浏览器登录界面
已确定先借鉴 Keycloakify 的交互方式:React + Vite 开发界面,Spring 在首个 HTML 响应中
带齐当前步骤和必要上下文,浏览器渲染组件,默认用原生表单 POST,由服务端认证流程
决定下一步页面或重定向。局部交互按需使用 JavaScript;后续根据实际体验决定哪些步骤
使用 fetch,避免将整个认证流程都搬到客户端路由和状态机。
页面与 Spring 后端同仓库维护,前端资源构建后随 Native 应用交付。生产不增加 Node/BFF、
嵌入式 JavaScript 运行时或 FreeMarker;首轮接受客户端首屏渲染,不实现 React SSR/RSC。
当前仅验证浏览器交互原型,不表示 AD、MFA 或 Hydra 登录链路已完成,也不替换现役入口。
原型启动、实现与验证见 [iam-login PR #3](https://git.ddupan.top/panxiao81/iam-login/pulls/3)
及其浏览器流程文档;后续机器 API 独立设计。
### 目录与 DNS 迁移
人类同样使用这套独立 IAM。首轮由 iam-login 直接连接 Samba AD 验证密码、查询用户与组,
按原组名直接映射;之后再推进统一粗粒度组模型与目录迁移,不要求同一步替换目录。
更换认证后端时应保持稳定主体与下游账号关联,避免按可变邮箱或用户名重新识别账号。
维护者认为 Samba AD 使用率较低,长期希望完全删除它。退役需处理 LDAP、Kerberos、
SMB 域身份、域成员和域 DNS 等实际依赖,不能用网页登录迁移成功代替全部退出条件。
DNS 可独立评估迁往 PowerDNS Authoritative,主要考虑其 API 与资源成本。可从简单后端
开始评估,不预先要求完整 Recursor/UI/数据库集群。实际资源占用尚未测量。
AD 存续期间保留其域记录权威与动态更新边界;普通记录的迁移、Blocky/路由器解析链和
最终域退役应分别设计。PowerDNS 不是 IAM 的必需组件。
## 与现役约束的关系
现役记录仍以 [架构约束](constraints.md)、[Authelia](../services/authelia.md) 和
[SPIFFE/SPIRE](../services/spire.md) 为准。当前文档中的 Authelia 主 OIDC 入口、
服务直接验证 SPIFFE 后签发自身 token 的规则,仍是现役基础。第一轮人类 PoC 对
Gitea 增加实验性 Hydra 签发入口的有限变更已在约束索引中单独记录。
本草案提出的变化是:增加独立的多主体 IAM,通过 Hydra 解耦认证与签发,让尚不支持
SPIFFE 的下游复用 OIDC;并为 agent 增加区别于传统 service account 的身份授权语义。
若采纳,应显式更新现役约束和相关服务文档。已能直接使用 SPIFFE 的服务无需强制改道。
这也不构成恢复已归档 [workload-sts](workload-sts-history.md) 项目的决定。
## 后续验证问题
以下是草案的验证范围,不是已启动的实施任务或第二份动态进度表:
1. 一个 SPIFFE 主体,通过官方 tea 的 OAuth 入口,用 CLI/HTTP 完成无浏览器登录,
以指定 bot 成功调用 Gitea API,同时验证错误身份不能取得该账号。
2. 人类和 agent 使用不同认证方式后,下游仍能通过同一 OIDC 接口识别正确身份与组。
3. Ayatori 的 kube-apiserver 验证 Hydra token,并正确映射主体、组与 RBAC。
4. Agent 动态申请权限,经过策略或人类批准后生效;到期与撤销行为覆盖下游凭据。
5. 明确稳定 agent、执行实例、委托者的绑定方式,以及可供 agent 使用的 MCP/CLI 接口。
6. 独立评估 Samba 退出条件、PowerDNS 资源成本与 DNS 迁移边界。
## 上游依据
以下文档用于说明协议与产品能力,不代表本方案已验证或已选定具体版本:
- [Hydra Login / Consent 流程](https://www.ory.com/docs/oauth2-oidc/custom-login-consent/flow)
- [Gitea OAuth2 provider 与 tea 内置客户端](https://docs.gitea.com/development/oauth2-provider/)
- [tea 登录命令定义](https://pkg.go.dev/code.gitea.io/tea/cmd/login)
- [Kubernetes 身份验证](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
- [ZITADEL LDAP 上游](https://zitadel.com/docs/guides/integrate/identity-providers/ldap)
- [PowerDNS Authoritative HTTP API](https://doc.powerdns.com/authoritative/http-api/index.html)
+52
View File
@@ -0,0 +1,52 @@
# 文档完善清单
本轮待核实事项已于 2026-09-16 收尾。以下是后续写作工作,不是未解决的状态核实任务,
也不代表所有相关项目都已部署或经过现场验收。需要补充事实时仍先向维护者对齐范围。
## 已补充使用指南
- [Gitea / Actions](services/gitea.md):登录、建仓库、最小 CI、runner 选择和常见问题。
- [Grafana](services/grafana.md):内存看板、指标查询、日志搜索和数据源用途。
- [zot](services/zot.md):拉取、发布授权、workflow 身份职责与后端数据恢复边界。
- [SeaweedFS](services/seaweedfs.md):S3 入口、专用凭据、列举与上传下载示例。
- [OpenBao](services/openbao.md):人的登录、按权限取密及机器身份边界。
- [NetBox](services/netbox.md):浏览设备与 IPAM,明确 Git 来源与评估用途。
- [共享 PostgreSQL](services/shared-postgresql.md):应用接入、连接检查与共享实例维护边界。
- [LiteLLM](services/litellm-gateway.md):模型请求、认证边界与独立数据库依赖。
- [Tailscale](services/tailscale.md):客户端接入、子网路由和 operator Service 的区别。
- [ps3netsrv](services/ps3netsrv.md)、[vlmcsd](services/vlmcsd.md):客户端使用与配置入口。
- [External Secrets](services/external-secrets.md)、[OpenEBS](services/openebs.md):应用秘密与 PVC 消费示例。
- [k3s DNS](services/k3s-dns.md):Pod 解析路径、配置意图与排障入口。
- [Marker](services/marker.md)、[OpenViking](services/openviking.md):转换与导入、等待、检索、读取示例。
- [SMTP relay](services/smtp-relay.md):应用配置、测试邮件与投递边界。
- [发布新服务](guides/publish-service.md):LAN DNS、证书、Envoy 路由、认证与 GitOps 的完整路径。
- [Samba AD](services/samba-ad.md)、[OCI](services/oci.md)、[Proxmox](services/proxmox.md):已有资料中的日常管理路径,动态状态未重查。
以上依据源码文档和上游说明整理,示例未在本轮执行,不作为现场验收记录。
## 后续使用说明
本轮列出的使用指南已补齐。后续以实际接入任务补充细节,不自动启动全量现场检查。
Samba AD、OCI、Proxmox 已按维护者指定采用 IaC 优先、以代码为准,并核对关键配置入口;未查询现场。
codex-proxy 已按维护者“应该是退役的”的说明移至归档范围,不再补新接入指南。
LiteLLM、Tailscale、ps3netsrv、vlmcsd 与 k3s 的 wiki 指南已补;源码目录仍缺根 README,配置入口已在各页列出。
## 来源与导航
- 已新增[按任务查找](guides/task-index.md),首页改为任务入口与服务总览。
- 已核对 62 个主要来源文件,提供[固定版本与工作区差异](sources.md)。
- 仍有差异或未收录的来源,等内容合并后再补对应版本;不自动提交原仓库工作区。
## 持续维护
- 已提供离线文档检查器、Gitea Actions 工作流与检查器测试。
- 已补 PR 模板及服务变更到文档的对应规则,见 [CONTRIBUTING](CONTRIBUTING.md)。
- Backstage 展示与 OpenViking 自动索引仍是独立后续工作,本轮未接入。
## 原仓库文档同步(按维护者要求暂缓)
- 源码仓库中 Authelia OIDC、LAN DNS、SPIRE 的旧说明后续与知识库结论同步。
- cert-manager / Envoy Gateway README 的 DNS 修改入口仍写旧变量,待同步为受管 records.yml 流程。
- Proxmox README 的早期身份方案与 runner bootstrap 描述待与当前 SPIFFE 原则对齐;Samba README 的通用示例域名/地址待清理。
上述项目仅保留记录,本轮不修改原仓库文档。
+135
View File
@@ -0,0 +1,135 @@
---
title: 监控覆盖与补齐计划
last_reviewed: 2026-09-25
---
# 监控覆盖与补齐计划
结论:监控底座和 Telegram 通知已工作,但业务服务接入与告警覆盖明显不足。
“有 exporter”“有 PodMonitor”“数据库里曾出现过指标名”都不能代替当前采集成功和有效规则。
本页用于接续覆盖建设,服务使用入口仍见 [Grafana](../services/grafana.md)。
## 第一批补齐进展
2026-09-25 已上线 kube-state-metrics,并恢复 NATS PodMonitor 转换与采集。
新增集群状态 11 条、主机/ZFS 5 条、采集与通知 5 条规则,共 21 条;正式规则总数为 68。
新增资源按维护者要求优先使用 ServiceMonitor/PodMonitor/PrometheusRule。
具体阈值、降噪边界、声明转换关系与验收方法见 [基础监控与告警运维](monitoring-foundation.md)。
下面的规模、矩阵和盲点保留初轮盘点基线,不能再当作第一批实施后的现状。
第二批数据库/OpenBao/存储/备份、外部探测和集群外心跳尚未实施。
## 证据和范围
2026-09-25 17:26–17:31 UTC,只读检查当前集群工作负载、采集 CR、vmagent 实际 targets、
vmalert 已加载规则、VictoriaMetrics 即时查询、CNPG 监控/备份声明、证书资源和本机服务清单。
同时查阅服务 wiki、源码配置和运维文档。没有读取 Secret、修改集群或部署 exporter。
共享 etcd 正由维护者调整;其瞬时采集异常不作为本轮待修故障。
没有逐台登录 PVE、OCI、域控和其他 VM,也没有验证所有应用业务接口、备份文件或恢复能力。
“未接入”指未进入这套中央 VictoriaMetrics/Alertmanager,不排除服务另有本地日志、
健康检查或独立监控;例如 LiteLLM 源码中有独立 Prometheus Compose 配置,本次未验证运行状态。
源码基线为 [homelab-infra a43b7d3](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/a43b7d3c26f9724b9d5b2ad45058f2d1632741af/platform/observability),
共享 etcd 采集/规则另以本次现场 CR 为准(来源工作区尚有未提交配置)。
审阅时主工作区落后于远端且有其他改动,不能拿本地旧 :8080 配置覆盖已合并修复。
## 初轮盘点规模(实施前)
- 69 个 Deployment/StatefulSet/DaemonSet 对象(44/13/12),不等同于服务数或全部实例数;CNPG 管理的数据库 Pod 不在此统计内。
- vmagent 有 17 个目标、15 个 job;其中 node-exporter 与 docker-hosts 重复采集同一个 :9100 地址,实际唯一 URL 为 16 个。
- 采集对象:3 VMNodeScrape、1 VMPodScrape、8 VMServiceScrape、3 VMStaticScrape。
- 有 1 个 NATS PodMonitor,但没有其转换后的 VMPodScrape 或实际 target;没有 ServiceMonitor、PrometheusRule、VMProbe。
- 5 个 VMRule,vmalert 实际加载 47 条告警:vm-health 12、vmagent 14、vmalert 8、vmsingle 7、shared-etcd 6。
- 严重性为 critical 16、warning 30、info 1;本次规则 API 未报告执行错误。41 条属于监控栈,6 条属于共享 etcd。
- Telegram 已接 warning/critical 和恢复通知;info 不推送。通知接入验收见服务页。
## 初轮覆盖矩阵(实施前)
“无专用告警”指没有该服务的业务/运行告警;共享进程或错误日志规则可能部分命中,不能视为完整覆盖。
| 对象 | 当前指标采集 | 当前告警覆盖 | 主要缺口 |
|---|---|---|---|
| VictoriaMetrics / vmagent / vmalert | 已采集 | 有基础规则 | 部分规则所依赖功能未启用;核对空结果与指标兼容性 |
| Alertmanager | 已采集 | 部分通用进程存活规则 | 缺 Telegram 发送失败、配置加载失败及集群外心跳 |
| VictoriaLogs / VictoriaTraces / OTel / VM Operator | 已采集 | 可能命中通用错误/进程规则 | 缺明确的存活、队列丢弃、容量与数据新鲜度覆盖;现有 ServiceDown 的 job 正则不完整覆盖这些名称 |
| Grafana | 未见专用目标 | 无专用告警 | 页面/登录可用性、数据源失败 |
| laptop node-exporter / process-exporter | 已采集;:9100 重复 | 无主机专用规则 | 内存、swap、磁盘空间/inode、ZFS 健康、IO、主机不可达、进程异常 |
| kubelet / Kubernetes cAdvisor | 已采集 | 无 Kubernetes 对象状态规则 | 只有资源指标,不能替代 Pod/Deployment/PVC 状态采集 |
| kube-state-metrics | 未部署,只有安装脚本 | 无 | NodeNotReady、CrashLoop/OOM、重启、不可用副本、PVC Pending、Job 失败 |
| Blocky | 已采集 | 无 DNS 专用规则 | DNS 实际解析探测、上游失败、响应延迟 |
| 共享 etcd | 三个成员已配置采集 | 6 条专用规则 | 维护中;后续补备份新鲜度、证书到期和目标缺失语义 |
| NATS | exporter 与 PodMonitor 已存在,未进入实际 targets | 无专用规则 | 先修通采集,再补 JetStream 存储、consumer pending/redelivery、连接与集群健康 |
| CNPG PostgreSQL | 现有 Cluster 的 enablePodMonitor=false,无专用 target | 无专用规则 | 连接数、复制/主从、事务、磁盘、备份/WAL 新鲜度;当前单实例 |
| OpenBao | 未接入中央采集 | 无专用规则 | sealed/可用性、请求错误、Raft、PKI 到期、快照成功及异机副本 |
| SPIRE / Authelia / Hydra | 未接入中央采集 | 无专用规则 | 身份签发/登录失败、证书续期、连接依赖、控制器就绪 |
| External Secrets | 未接入中央采集 | 无专用规则 | Secret 同步失败/过期、provider 访问失败 |
| cert-manager | 指标 Service 已有,未采集 | 无证书规则 | 证书临期、续签失败、Issuer 状态;本次 4 个 Certificate 均 Ready 不等于已有告警 |
| Envoy Gateway / Cloudflared | 未接入中央采集 | 无专用规则 | 入口 5xx/延迟、路由、上游、隧道可用性 |
| CoreDNS | 已暴露 :9153 指标,未采集 | 无专用规则 | DNS 请求失败/延迟、实际解析探测 |
| Flux | 未接入中央采集 | 无专用规则 | Kustomization/HelmRelease/GitRepository 同步失败、长时间未更新 |
| SeaweedFS | master/filer/volume 已有 :9327 指标 Service,未采集 | 无专用规则 | 容量、卷/副本健康、S3 可用性、持久化与备份 |
| OpenEBS / ZFS LocalPV | 控制器未专门采集;宿主 ZFS 指标已有 | 无存储专用规则 | PVC/卷挂载、池降级、容量、故障盘;SMART/IPMI 未接入 |
| Gitea / zot / Nexus / NetBox / Backstage | 未见应用专用目标 | 无专用规则 | HTTP 可用性、错误率、依赖;按实际使用优先级接入 |
| Dynamic Runner | 未接入中央采集 | 无专用规则 | 队列积压、调度失败、孤儿实例、执行基础设施不可用;与 NATS 联动 |
| SMTP relay / Tailscale | 未接入中央采集 | 无专用规则 | 邮件队列/投递失败、节点/路由可达性 |
| PVE / OCI / Samba AD / 其他 VM | 中央 targets 未覆盖 | 无专用规则 | 主机存活与资源、复制/时间同步、关键服务、站点网络、备份 |
| laptop Docker / Incus / libvirt / FRR / NFS/SMB 等 | 主机/进程资源只有部分可见性,无组件专用目标 | 无专用规则 | 虚机/容器生命周期、宿主服务失败、路由邻居/存储服务可用性;独立 Docker cAdvisor 未部署 |
| Marker / OpenViking / LiteLLM 等源码服务 | 未见中央 target;运行范围需由各项目确认 | 无中央专用规则 | 先明确现役范围,再接业务指标;不为归档或未部署服务添加空目标 |
| e5renew / research-auto | 有集群 workload,但未见专用目标 | 无中央专用规则 | 属外部消费者,业务规则由项目维护;平台提供通用 workload 健康覆盖 |
## 初轮发现的盲点(实施前)
### Kubernetes 对象状态
没有 kube-state-metrics workload,也没有其 targets。即时查询
`kube_deployment_status_replicas_available`、`kube_pod_container_status_restarts_total`、
`kube_node_status_condition`、`kube_persistentvolumeclaim_status_phase` 均无当前样本。
数据库历史指标名列表仍能找到 kube_*,因此不能仅凭 Grafana 自动补全认定已经接入。
盘点瞬间 Backstage 为 CrashLoopBackOff,SPIRE StatefulSet 的 sandbox controller 不就绪,
SPIRE server 主容器仍 Ready。它们可能由其他任务调整;本轮未诊断或操作,
只用于说明现有 47 条规则无法承担通用 workload 状态告警。以后需要人工对齐维护窗口。
### NATS 声明与运行不一致
NATS StatefulSet 有 :7777 prom-exporter,PodMonitor/nats 已存在,但实际没有 NATS target,
即时 nats_* 查询为空。VM Operator Pod 从 2026-07-10 运行,而 PodMonitor CRD 创建于
2026-09-16;启动时 CRD 发现/转换控制器启动是排查线索,尚不能据此认定根因。
应检查转换器启用状态、watch/RBAC 和启动日志,修复后验证生成对象、target 和实际样本三层。
### 备份不是“有 PVC 就够了”
现有 CNPG Cluster 没有 spec.backup,也没有 ScheduledBackup,status.lastSuccessfulBackup 为空。
这只证明 CNPG 管理的备份链路未声明,不排除未盘点的宿主脚本;需要另外明确备份方式。
OpenBao 源码已有本地 snapshot timer,但成功时间、异机传输和恢复验收没有中央指标/告警。
Samba AD 文档有备份操作示例,SeaweedFS/zot 文档也明确独立异机备份缺口;不能直接标记为已保护。
备份监控至少记录最近成功时间、结果、目标可达性和保留副本;恢复演练成功时间单独记录,
不能由“备份任务退出码 0”推断可恢复。定义实际备份流程后再定告警阈值。
### 监控自身和规则语义
- vmalert 的 AlertmanagerErrors 只覆盖 vmalert → Alertmanager,不覆盖 Alertmanager → Telegram;后者的失败计数已经有指标但没有对应规则。
- 当前 ServiceDown 只匹配部分 VictoriaMetrics job,缺通用 target down 与 expected-target absent 检查。
`up == 0` 无法发现目标被移出发现集合;必须先定义关键目标清单,再做缺失检测。
- 没有 blackbox/VMProbe、probe_* 当前指标或 HTTP/DNS/TCP/TLS 外部探测。
集群内指标正常不证明用户端入口、DNS、证书链与身份登录可用。
- 没有 Watchdog/集群外心跳接收。Alertmanager 或整个站点断电/断网时,内部告警不能保证通知到达。
- RecordingRulesError/RecordingRulesNoData、SeriesLimitHour/DayReached、StreamAggr* 等规则查不到依赖 series;
当前没有 recording rules,部分可选功能可能未启用,不能把所有空结果判为坏规则。
`vmagent_relabel_config_last_reload_successful` 当前也无样本,需逐条做功能/版本匹配。
- 主机 :9100 被 node-exporter 和 docker-hosts 两个 job 重复采集。后续统一所有权,清理前核对查询依赖,避免 sum 重复统计。
- 缺面向节点/服务依赖的抑制、维护静默流程和预期维护范围。优先减少无行动价值的重复通知,不直接导入全套规则。
## 建议实施顺序与验收
| 批次 | 实施内容 | 验收条件 |
|---|---|---|
| 1:补平台基本覆盖 | GitOps 部署 kube-state-metrics;Node/Pod/Deployment/PVC/Job 规则;复用 node-exporter 补主机/ZFS;修 NATS 转换;补 Telegram 发送失败规则 | 新目标 up 且有当前样本;规则有依赖数据;测试触发/恢复消息送达;维护对象能明确静默 |
| 2:保护关键依赖和数据 | CNPG、OpenBao、SeaweedFS、NATS 业务规则;cert-manager、ESO、Flux;备份方案与最后成功时间指标 | 每项有采集、针对性规则、runbook、凭据最小权限和故障演练结果;备份独立验收 |
| 3:验证用户可用性 | LAN DNS、入口 HTTPS、Gitea/认证/S3/镜像等关键路径探测;集群外 Watchdog 接收 | 从独立位置发现站点/监控中断,探测不用暴露管理员凭据或制造业务写入 |
| 4:扩展到其余基础设施和应用 | PVE/OCI/域控主机、Docker/Incus/libvirt/网络;按使用频率接入应用 | 按服务维护覆盖表,退役目标同步移除,采集开销和标签基数受控 |
第一批基础补齐已实施,验收边界见上方链接;下一步对齐第二批关键依赖与备份方案。开始具体实施前对齐各服务进行中的工作,
尤其是共享 etcd、数据库迁移与身份平台;本次盘点不授权自动修改这些项目。
+99
View File
@@ -0,0 +1,99 @@
---
title: 基础监控与告警运维
last_reviewed: 2026-09-25
---
# 基础监控与告警运维
第一批补齐 Kubernetes 状态、主机/ZFS 和通知链路;业务数据库、备份、外部探测等
后续范围见 [覆盖计划](monitoring-coverage.md)。本页的规则检查不等于所有服务健康。
## 声明与归属
维护者于 2026-09-25 明确:新增监控配置优先使用 Prometheus Operator 的
`ServiceMonitor`、`PodMonitor`、`PrometheusRule`。VictoriaMetrics Operator 负责转换为
VMServiceScrape、VMPodScrape、VMRule,vmagent/vmalert 继续负责采集与规则执行。
不要再为同一个新目标/规则手工维护一份 VM 对象;已有历史 VM 配置按需求单独迁移。
- kube-state-metrics:Flux HelmRelease,chart `8.5.0` / app `2.20.0`,适配本集群 Kubernetes 1.36。
- KSM 的 ServiceMonitor 使用 `honorLabels: true`,保留被观测对象的 namespace/pod 等标签。
:8080 提供对象指标,:8081 提供 exporter 自身指标;job 均为 `kube-state-metrics`。
- collector/RBAC 限于本批需要的 nodes、pods、deployments、statefulsets、daemonsets、
PVC/PV、jobs/cronjobs、namespaces,只读 list/watch,没有启用 secrets collector。
- NATS 沿用其 Helm 管理的 PodMonitor,转换后的 `nats/nats` VMPodScrape 抓取 :7777,job 为 `nats/nats`。
- Operator HelmRelease 依赖 `prometheus-operator-crds`;KSM 同时依赖两者。
先确保 CRD Ready,再启动依赖 CRD 的转换器和消费者。
- 源码:[基础补齐 PR #149](https://git.ddupan.top/panxiao81/homelab-infra/pulls/149)。
三份新增规则位于 `platform/observability/metrics/rules/{kubernetes-health,host-health,monitoring-delivery}.yaml`。
PrometheusRule 声明切换见 [PR #151](https://git.ddupan.top/panxiao81/homelab-infra/pulls/151),
Flux 已应用 `e8e7bd4b203def4123658a4d02a1d92a854005fc`。
## 21 条规则的范围
| 组 | 规则与持续时间 | 严重性 |
|---|---|---|
| Kubernetes(11) | NodeNotReady 5m;Memory/Disk/PID Pressure 5m | 节点未就绪 critical,压力 warning |
| Kubernetes(续) | CrashLoop 10m;15 分钟内重启 >3 次持续 5m;近期 OOM 重启 1m;Pod Pending 15m | warning |
| Kubernetes(续) | Deployment/StatefulSet/DaemonSet 可用副本不足 10m;PVC Pending 15m;Job Failed condition 5m | warning |
| 主机(5) | 可用内存 <10% 持续 10m;磁盘可用空间/inode <10% 持续 15m | warning |
| 主机(续) | 文件系统只读 5m;ZFS 池非 online 的状态值为 1 持续 5m | critical |
| 采集(3) | KSM、node-exporter、NATS target down 或整个 job 消失持续 5m | 前两项 critical,NATS warning |
| 通知(2) | Telegram 失败计数最近 5 分钟增加并持续 1m;Alertmanager 配置加载失败 5m | critical |
主机规则只用 `job="node-exporter"`,避免旧 docker-hosts 重复样本。
磁盘规则排除 tmpfs/devtmpfs/overlay/squashfs/nsfs/fuse 和临时挂载路径;inode 总数为零不报警。
OOM 同时要求近期 restart counter 增加,避免历史终止原因持续报警。
Deployment 以声明副本为准,缩容到零不触发。
本批没有增加主机 CPU/Swap/IO 告警、NATS JetStream 业务规则、数据库/备份或外部探测。
job 完全消失使用 absent(up) 检查,但未建立每个预期主机/成员的独立清单,不能保证发现
同一个 job 中少了一个成员;此类预期拓扑检测后续再补。
## 通知、静默与抑制
warning/critical 及恢复消息沿用 [Telegram 路由](../services/grafana.md#telegram-告警接入)。
新规则 annotations 中包含本 runbook 链接。
告警 Source 的指标查询入口与 Grafana 中的 Alertmanager 静默管理入口见
[从告警进入 Grafana](../services/grafana.md#从告警进入-grafana)。
同一 namespace/pod/container 的 `KubePodCrashLooping` 只抑制 `KubePodFrequentRestarts`,
不抑制 OOM,也不静默整个 namespace。工作负载副本不足仍独立可见。
维护时在 Alertmanager 为明确标签创建有截止时间和原因的 silence;不要把维护中的
etcd、SPIRE 或 Backstage 直接写成永久排除规则。结束维护后核对 silence 到期和目标健康。
Telegram 完全不可达时,发送失败告警也无法依靠同一渠道送达。该规则有助于留存和
恢复后通知,不能替代集群外心跳或第二渠道。发送失败时直接检查 Alertmanager/Grafana。
## 接入或升级后如何验收
1. 确认 Flux HelmRelease Ready,原生 ServiceMonitor/PodMonitor/PrometheusRule 存在。
2. 确认转换出的 VM 对象存在、内容同步;不要仅凭原生 CR 已创建判定成功。
3. 在 vmagent `/api/v1/targets` 确认 up、最近采集时间和样本数;VictoriaMetrics 即时查询
验证 `up{job="kube-state-metrics"}`、`up{job="nats/nats"}` 和所需指标当前有值。
4. 在 vmalert `/api/v1/rules` 核对规则数量、lastError 和依赖样本。
没有失败 Job 或 OOM 时条件指标可能不存在,不能把这种空结果直接当作采集失败。
5. 变更规则时从源码运行 `bash platform/observability/metrics/tests/check-rules.sh`;
依赖 Python 3、PyYAML、promtool(本次验证版本 3.5.0)。该脚本直接读取三份规则的 spec.groups,
生成临时文件校验,不维护第二份规则。8 组测试覆盖阈值持续时间、缺失目标和常见噪声边界。
6. 经维护者授权发送临时 canary,验证触发与恢复后删除测试规则,恢复正式规则总数。
不通过制造真实 OOM、磁盘满或破坏 Telegram token 来做验收。
## NATS 转换故障经验
NATS 已有 exporter 和 PodMonitor,但 Operator 自 7 月启动,PodMonitor CRD 到 9 月才安装。
本次滚动重启 Operator 后,日志记录启动 PodMonitor controller 并创建 `VMPodScrape=nats/nats`,
之后 target up 且 nats_* 指标入库。NATS 本身没有重启。
遇到同类问题先检查原生 CR、转换对象、转换器日志、watch/RBAC 和 CRD 安装时间;
不能直接另建同目标 VM scrape 来掩盖转换链路问题。必要重启只针对 Operator,
先确认当前无升级/恢复操作,重启后验证对象生成和采集。
## 本次验证边界
2026-09-25,KSM 两个端点及 NATS 均 up,KSM 约 5,300 条对象样本和 75 条自身样本,
可读到 27 个 workload namespace 的容器重启指标。NATS 有约 187 条采集样本。
正式规则从 47 增为 68,当前规则评估无错误;8 组离线测试、Helm/Kustomize 渲染和服务端 dry-run 通过。
canary 触发已由维护者确认收到;规则恢复后 Telegram 发送计数从 11 增至 12,
失败计数仍为 0,Alertmanager 无残留 canary,测试 VMRule 已删除。恢复消息未单独取得收件端确认。
三份 PrometheusRule 的转换内容一致(仅 VMRule 补默认空 record 字段),vmalert 最终仅有 68 条正式规则,未重复评估。
这些数量是验收快照,不是容量承诺或持续健康结论。正在调整的 etcd 不在本批修复范围。
+166
View File
@@ -0,0 +1,166 @@
---
title: 为新服务配置 LAN HTTPS 入口
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# 为新服务配置 LAN HTTPS 入口
普通 LAN Web 服务使用 `your-app.ad.ddupan.top`,复用共享 Envoy Gateway 和通配符证书。
本指南串联应用 Service、路由、DNS、认证与 GitOps;示例不会自动创建任何对象。
本轮只读仓库与上游资料,未查询现场、签发证书或发布服务。
## 接入前明确应用参数
准备应用 namespace、Service 名称与 **Service port**、域名、访问人群及认证方式。
先让应用及其 Service 在集群内可用;需要秘密或持久存储时,分别参考
[External Secrets](../services/external-secrets.md) 和 [OpenEBS](../services/openebs.md)。
本例约定 namespace 和 Service 均为 `your-app`,Service port 为 `8080`。
这些都是占位值,须替换为实际配置。HTTPRoute 不负责部署应用、创建 namespace 或授予应用权限。
## 1. 复用现有证书与 listener
共享入口为 `envoy-gateway-system/eg`,普通 LAN 域名绑定 `https` listener。
其证书 Secret 为 `envoy-gateway-system/wildcard-ad-ddupan-top-tls`,由 cert-manager 管理。
| 域名场景 | 接入选择 |
|---|---|
| `your-app.ad.ddupan.top` | 复用 `https` listener 与通配符证书 |
| `auth.ddupan.top`、`git.ddupan.top` | 已有各自的 `https-auth`、`https-git` listener |
| 更深的域名或其他域 | 单独设计证书 SAN 与匹配的 listener,不能套用本例 |
TLS 通配符只覆盖一层子域。证书包含 `ad.ddupan.top` SAN 也不表示现有 listener 会接收这个 apex;
证书名称和 listener hostname 是两个需要同时满足的条件。
新 LAN 服务不需要复制私钥、创建第二个 Gateway 或重新安装 cert-manager。
现有通配符通过 `ClusterIssuer/letsencrypt` 与 Cloudflare DNS-01 签发。
DNS-01 不要求业务端口对公网开放;自检需保留现有公共递归 resolver 设置,避免内部 AD 视图看不到公开 TXT。
详见 [cert-manager DNS-01](https://cert-manager.io/docs/configuration/acme/dns01/)。
`bao-acme` 是内部 CA 的另一个选择,客户端需信任内部 CA;它不是无需配套调整的通配符替代品。
## 2. 在应用 namespace 声明 HTTPRoute
```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: your-app
namespace: your-app
spec:
parentRefs:
- name: eg
namespace: envoy-gateway-system
sectionName: https
hostnames:
- your-app.ad.ddupan.top
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: your-app
port: 8080
```
本例后端 Service 与路由同 namespace;`8080` 必须是 Service 暴露的端口,不直接照搬容器端口。
跨 namespace 后端引用还需目标 namespace 的 ReferenceGrant,不能只增加一个 namespace 字段就认为授权完成。
共享 Gateway 的 `allowedRoutes` 允许其他 namespace 挂载路由,但这不等于应用已经得到用户认证保护。
需要 HTTP→HTTPS 跳转时,为同一 hostname 增加独立 HTTPRoute,绑定 `sectionName: http`,
使用 `RequestRedirect` 的 `scheme: https`、`port: 443` 和适当状态码,不配置业务 backend。
HTTPS 路由本身不会自动生成跳转。规则语义参考
[Gateway API 跳转指南](https://gateway-api.sigs.k8s.io/guides/user-guides/http-redirect-rewrite/)。
保留 HTTP listener 的 ACME 用途,不为单个应用替换整个 listener。
## 3. 在受管 DNS 清单增加名称
工作区的声明入口为 `infrastructure/dns/records.yml`,在 `homelab_dns.samba.records`
现有列表中增加以下 RRset,不能用这个片段覆盖原列表:
```yaml
- zone: ad.ddupan.top
name: your-app
type: A
values:
- 192.168.10.127
```
该地址来自共享 Envoy Gateway 的现有记录。Samba Ansible 的 `provision-dc.yml` 已引用该清单,
DNS task 消费 `homelab_dns.samba.records`;旧 README 中增加 `samba_ad_extra_a_records` 的步骤不再作为本页入口。
相关 DNS 清单与任务存在工作区改动,正式合并来源仍需补全,不能认定任意远端 checkout 都已包含它们。
维护者先审查针对 DNS 的 Ansible check/diff,再按既有流程应用。受管 RRset 的 exact 语义可能移除同名同类型的其他值,
因此应检查完整记录集合;不要遍历清理 Samba 自动生成的 AD/Kerberos 记录。
[LAN DNS](../services/lan-dns.md) 与 [Pod DNS](../services/k3s-dns.md) 的路径不同,
新增名称后分别检查所需视图。LAN 已使用 Blocky,不采用旧 DNS README 中“尚未成为正式 resolver”的历史表述。
## 4. 按应用选择认证
| 应用类型 | 接入方式 |
|---|---|
| 已支持 OIDC 的 Web 应用 | 按应用文档接入 Authelia,配置 client、回调地址与应用内权限 |
| 信任反向代理身份头的应用 | 配套 Envoy SecurityPolicy、Authelia 规则及阻止绕过网关的网络策略 |
| API、Git、机器客户端 | 使用服务支持的认证协议,避免浏览器登录跳转截获协议请求 |
Gitea 使用原生登录/OIDC 和 Git token,因此其路由没有套用 NetBox 的 forward-auth。
SPIFFE workload 接入按[机器身份原则](../services/spire.md)设计,服务自行授权;
HTTPS 证书和 HTTPRoute 都不会自动替代业务认证。
forward-auth 的现有参考为 `apps/netbox/securitypolicy.yaml` 与 `networkpolicy.yaml`,另需协调:
- `apps/authelia/referencegrant-extauth.yaml`:目标 namespace 授权新的 SecurityPolicy 来源。
- `apps/authelia/values.yaml`:目标域名及访问群组规则。
- 应用配置:信任哪些身份头,以及如何映射用户权限。
复制前逐项替换 route 名、namespace、Pod selector 和端口。现有 Authelia Service port 是 `80`,
不是容器 `9091`;`headersToBackend` 位于 `extAuth.http`,并由可信结果覆盖客户端同名头。
保留 `failOpen: false`,同时限制直接访问后端的路径。NetworkPolicy 的 probe 例外与节点地址需按应用核对,
不能机械复制 NetBox 的节点白名单。
## 5. 纳入部署入口并验收
将路由和配套策略加入应用 Kustomization 或 chart values,并确认应用由哪个 Flux Kustomization 管理。
只新建 YAML 文件不会使它自动部署。独立新应用还需 namespace 与集群 reconciliation 入口,
按 `clusters/homelab/README.md` 审查;不要为接入一个应用开启全局 prune。
先本地渲染并检查 diff,合并后由已有 GitOps 流程交付。获得现场检查授权后,分层验证:
1. Flux 已同步目标 revision;后端 Service 有可用 endpoint。
2. Gateway listener 可用,HTTPRoute 对目标 parent 的 `Accepted`、`ResolvedRefs` 为 True。
3. 从相应客户端解析新名称,并检查证书名称与信任链。
4. 验证登录、应用权限及需要支持的 API/机器客户端,不能只检查首页 200。
若需分开验证入口与 DNS,可在已授权的客户端使用以下诊断请求,域名仍保留在 TLS SNI 与 Host 中:
```bash
curl --silent --show-error --output /dev/null --write-out '%{http_code}\n' \
--resolve your-app.ad.ddupan.top:443:192.168.10.127 \
https://your-app.ad.ddupan.top/
```
该命令绕过客户端 DNS,不是 DNS 验收;不加 `-k` 绕过证书校验。
响应是否符合预期取决于应用,受保护页面可能返回登录跳转。
## LAN 入口与公网发布的边界
本指南只完成 LAN HTTPS 路径。公开可信证书不意味着服务已开放公网。
公网发布还需单独审查 Cloudflare DNS、Tunnel 路由、访问控制与应用外部 URL,
入口为 `infrastructure/cloudflared/terraform/README.md`;不要从已有域名复制 Tunnel 设置就宣称完成发布。
## 来源与维护
homelab-infra:`platform/cert-manager/README.md`、`certificate-wildcard-ad.yaml`,
`platform/envoy-gateway/README.md`、`gateway.yaml`,`infrastructure/dns/`,
`infrastructure/samba-ad/ansible/`,`apps/netbox/`,`apps/authelia/referencegrant-extauth.yaml`,
`apps/gitea/httproute.yaml` 与 `clusters/homelab/README.md`。
`apps/http-echo/httproute.yaml` 是已排除出 Kustomization 的历史 Contour 示例,
`archive/traefik/` 也不是当前接入模板;不要因文件存在就直接应用。
上述源码 README 的旧描述尚待同步,本页按实际所读配置与维护者已经确认的结论整理。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#publish-service)。
+60
View File
@@ -0,0 +1,60 @@
---
title: 按任务查找文档
last_reviewed: 2026-09-25
---
# 按任务查找文档
先找任务,再读相关服务页;不必一次读取整个仓库。
需要环境清单时看[服务总览](../services/index.md),准备变更时先读[架构约束](../architecture/constraints.md)。
| 要做什么 | 先读 | 需要时再读 |
|---|---|---|
| 评估独立 IAM 与 AI agent 身份 | [独立 IAM 草案](../architecture/independent-iam-draft.md) | [Hydra 人类登录 PoC](../services/hydra.md);完整 IAM 仍为草案 |
| 设计或实现 Ayatori 控制面能力 | [Ayatori 控制面边界](../architecture/ayatori-control-plane.md) | Ayatori 仓库 ADR、对应领域 API 与 adapter 文档 |
| 发布新的 LAN Web 服务 | [发布新服务](publish-service.md) | [DNS](../services/lan-dns.md)、[Authelia](../services/authelia.md) |
| 写 CI 或选择 Pod/VM runner | [Gitea / Actions](../services/gitea.md) | [Dynamic Runner](../services/gitea-dynamic-runner.md)、[SPIFFE](../services/spire.md)、[`ci-actions@v1`](https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1) |
| 为 CI 缓存 Ansible/Go 依赖 | [Nexus POC](../services/nexus.md) | [Dynamic Runner](../services/gitea-dynamic-runner.md)、[OpenBao](../services/openbao.md) |
| 拉取或发布容器镜像 | [zot](../services/zot.md) | [SPIFFE](../services/spire.md);S3 后端维护才读 SeaweedFS |
| 使用 S3 对象存储 | [SeaweedFS](../services/seaweedfs.md) | [OpenBao](../services/openbao.md) |
| 给应用分配数据库 | [共享 PostgreSQL](../services/shared-postgresql.md) | [计划中的 DBaaS](../services/postgresql-tenant-operator.md) |
| 给应用提供秘密或存储 | [External Secrets](../services/external-secrets.md)、[OpenEBS](../services/openebs.md) | [OpenBao](../services/openbao.md) |
| 盘点或补齐监控与告警 | [监控覆盖与补齐计划](monitoring-coverage.md) | [基础监控运维](monitoring-foundation.md)、[Grafana](../services/grafana.md) |
| 排查内存、日志或追踪 | [Grafana](../services/grafana.md) | 对应服务源码 runbook |
| 排查域名解析 | [LAN DNS](../services/lan-dns.md)或[Pod DNS](../services/k3s-dns.md) | [Tailscale](../services/tailscale.md),如果请求来自远程客户端 |
| 排查登录或域权限 | [Authelia](../services/authelia.md)、[Samba AD](../services/samba-ad.md) | 具体应用的权限说明 |
| 为 workload 提供机器身份 | [SPIFFE](../services/spire.md) | 目标服务的 token 与权限规则;进度回到 #34 |
| 使用消息队列 | [NATS](../services/nats.md) | consumer 项目自己的协议与队列文档 |
| 调用模型或处理文档 | [LiteLLM](../services/litellm-gateway.md)、[Marker](../services/marker.md) | [OpenViking](../services/openviking.md),如果需要检索 |
| 让应用发送邮件 | [SMTP relay](../services/smtp-relay.md) | 消费者的发信配置 |
| 远程访问或查看网络资产 | [Tailscale](../services/tailscale.md)、[NetBox](../services/netbox.md) | NetBox 的权威来源是 Git,不能代替运行状态 |
| 管理云主机或虚拟机 | [OCI](../services/oci.md)、[Proxmox](../services/proxmox.md) | 对应 IaC 和网络/HA runbook |
| 使用 PS3 内容或 KMS 服务 | [ps3netsrv](../services/ps3netsrv.md)、[vlmcsd](../services/vlmcsd.md) | 各自客户端配置 |
## 给 AI 接续一个任务
提供目标、目标服务、已经授权的操作范围,以及你掌握但尚未写入文档的变化。
一个简短的任务交接可以这样写:
```text
目标:为某个新应用增加 LAN HTTPS 入口。
入口文档:guides/publish-service.md。
已有条件:应用 namespace、Service 名称与端口、计划域名。
本次范围:先准备配置与文档 PR;尚未授权现场部署。
动态背景:相关 ticket / PR,或维护者最新说明。
完成条件:配置可审阅,检查通过,说明来源与未执行的验证。
```
这个例子的范围仅用于演示,不能覆盖具体任务已经获得的授权。
Samba AD、OCI、Proxmox 已明确以 IaC 为准,可直接核对其代码;其他动态项目按既定规则对齐来源。
身份设计、配置声明、历史实施记录和本次现场证据应分别表达。
## 找到资料后如何判断是否足够
服务页中的 `last_reviewed` 表示文档审阅时间,`last_verified` 才表示对应现场验证时间。
查阅[来源追溯](../sources.md)可定位固定源码版本,并看到它与工作区是否一致。
索引中的“内容一致”只确认文件,不确认服务健康。
检索、转换或 AI 摘要用于定位原文;结论仍应关联到源码、维护者说明或 ticket。
工作完成后,将持久使用方法写入服务页,将一次变化留在 commit/PR,动态进度回到原项目 ticket。
原仓库 README 同步目前按维护者要求暂缓,不将其列为每次任务的前置条件。
+228
View File
@@ -0,0 +1,228 @@
---
title: 2026-09-25 DRBD quorum 抖动与 sandbox 控制面中断
last_reviewed: 2026-09-25
---
# 2026-09-25 DRBD quorum 抖动与 sandbox 控制面中断
状态:服务已恢复;事故机制已确认,资源争用的具体瓶颈与预防性整改仍待验证。
时间统一使用 UTC。报告依据当日 PVE/VyOS/guest 现场日志、相关操作会话和未提交 IaC;
不是全量数据完整性审计,也不把短期恢复等同于根因消除。
## 结论
共享 PostgreSQL 的承载准备在 17:12 为 CT150、CT151 新建 16 GiB、32 GiB HDD DRBD
数据卷,两卷初始同步重叠。随后多个既有 DRBD 资源出现 PingAck 超时和 quorum 丢失。
sandbox1 根卷在 17:15:49 因 I/O 错误中止 ext4 journal、进入只读,PostgreSQL 主库和
本机 K3s 退出;sandbox2 K3s 也失去数据库连接。VyOS HAProxy 摘除了不可连接的后端,
从客户端看起来像 LB 故障。etcd CT150 的 SSD 根卷在 17:16:52 也发生同类故障。
**已确认的直接故障机制**是 DRBD 失去 quorum 后按 `on-no-quorum=io-error` 返回错误,
引发 ext4 只读和上层服务中断。**最有证据支持的触发因素**是新 HDD 卷并发初始同步期间的
共享资源压力;尚无故障时段的链路队列、丢包、磁盘延迟和 CPU 调度证据,不能定论为
某条链路打满、某块磁盘损坏或唯一由 resync 流量造成。
这次更接近故障的操作是“创建数据卷并触发复制”,不是 15:30–15:32 已完成的 etcd
rootfs 迁移。新 shared PostgreSQL 当时尚未启动,未迁移现有 CNPG 或 sandbox 数据库;
影响经共享底层存储扩散到原有服务。
## 影响与恢复边界
| 对象 | 已观察到的影响 | 恢复证据 |
| --- | --- | --- |
| sandbox PostgreSQL,`10.60.0.1:5432` | 主库 `10.60.0.11` 停止监听,LB 无可用 backend | 原主库 crash recovery 完成;sandbox2 streaming/sync,采样 replay lag=0 |
| sandbox K3s,`10.60.0.13:6443` | 两个 API 后端拒绝连接,控制面不可用 | 两个直连 API 与 VIP `/readyz=ok`;两节点和全部 Pod Ready |
| OpenSandbox,`10.60.0.13:8080` | 健康入口仍可返回 200;依赖 K3s 的生命周期操作受控制面中断影响 | `/health` healthy;本轮未实际创建/销毁 sandbox,不能用 health 替代业务验收 |
| shared etcd CT150 | SSD rootfs `emergency_ro`,成员无法正常服务,触发无 leader/频繁选举告警 | 另一会话完成离线修复,记录三成员 endpoint healthy、Raft term/index 一致 |
| 其他 DRBD 资源 | pve1 在限定窗口记录 11 个资源共 43 次 quorum 丢失 | 尚未逐项完成 guest/应用层影响审计,不能说其他服务均未受影响 |
API 全后端不可用从 HAProxy 17:16:01 告警可确认;约 17:49 已有可用 API,
约 17:51 完成双后端、节点与 Pod 验收。控制面中断约 33 分钟,完整恢复约 35 分钟。
恢复后的复制和服务检查未发现新的异常,但不能据此证明中断期间全部业务请求成功或零数据丢失。
数据库日志曾记录同步等待取消及“本地已提交、可能尚未复制”,未逐事务审计;未执行 WAL reset、
standby 提升、数据库重建或恢复旧备份。
## 变更范围与存储映射
| 用途 | PVE/容器 | DRBD resource | 设备 | 存储池/大小 |
| --- | --- | --- | --- | --- |
| 既有 sandbox1 根盘,包含 K3s datastore 主库 | pve1 / CT148 | `pm-6d8bee62` | `drbd1007` | `pve-rg-hdd` / 32 GiB |
| etcd-pve1 根盘 | pve1 / CT150 | `pm-d1d1f3ea` | `drbd1008` | `pve-rg` SSD / 8 GiB |
| 新 PG standby 数据盘 | pve1 / CT150 mp0 | `pm-af21c43d` | `drbd1011` | `pve-rg-hdd` / 16 GiB |
| 新 pgBackRest 仓库盘 | pve2 / CT151 mp0 | `pm-de86804d` | `drbd1012` | `pve-rg-hdd` / 32 GiB |
17:12:20,pve1 作为 SyncSource 向 pve3 同步 CT150 新盘;17:12:56,pve1 又作为
SyncTarget 从 pve2 接收 CT151 新盘。容器操作串行不代表底层复制串行,也不代表不同
SSD/HDD 池具有独立的网络、宿主调度或 I/O 故障域。
## 时间线
| UTC | 事件与证据 |
| --- | --- |
| 15:30:16–15:31:09 | CT150 `move_volume` 完成,PVE 任务 OK;`local-lvm` → `pve-rg` |
| 15:31:32–15:32:11 | CT151 同类迁移完成;会话随后确认三 etcd 端点健康 |
| 17:09:14 | PG 会话说明即将创建独立 HDD mp0、增加内存预算,不启动 PG |
| 17:11:46 | 执行 `ansible-playbook pve-storage.yml` |
| 17:12:20 / 17:12:56 | 两个新 HDD 资源分别开始 DRBD 初始同步,发生重叠 |
| 17:14:00 | 本报告 17:10–17:55 pve1 内核窗口内首条 `quorum( yes -> no )`;对象为既有 `pm-59a94edd` |
| 17:14:09 | PG 会话报告承载准备完成、etcd 健康;未包含 DRBD 同步完成和跨服务检查 |
| 17:15:47–17:15:48 | sandbox1 根卷先后丢失 pve3、pve2 连接,quorum yes→no |
| 17:15:49 | `drbd1007` 写入错误、MMP 写失败、journal abort、只读;PG 启动控制命令报 I/O error,K3s SIGBUS |
| 17:15:54 | HAProxy 报 sandbox1 API 和 PostgreSQL 后端 DOWN |
| 17:16:01 | sandbox2 API 后端也 DOWN,K3s backend 无可用服务器 |
| 17:16:52 | CT150 `drbd1008` 失去 quorum,ext4 进入只读 |
| 17:18:53 | PG 会话发现 CT150 只读,暂停后续部署;另两个 etcd 成员健康 |
| 17:20:27 | 维护者在 PG 会话提供 `SharedEtcdNoLeader` 实际通知 |
| 17:20–17:25 | 准备限速;先遇到 playbook 路径错误,随后遇到 YAML 条件表达式类型错误,修正后重跑 |
| 17:23:39 | 该内核窗口内最后一条 quorum 丢失;之后仍有 PingAck 超时,不能写成“限速后才停止 quorum 丢失” |
| 17:24:37 | Alertmanager 会话获知 etcd 正在另一路调整,结束该会话对 etcd 的排查 |
| 17:25:58 | 会话收到限速成功结果,两主机各 changed=1;新卷 `c-max-rate=10240` |
| 17:25:59–17:28:11 | CT150 停机、离线修复、重新启动;约 17:30 报告三成员健康 |
| 17:31:21 / 17:33:38 | CT151 / CT150 新数据卷分别完成 DRBD 同步,内核标记 resync-finished |
| 17:42 起 | 维护者报告 sandbox LB 异常,本会话开始排查 |
| 17:43–17:46 | 确认 HAProxy 正常、后端故障;定位 sandbox1 根盘 emergency_ro 和原始 quorum/I/O 日志 |
| 17:46:41–17:46:49 | CT148 正常关机完成 |
| 17:47–17:48 | `pct fsck 148 --device rootfs --force 1` 恢复 journal、清理 orphan inode;只读 `e2fsck -fn` 五阶段通过、返回 0 |
| 17:48:40–17:48:44 | CT148 启动;根盘恢复 rw 且无 emergency_ro |
| 17:49:04 / 17:49:08 | 原 PG 主库恢复接收连接;sandbox2 恢复同步 standby |
| 17:50:40 左右 | sandbox2 K3s 在重启服务后恢复 API;此前旧进程卡在故障期间的启动/关闭状态 |
| 约 17:51 | 两个 API 和 VIP readyz 通过、两节点及全部 Pod Ready、复制 lag=0 |
| 17:53:49 | 两个新卷现场复核均 Established/UpToDate,限速属性和运行配置仍为 10240 |
宿主默认 journal 展示曾为 UTC+9,guest/VyOS 使用 UTC。初次用 UTC 字面时间过滤宿主
本地日志没有找到错误;后来用 `journalctl --utc` 和明确 UTC 时间窗口纠正。上表不使用
未经转换的 `Sep 26 02:xx` 作为独立事故时间。
## 故障机制与变更保护缺口
```mermaid
flowchart TD
A[新增两个 HDD 数据卷] --> B[初始同步重叠]
B -. 资源压力为待证实触发因素 .-> C[多个 DRBD 对端 PingAck 超时]
C --> D[既有卷失去 majority quorum]
D --> E[on-no-quorum=io-error]
E --> F[ext4 journal abort / emergency_ro]
F --> G[sandbox PostgreSQL 与本机 K3s 退出]
G --> H[另一 K3s 失去 datastore / API 中断]
H --> I[HAProxy 后端均 DOWN]
F --> J[shared etcd 单成员异常]
```
1. **变更验收停在容器/etcd 层。** `serial: 1` 和 endpoint health 只限制 Ansible 的
容器操作顺序;未等待前一 DRBD 新卷完全同步,所以后台复制仍重叠。
2. **未把新卷创建视为共享基础设施变更。** 新数据库尚未运行、卷内没有业务数据,
仍会发生全卷复制并影响现有资源。仅检查新服务健康不能限制影响范围。
3. **恢复检查范围过窄。** 首轮识别并恢复 CT150 后,未沿同批 quorum/I/O 日志
核查 CT148 等既有消费者;sandbox 控制面继续故障,直至维护者再次报告。
4. **监控缺少依赖链覆盖。** Alertmanager 通知当天已打通,etcd 实际告警送达;
不能归因于“没有通知”。另一会话的盘点发现告警主要覆盖监控自身及 shared etcd,
尚缺可证明有效的跨资源 DRBD、文件系统异常、sandbox API 外部可用性覆盖。
`/health=200` 与单节点 Ready 也不足以证明两个 API 后端健康。
5. **紧急缓解执行有延迟。** 限速 playbook 首次工作目录错误、随后条件被 YAML
解析成非字符串,两次均在配置变更前失败;直到 17:25:58 才有成功回执。
限速后短期稳定且最终同步完成支持资源压力假设,但缺少控制变量;本次最后一次 quorum
丢失早于成功限速,不能把时间相关性写成严格因果证明。现有 `pve-storage.yml` 已补入
限速任务,但位于 `pct set --mp0` **之后**;初始同步在创建卷时已经开始,仍存在未限速
窗口,并且仍缺 DRBD 同步完成屏障。此报告没有擅自更改这些并行工作中的实现。
## 已完成处置与验收
- PG/etcd 会话:仅为两个新卷设置资源级 `DrbdOptions/PeerDevice/c-max-rate=10240`
(配置的自适应同步上限 10 MiB/s),记录幂等复跑无变更;CT150 离线修复后恢复三端点健康。
- 本会话:确认 CT148 stopped、卷身份/未挂载、副本 UpToDate/quorum 后,使用 PVE 安全自动
fsck;返回 1 表示已修复,随后独立只读完整检查返回 0,再启动原容器。
- PostgreSQL 自行回放 WAL 并恢复原角色;未切主。sandbox2 K3s 在数据库恢复后仍卡住,
仅重启该 K3s 服务,未重启或提升它的 PostgreSQL。
- 两个直连 API 与 VyOS VIP `/readyz` 均为 ok;全部 Pod Ready;所有相关 HAProxy
后端 UP/L4OK;OpenSandbox `/health` healthy;目标根卷恢复正常 rw。
- 未修改 VyOS LB、全局 DRBD 协议/quorum/超时或集群网络。VyOS 最新提交及生成配置仍为
9 月 18 日,最近两次 LB 变更仅新增 OpenSandbox 入口并调整其超时。
## 后续整改与关闭标准
下列项目是待办,不代表已获执行或发布授权;责任人/issue 由维护者分配。
| 优先级 | 项目 | 验收条件 |
| --- | --- | --- |
| P0 | 审计同批受影响 DRBD 资源对应 guest/应用 | 11 个资源逐一映射并记录文件系统、服务和数据层状态,不能只看 DRBD UpToDate |
| P0 | 新卷创建前实施同步预算,新增 DRBD 同步屏障 | 第一字节同步前限额已生效;全部所需副本 UpToDate/Established 才允许下一卷;超时/异常停止推进 |
| P0 | 扩大存储变更前后健康检查 | 验证已有 sandbox API、datastore、etcd 等消费者;新增 quorum loss、I/O 错误或只读即中止变更 |
| P1 | 采集并定位实际瓶颈 | 对齐三宿主网络丢包/队列、吞吐、磁盘 await、CPU/PSI、DRBD 状态;无证据不直接扩大 ping timeout |
| P1 | 补齐可操作告警 | DRBD quorum/peer、ext4 emergency_ro、数据库与 API 外部探测、LB 零后端,并演练真实通知链路 |
| P1 | 恢复后业务验收与数据检查 | 对现有 sandbox 生命周期操作做受控验收,核对 PG 数据/备份和应用影响,单独报告不能验证的 RPO |
| P1 | 复核共享故障域与同步总预算 | 同时覆盖多个 resource/peer;区分 SSD/HDD 池和物理网络/宿主故障域;设计限速或隔离方案后再测试 |
| P2 | 标准化取证与并行变更交接 | 时间统一 UTC;事故期间共享受影响资源表、执行日志和完成边界;先 syntax/check,再执行缓解 playbook |
关闭本次根因整改需完成:跨资源影响审计、同步前预算与屏障验证、消费者健康保护、
足够覆盖复制全过程的稳定性观察。当前只可宣称 **sandbox 服务恢复**。
## 证据与来源
### 现场关键摘录
```text
17:12:20 drbd pm-af21c43d/0 drbd1011 pve3: Began resync as SyncSource
17:12:56 drbd pm-de86804d/0 drbd1012 pve2: Began resync as SyncTarget
17:15:47 drbd pm-6d8bee62 pve3: PingAck did not arrive in time.
17:15:48 drbd pm-6d8bee62 pve2: PingAck did not arrive in time.
17:15:48 drbd pm-6d8bee62/0 drbd1007: quorum( yes -> no )
17:15:49 EXT4-fs error (device drbd1007): kmmpd:181: Error writing to MMP block
17:15:49 Aborting journal on device drbd1007-8.
17:15:49 EXT4-fs (drbd1007): Remounting filesystem read-only
17:16:52 drbd pm-d1d1f3ea/0 drbd1008: quorum( yes -> no )
17:16:52 EXT4-fs (drbd1008): Remounting filesystem read-only
17:31:21 drbd pm-de86804d/0 drbd1012 pve2: repl( SyncTarget -> Established ) [resync-finished]
17:33:38 drbd pm-af21c43d/0 drbd1011 pve3: pdsk( Inconsistent -> UpToDate ) repl( SyncSource -> Established ) [resync-finished]
```
上述为 pve1 内核摘录,已省略重复前缀。43 次 quorum 丢失统计范围为 pve1 的
`2026-09-25 17:10:00 UTC` 至 `17:55:00 UTC`,不是三节点全集群事件数。
资源为 `pm-1f83b001`、`pm-57eb0cd7`、`pm-59a94edd`、`pm-6d8bee62`、
`pm-7ad1a714`、`pm-a58b5f08`、`pm-cbba8c9d`、`pm-d1d1f3ea`、
`pm-d4c12a89`、`pm-f21d1da3`、`vm-101-cloudinit`。
可复核入口:宿主 `journalctl --utc -k --since '2026-09-25 17:10:00 UTC'
--until '2026-09-25 17:55:00 UTC'`、`pvenode task list`、目标 `drbdsetup status`;
VyOS `journalctl -u haproxy` 和只读 stats socket;guest PostgreSQL/K3s journal。
日志有保留期限,后续审计应保存经过秘密审查的所需片段。
### 操作会话
按维护者指向的 spaces1、spaces3 线索,读取了本地以下实际会话;以会话 ID/标题定位,
不把 UI 的位置编号当作长期标识。不复制完整会话或凭据。
- `01a0d8c1-c4ad-7360-b52e-2a11c34dc13e`,**规划共享 PostgreSQL 数据库**:
17:11:46 工具调用 `ansible-playbook pve-storage.yml`;17:20:27 输出显示默认
`c-max-rate=102400k`,这只是配置上限,不是已测吞吐;17:25:58 两卷限速成功;
17:30–17:31 报告 CT150 恢复;对应 rollout 的关键记录在行 1916、2019、2068 附近。
- `01a0d972-e6e5-7432-ad4b-4fd7ca7b3956`,**配置 Alertmanager 通知**:
17:13 用户确认测试通知送达;17:20 后观察到 etcd 新故障;17:24:37 用户确认
另一路正在调整 etcd;约 17:28–17:30 记录监控覆盖缺口。该会话的监控盘点不等于
对 sandbox 集群做过完整事故验收。
- `01a0d9a9-7ef0-7992-a313-54668bb3b4e4`,**检查 VyOS 上的 LB 配置**:
本次 sandbox 诊断、CT148 离线恢复和最终链路验收。
本地原记录位于 `/home/panxiao81/.codex/sessions/2026/09/25/`。
会话说明只能证明当时的判断;时间线中执行结果以工具回执、PVE 任务和内核日志交叉核对。
### 相关源码与运行手册
- etcd rootfs 迁移:`infrastructure/etcd/ansible/move-storage.yml`
- PG 数据卷准备:`infrastructure/shared-postgresql/ansible/pve-storage.yml`
- 新卷限速任务:`infrastructure/shared-postgresql/ansible/tasks/limit-resync.yml`
- etcd 故障恢复记录:`infrastructure/etcd/README.md`
- shared PostgreSQL 当前部署边界:`infrastructure/shared-postgresql/README.md`
- sandbox 架构与数据库依赖:`infrastructure/sandbox-cluster/README.md`
上述源码路径相对于 homelab-infra;etcd/shared-postgresql 文件在取证时仍未提交,
当前文件已包含事故后的限速补丁,不能倒推事故前已经有同样保护。
本报告以 wiki 为唯一维护位置,长期操作流程见[Proxmox 恢复手册](../services/proxmox.md#sandbox-lb-与根文件系统恢复)。
源码合并后再补其固定版本链接。
### 取证过程中的敏感输出问题
首次 VyOS 查询误认为 `cli-shell-api showConfig` 尾随 `load-balancing` 会限制子树,
实际返回完整配置,包含 WireGuard 私钥及登录密码哈希,进入了本会话工具输出。
后续已改为设备端提取所需段,并在 `CLAUDE.md` 记录陷阱;未把敏感值写入报告或仓库。
既有会话记录并未因此消除,应限制其分享;相关凭据轮换需另行安排,不能称为已处理完毕。
+3
View File
@@ -0,0 +1,3 @@
markdown-it-py==3.0.0
mdurl==0.1.2
PyYAML==6.0.1
+221
View File
@@ -0,0 +1,221 @@
#!/usr/bin/env python3
"""离线检查 wiki 的元数据、链接、标题锚点与服务索引。"""
from __future__ import annotations
import argparse
from datetime import date
from html.parser import HTMLParser
from pathlib import Path
import re
import subprocess
import sys
import unicodedata
from urllib.parse import unquote, urlsplit
from markdown_it import MarkdownIt
import yaml
LIFECYCLES = {"planned", "experimental", "active", "retired", "unknown"}
EVIDENCE = {"configuration", "documented", "live-verified"}
# These two pages are navigation/scope descriptions, not individual services.
SERVICE_INDEXES = {"services/index.md", "services/external-consumers.md"}
class UniqueLoader(yaml.SafeLoader):
pass
def unique_mapping(loader, node):
result = {}
for key_node, value_node in node.value:
key = loader.construct_object(key_node)
if not isinstance(key, str):
raise ValueError("frontmatter 键必须是字符串")
if key in result:
raise ValueError(f"重复 frontmatter 键:{key}")
result[key] = loader.construct_object(value_node)
return result
UniqueLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, unique_mapping)
def split_frontmatter(text):
lines = text.splitlines(keepends=True)
if not lines or lines[0].strip() != "---":
return None, text
for i in range(1, len(lines)):
if lines[i].strip() == "---":
metadata = yaml.load("".join(lines[1:i]), Loader=UniqueLoader)
if not isinstance(metadata, dict):
raise ValueError("frontmatter 必须是映射")
# Preserve line positions for diagnostics.
return metadata, "\n" * (i + 1) + "".join(lines[i + 1:])
raise ValueError("frontmatter 缺少结束分隔符")
def as_date(value):
if type(value) is date:
return value
if isinstance(value, str) and re.fullmatch(r"\d{4}-\d{2}-\d{2}", value):
return date.fromisoformat(value)
raise ValueError("必须是 YYYY-MM-DD 日期")
def metadata_errors(meta, required=False, template=False):
if meta is None:
return ["服务页缺少 frontmatter"] if required else []
errors = []
keys = {"title", "last_reviewed"}
if required:
keys |= {"lifecycle", "evidence", "last_verified"}
for key in sorted(keys - meta.keys()):
errors.append(f"缺少字段 {key}")
if not isinstance(meta.get("title"), str) or not meta["title"].strip():
errors.append("title 必须是非空字符串")
for key, choices in [("lifecycle", LIFECYCLES), ("evidence", EVIDENCE)]:
if key in meta and (not isinstance(meta[key], str) or meta[key] not in choices):
errors.append(f"{key} 不在允许值中")
dates = {}
for key in ["last_reviewed", "last_verified"]:
if key not in meta:
continue
if meta[key] is None:
if key == "last_reviewed" and not template:
errors.append("last_reviewed 不得为 null")
continue
try:
dates[key] = as_date(meta[key])
except (ValueError, TypeError):
errors.append(f"{key} 必须是 YYYY-MM-DD 日期或允许的 null")
if meta.get("evidence") == "live-verified" and "last_verified" not in dates:
errors.append("live-verified 必须提供 last_verified 日期")
if len(dates) == 2 and dates["last_verified"] > dates["last_reviewed"]:
errors.append("last_verified 不能晚于 last_reviewed")
if "sources" in meta and (not isinstance(meta["sources"], list) or
any(not isinstance(x, str) or not x.strip() for x in meta["sources"])):
errors.append("sources 必须是非空字符串组成的列表(可为空列表)")
return errors
def slug(text):
# Common Gitea/GitHub heading form; keep CJK, words, spaces and hyphens.
return "".join(c for c in text.lower() if c in " -_" or
unicodedata.category(c)[0] in "LN").replace(" ", "-")
class HTMLLinks(HTMLParser):
def __init__(self):
super().__init__()
self.links = []
self.anchors = set()
def handle_starttag(self, tag, attrs):
attrs = dict(attrs)
for key in ["href", "src"]:
if attrs.get(key):
self.links.append(attrs[key])
if attrs.get("id"):
self.anchors.add(attrs["id"])
if tag == "a" and attrs.get("name"):
self.anchors.add(attrs["name"])
def parse_body(body):
tokens = MarkdownIt("commonmark").enable("table").parse(body)
anchors, links = set(), []
for i, token in enumerate(tokens):
if token.type == "heading_open":
inline = tokens[i + 1]
text = "".join(t.content for t in inline.children or []
if t.type in {"text", "code_inline", "image"})
base = slug(text)
candidate, suffix = base, 0
while candidate in anchors:
suffix += 1
candidate = f"{base}-{suffix}"
anchors.add(candidate)
def visit(t, line):
line = t.map[0] + 1 if t.map else line
if t.type in {"link_open", "image"}:
url = t.attrGet("href" if t.type == "link_open" else "src")
if url is not None:
links.append((line, url))
if t.type in {"html_inline", "html_block"}:
html = HTMLLinks()
html.feed(t.content)
anchors.update(html.anchors)
links.extend((line, u) for u in html.links)
for child in t.children or []:
visit(child, line)
visit(token, 1)
return anchors, links
def check(root, files):
root = root.resolve()
errors, documents = [], {}
for relative in files:
path = root / relative
try:
if not path.resolve().is_relative_to(root):
raise ValueError("文件指向仓库外部")
meta, body = split_frontmatter(path.read_text(encoding="utf-8"))
required = relative.startswith("services/") and relative not in SERVICE_INDEXES
errors.extend(f"{relative}:1: {e}" for e in metadata_errors(
meta, required=required, template=relative.startswith("templates/")))
documents[relative] = parse_body(body)
except (ValueError, OSError, yaml.YAMLError) as exc:
# Do not print YAML source lines: malformed frontmatter may contain secrets.
errors.append(f"{relative}:1: 无法解析文件或 frontmatter({type(exc).__name__})")
indexed = set()
for relative, (_, links) in documents.items():
for line, url in links:
prefix = f"{relative}:{line}: "
try:
parsed = urlsplit(url)
except ValueError:
errors.append(prefix + "URL 格式无效")
continue
if parsed.scheme in {"http", "https", "mailto", "tel", "data"} or parsed.netloc:
continue
if parsed.scheme or parsed.path.startswith("/"):
errors.append(prefix + "链接必须使用仓库内相对路径或网页 URL")
continue
target = ((root / relative).parent / unquote(parsed.path)).resolve() if parsed.path else root / relative
if not target.is_relative_to(root):
errors.append(prefix + "链接越出仓库")
continue
if not target.exists():
errors.append(prefix + f"目标不存在:{unquote(parsed.path)}")
continue
dest = target.relative_to(root).as_posix()
if relative == "services/index.md":
indexed.add(dest)
anchor = unquote(parsed.fragment)
if anchor and dest in documents and anchor not in documents[dest][0]:
errors.append(prefix + f"标题锚点不存在:{dest}#{anchor}")
for relative in documents:
if relative.startswith("services/") and relative not in SERVICE_INDEXES and relative not in indexed:
errors.append(f"{relative}:1: 服务页未被 services/index.md 链接")
return errors
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, default=Path(__file__).resolve().parents[1])
args = parser.parse_args()
output = subprocess.check_output(
["git", "-C", str(args.root), "ls-files", "--cached", "--others", "--exclude-standard", "-z"])
files = sorted({p for p in output.decode().split("\0") if p.endswith(".md")})
errors = check(args.root, files)
if errors:
print("\n".join(errors), file=sys.stderr)
return 1
print(f"文档检查通过:{len(files)} 个 Markdown 文件;未联网或执行文档示例。")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+5 -3
View File
@@ -2,7 +2,7 @@
title: Authelia
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_reviewed: 2026-09-25
last_verified: null
sources:
- 维护者于 2026-09-16 确认当前状态
@@ -10,8 +10,10 @@ sources:
# Authelia
**Authelia 已作为 homelab 唯一的主 OIDC broker 工作,当前状态为 active。**
此状态由维护者于 2026-09-16 明确,本轮未查询运行环境。
**Authelia 继续作为 homelab 的主 OIDC 入口与人类认证后端工作,状态为 active。**
基础状态由维护者于 2026-09-16 明确。2026-09-25 新增 [Hydra 人类登录 PoC](hydra.md),
以标准 OIDC client 复用 Authelia;其原有应用客户端、Samba AD 后端及 MFA 策略保留。
该次仅验证新增配置有效和 Pod 就绪,未更新本页原有功能的整体验收日期。
## 用途与入口
+87
View File
@@ -0,0 +1,87 @@
---
title: External Secrets 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# External Secrets Operator
ESO 将 [OpenBao](openbao.md) 中的秘密投射为 Kubernetes Secret,供应用消费。
本页依据 homelab-infra 工作区 `platform/external-secrets/README.md`、
`clustersecretstore.yaml`、`externalsecrets.yaml` 与 `kustomization.yaml` 整理,未查询现场。
其中 `externalsecrets.yaml` 含未提交修改,不代表这些修改已部署。
## 应用如何获得秘密
现有 `ClusterSecretStore/openbao` 指向 `https://bao.ad.ddupan.top:8200` 的 KV v2 mount `kv`。
ESO 使用 `external-secrets` namespace 中同名 ServiceAccount 的短期 JWT,
通过 OpenBao 的 Kubernetes auth 与 `external-secrets` role 登录。
这是已记录的认证方式,不能因 SPIFFE 是整体身份设计就宣称 ESO 已迁移到 SPIFFE。
接入前由维护者确认应用 namespace、OpenBao 路径、字段、目标 Secret 名称和授权范围。
先准备 OpenBao 中的真实值,再提交只含引用的 ExternalSecret;凭据本身不进 Git。
共享 ClusterSecretStore 不意味着任意 namespace 都应有权引用所有秘密,新增引用需要审查来源与消费者权限。
## 最小字段投射示例
以下是待按应用替换的模板:`your-app` namespace 须已存在,
OpenBao 的 `kv/k8s/your-app` 须已包含 `password` 字段且允许 ESO 读取。
本轮仅展示模板,没有创建这些对象。
```yaml
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: your-app-credentials
namespace: your-app
spec:
refreshInterval: 1h
secretStoreRef:
name: openbao
kind: ClusterSecretStore
target:
name: your-app-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: k8s/your-app
property: password
```
`remoteRef.key` 相对于 store 的 `kv` mount,不把 API 的 `data/` 层写进这个例子。
字段映射语义见 [ESO Vault provider](https://external-secrets.io/latest/provider/hashicorp-vault/);
这里沿用现有 `vault` provider 配置,不因上游出现其他 provider 就修改认证实现。
应用在同一 namespace 的容器配置中引用生成结果,例如:
```yaml
env:
- name: APP_PASSWORD
valueFrom:
secretKeyRef:
name: your-app-credentials
key: password
```
这是容器配置片段,需放入应用自己的 manifest,不能独立 apply。
采用环境变量消费时,Secret 刷新不会更新已启动进程的环境变量,轮换须配合应用重启或既有滚动流程。
## 同步与维护边界
受权检查时,先查看 ExternalSecret 的同步状态与事件,再确认目标 Secret 的名称和键是否满足应用引用;
不通过输出 Secret YAML 或解码真实值来证明接入成功。
引用缺失先检查 namespace、路径和字段;认证失败检查 store 的 ServiceAccount、OpenBao role/policy 与 TLS。
`creationPolicy: Owner` 使 ESO 管理目标 Secret 的所有权,删除 ExternalSecret 可能连带删除目标 Secret,
不能将它当作无影响的临时配置。不要手工覆盖 ESO 生成的副本。
源码 README 明确区分 Helm release 接管与 secret delivery 对象接管,当前目录 Kustomization
只列 Helm 相关资源,没有列入 `clustersecretstore.yaml` 和 `externalsecrets.yaml`。
新增引用先确定由哪个 GitOps/部署入口管理;把文件改好不等于 Flux 已经应用。
部署和接管细节回到 `platform/external-secrets/README.md`。
依赖包括 OpenBao、Kubernetes TokenReview、集群 DNS 与 ESO controller。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#external-secrets)。
+40 -3
View File
@@ -2,10 +2,12 @@
title: Gitea Dynamic Runner
lifecycle: experimental
evidence: documented
last_reviewed: 2026-09-16
last_reviewed: 2026-09-21
last_verified: null
sources:
- https://git.ddupan.top/panxiao81/gitea-dynamic-runner/src/branch/main/README.md
- https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/platform/dynamic-runner/README.md
- https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1
---
# Gitea Dynamic Runner
@@ -17,9 +19,23 @@ microVM;每个环境只执行一个 job,结束后销毁环境及本地状态
更名由维护者提供;以下组件与接口说明依据 2026-09-16 查阅的项目 README。
维护者进一步明确:**项目正在积极开发,具体启用范围和实现进度以该项目文档为准。**
本页保留用途、设计原则和该次 README 的摘要,不另行维护部署范围或消息队列参数清单。
本页保留用途、设计原则和该次 README 的摘要,仅补充维护者明确提供的阶段与容量,不复制维护完整部署范围或消息队列参数清单。
本轮未查询现场,不将设计接口视为已完成的上线验收。
## 当前开发与启用阶段
维护者于 2026-09-16 补充:开发接近完成,动态 `pod` 已上线测试,`vm` 正在工作;
纯 `self-hosted` 的旧常驻 runner 准备退役。
| 执行环境 | workflow labels | 系统总并发量 | 阶段 |
|---|---|---:|---|
| Pod | `[self-hosted, pod]` | 4 | 已上线测试 |
| VM | `[self-hosted, vm]` | 1 | 正在工作,具体进度以项目文档为准 |
并发量是对应环境在系统中的总容量,不按仓库或 workflow 分别分配一份额度。
本页记录维护者提供的阶段与容量,不将“上线测试”写成完整正式验收;
旧常驻 runner 也尚未标记为已退役。后续变化继续以项目文档为准。
## workflow 如何选择执行环境
README 定义两种稳定接口,在 workflow 的 job 中选择:
@@ -34,13 +50,23 @@ runs-on: [self-hosted, vm]
| 接口 | 执行方式 | 使用时需要理解的边界 |
|---|---|---|
| `pod` | 动态 Kubernetes privileged Pod;workflow 使用 host executor | Docker、BuildKit、kind 等工具由 pipeline 按需 setup;这里的 host executor 指 Pod 内执行环境 |
| `pod` | 动态 Kubernetes privileged Pod;workflow 使用 host executor | 旧 README 要求 pipeline 按需 setup Docker;Docker 的新约定见下文。host executor 指 Pod 内执行环境 |
| `vm` | 动态 Cloud Hypervisor microVM | 每个任务创建独立 COW disk、seed 和 TAP,guest runner 执行一个 job 后关机并清理 |
两种接口不能仅凭“环境一次性”就认定具有相同的隔离边界。
接入前需要结合项目设计约束和实际部署确认任务的信任范围。
旧 homelab-infra 文档中的 `kind-microvm` 是早期记录,不作为本项目当前 workflow 接口。
### Docker 可用性约定更新
维护者于 2026-09-21 明确:CI 后端正在修复,后续由 runner 保证 dockerd 默认可用。
这取代旧说明中要求业务 workflow 自行启动 Docker daemon 的部分;不能据此推断 BuildKit、
kind 等其他工具也默认就绪。数据库集成测试不因使用 Docker 而要求 VM。
消费方 workflow 应检查 Docker 是否可用,而不重复启动 daemon、强制 storage driver 或
覆盖 runner 提供的 endpoint。[Ayatori #6](https://git.ddupan.top/panxiao81/ayatori/pulls/6)
正在按此约定调整。此处依据维护者说明,不表示后端修复已经部署或远端集成已经通过,
`last_verified` 保持不变。
## 组件如何协作
当前 README 描述的 bootstrap 路径为:
@@ -80,6 +106,16 @@ workflow 决定如何消费身份:登录哪个服务、请求哪个 audience
不属于 runner 内置的业务流程。向其他服务请求 token 也遵循同一边界;
runner 不应替 workflow 选择下游 role/policy,或统一代理其业务凭据交换。
通用实现已发布为 [`panxiao81/ci-actions@v1`](https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1):
`spiffe-openbao-login` 负责获取 JWT-SVID、交换 Bao token 和退出吊销,`setup-nexus`
负责匿名配置 Ansible Galaxy、Go module proxy 与 OCI endpoint。后者读取 Nexus public
repository 时不需要 Bao 登录;发布制品应另建 repository service account 和最小权限
policy。
这些 Action 不扩大 runner 权限。runner 只提供 Node.js 20、`spire-agent` 与 Workload
API socket,workflow 明确声明 role、audience 和用途,目标服务 policy 做最终授权。
由于短期 token 会进入 Actions job 临时文件,只能在一次性 Pod/VM executor 使用。
因此,身份相关的环境验收应关注 Pod/VM 能否取得各自身份和是否保持隔离;
具体服务的登录与 token 使用由对应 workflow 验收。
本段记录设计职责,不表示获取身份的能力已经在所有 backend 完成实现或现场验证。
@@ -101,6 +137,7 @@ runner 不应替 workflow 选择下游 role/policy,或统一代理其业务凭
- [设计原则](https://git.ddupan.top/panxiao81/gitea-dynamic-runner/src/branch/main/docs/design-principles.md):README 指向的完整设计约束,本轮未逐篇复核。
- [Runner 协议路线](https://git.ddupan.top/panxiao81/gitea-dynamic-runner/src/branch/main/docs/runner-protocol-roadmap.md):README 指向的长期调度路线与迁移边界,本轮未逐篇复核。
- [SPIFFE/SPIRE](spire.md):统一机器身份的设计定位与阶段依据。
- [`ci-actions@v1`](https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1):workflow 可复用的 SPIFFE/OpenBao 登录与 Nexus 配置 Action。
实际启用范围、workflow 验收、排障及消息队列约定在项目文档中维护。
开发中的变化直接以项目文档为准,知识库不另列“启用范围待核实”任务。
+90
View File
@@ -0,0 +1,90 @@
---
title: Gitea 与 Actions 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-25
last_verified: null
---
# Gitea 与 Actions
Gitea 托管 homelab 的代码、文档、issue 和 PR;Actions 执行仓库声明的 CI workflow。
入口为 <https://git.ddupan.top>,人类登录使用 [Authelia](authelia.md)。
本页依据现有服务 README、runner README、仓库 workflow 和官方使用文档整理。
本轮没有重新验证登录或运行示例;下面的操作是使用指南,不是本轮执行记录。
## 登录并找到项目
1. 打开 Gitea,选择已配置的 Authelia/OIDC 登录入口。
2. 在 Authelia 完成认证,返回 Gitea;应用权限由 Gitea 账号和仓库授权决定。
3. 打开目标仓库:Code 看源码,Issues 看动态工作,Pull Requests 看待合并改动,Actions 看 CI。
登录成功但看不到仓库时,先确认当前账号与仓库权限;OIDC 登录本身不会赋予所有项目的管理权。
已有账号应沿用原账号关联,遇到关联问题交由管理员处理,不另建同名账号规避。
## Hydra 实验性登录
2026-09-25 按维护者要求新增 [Hydra 人类登录 PoC](hydra.md),保留旧 Authelia 登录源。
从 <https://git.ddupan.top/user/oauth2/hydra> 发起,需 LAN/Tailscale 连通 Hydra 内网入口。
最终认证仍在 Authelia 完成;真实账号返回和权限验收结果见 Hydra 服务页。
## 创建与修改仓库
通过页面的 New Repository 创建仓库,选择所属用户或组织、名称及可见性。
仓库里的 Clone 按钮提供当前准确的 HTTPS/SSH 地址,复制该地址到 Git 客户端即可。
浏览器的 OIDC 会话不直接充当 Git 命令行凭据;客户端使用自己的凭据管理或已登记 SSH key。
日常修改先建分支、提交并推送,再开 PR 合并到 main。PR 应说明最终行为与验证结果,
不要把本机未提交的其他工作一并带入。基础设施仓库默认以中文维护 commit、PR 和文档。
## 第一个 CI workflow
在可信的测试仓库中启用 Repository Actions,再添加 `.gitea/workflows/hello.yaml`:
```yaml
name: Hello
on: [push]
jobs:
hello:
runs-on: [self-hosted, pod]
steps:
- name: Check execution
run: echo 'homelab CI is running'
```
推送该文件后,进入 Actions,打开本次运行和 hello job。
预期看到输出 `homelab CI is running` 且 job 成功;示例不需要检出源码或读取秘密。
若仓库设置没有 Actions 开关,先确认自己的管理权限。
workflow 路径、启用方式与事件规则见 [Gitea 官方入门](https://docs.gitea.com/usage/actions/quickstart/)。
维护者于 2026-09-16 说明:动态 `pod` 已上线测试,系统总并发量为 4;
纯 `self-hosted` runner 准备退役,新 workflow 使用明确的动态环境 labels。
本例据此采用 `[self-hosted, pod]`,本轮未实际运行示例。
若任务排队,除 runner 在线状态和 labels 外,也要考虑系统并发容量,不能把入队当作执行成功。
## 选择 runner
| 需求 | 使用入口 |
|---|---|
| 动态 Pod:已上线测试 | `[self-hosted, pod]`;系统总并发 4,不是每个仓库各有 4 个名额 |
| 动态 VM:正在工作 | `[self-hosted, vm]`;系统总并发 1,具体可用范围和进度以项目文档为准 |
| 旧常驻 runner:准备退役 | 纯 `self-hosted`,不再作为新 workflow 的默认示例;已有 workflow 需按需求迁移到明确的 Pod/VM 接口 |
上述阶段与容量由维护者于 2026-09-16 提供。实现与后续变化见
[Dynamic Runner](gitea-dynamic-runner.md) 及其项目文档。
常驻 runner 使用 privileged DinD,README 明确限定可信 workflow;不要为不可信代码开放它。
动态 runner 提供环境及获取自身 SPIFFE 身份的能力;登录下游、请求 token 和凭据清理由 workflow 负责。
## 遇到问题先看哪里
- 没有触发:看 Actions 是否启用、文件是否位于正确路径、事件是否匹配此次推送。
- 一直排队:看仓库可用 runner、在线状态和 labels;动态 runner 的问题回到其项目文档。
- job 失败:打开具体 step 的日志,从第一个失败步骤排查,不只看最终退出码。
- Git 命令失败但网页能登录:分别检查 Git 使用的身份、凭据方式和仓库权限。
服务部署与升级恢复以 homelab-infra `apps/gitea/README.md` 为入口;常驻 runner 以
`platform/gitea-runner/README.md` 为入口。本页不复制 token、密码或部署命令。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#gitea)。
+171
View File
@@ -0,0 +1,171 @@
---
title: Grafana 与可观测性使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-25
last_verified: null
---
# Grafana 与可观测性
从 <https://grafana.ad.ddupan.top> 查看 homelab 的指标、日志和追踪。
使用 Authelia OIDC 登录;远程访问需要到 LAN 的路由及内网 DNS。
本页依据现有 observability README、Grafana 数据源配置、内存看板 JSON 和 exporter 说明整理,
部分来源仍在源码工作区、尚未提交。看板使用说明未逐项现场验证;
2026-09-25 的通知链路与采集故障验证范围见下文。
整体接入范围、已确认盲点和补齐顺序见 [监控覆盖与补齐计划](../guides/monitoring-coverage.md)。
第一批已接入的规则、阈值、静默和排障方法见 [基础监控与告警运维](../guides/monitoring-foundation.md)。
## 先看主机内存与 Swap
1. 打开 [Homelab 内存与 Swap](https://grafana.ad.ddupan.top/d/homelab-memory)。
2. 时间范围选择最近 1 小时,需要定位问题时改成问题发生的具体时段。
3. 先看“主机物理内存”“Swap 使用量”“Swap 换页速率”,再看程序/虚拟机 PSS 和 Pod working set。
4. 对比异常发生前后的曲线,记录时间与相关程序或 Pod,便于继续查日志。
看板来源为 `platform/observability/grafana/dashboards/homelab-memory.json`。
PSS、RSS、Pod working set 和 ZFS ARC 是不同统计口径,不应直接相加。
“没有数据”表示当前查询没有返回匹配样本,不等于数值为零。
## 自己查一条指标
进入 Explore,选择 **VictoriaMetrics** 数据源,时间范围设为最近 1 小时,
在 Code 模式输入以下看板已有的表达式,再执行查询:
```promql
node_memory_MemTotal_bytes{job="node-exporter"}
- node_memory_MemAvailable_bytes{job="node-exporter"}
```
它计算主机已用内存,单位为字节。预期按采集目标返回曲线;有多个目标时,
查看返回标签后选择相应 instance,避免把多台机器当作一台解读。
该环境特意限定 `job="node-exporter"`,避免旧 docker-hosts 抓取同端口导致重复统计。
如需查看 Swap 换出活动,可使用看板已有查询:
```promql
rate(node_vmstat_pswpout{job="node-exporter"}[5m])
```
单位是 pages/s,不是 bytes/s。查询入口与编辑器行为见
[Grafana Prometheus 查询文档](https://grafana.com/docs/grafana/latest/datasources/prometheus/query-editor/)。
## 找一段日志
1. 进入 Explore,切换到 **VictoriaLogs** 数据源,设定最近 15 分钟。
2. 输入 `* | limit 20` 执行查询,展开一条结果,观察这套采集实际提供的字段。
3. 用真实出现的 namespace、Pod 或应用字段收窄范围;不要预先假定字段名。
4. 要找错误消息,可先输入 `error | limit 50`;有结果后按实际字段进一步筛选。
VictoriaLogs 使用 LogsQL。上述 limit 限制返回数量,不保证返回的是最新若干条。
关键字没有结果时可以放宽时间范围并回到第一步,区分“没有该关键字”与“没有采集数据”。
语法依据见 [VictoriaLogs 查询说明](https://docs.victoriametrics.com/victorialogs/querying/)。
## 数据源的分工
| 数据源 | 用途 |
|---|---|
| VictoriaMetrics | Prometheus 兼容指标查询,例如内存、CPU、采集健康 |
| Alertmanager | 现有告警通知状态与静默管理;Prometheus 实现,UID 为 `alertmanager` |
| VictoriaLogs | LogsQL 日志查询 |
| VictoriaTraces | Jaeger 兼容追踪查询;应用需要先接入追踪,不能仅凭数据源存在认为所有服务都有 trace |
数据源名称来自 `platform/observability/grafana/values.yaml`。
## Telegram 告警接入
2026-09-25 已通过 [homelab-infra PR #147](https://git.ddupan.top/panxiao81/homelab-infra/pulls/147)
合并并由 Flux 同步,替换原有全部 blackhole 的通知策略。配置来源为
[VMAlertmanager](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/c06c6f78572106586b9b55069dae654a35f4f6bf/platform/observability/metrics/vmalertmanager.yaml)
及同目录的 `alertmanager-external-secret.yaml`、`kustomization.yaml`。
已现场确认 Flux Ready、ExternalSecret SecretSynced、Alertmanager Pod Ready、
配置加载成功。通过 Alertmanager API 注入的临时测试告警已触发 Telegram 发送,
发送失败计数为 0,维护者已确认收到测试告警;测试在 60 秒后自动恢复。
恢复通知按 5 分钟组内间隔发出,发送总计数从 2 增至 3,失败计数仍为 0。
恢复消息的收件端确认未单独取得;总计数也包含一条既有 TooManyScrapeErrors 通知。
本次验证限于通知链路,不刷新整个 Grafana 服务的 `last_verified`。
- 接收频道:<https://t.me/ddupan_alerting>,数字 chat ID 为 `-1003956377923`。
- bot:`@ddupan_alerting_bot`。2026-09-25 通过 Telegram `getChat` / `getChatMember`
确认频道 ID、管理员身份和发布消息权限;bot 直发的测试触发、恢复消息已由维护者确认收到。
- OpenBao:KV v2 mount `kv`、路径 `k8s/alertmanager`、字段 `telegram_bot_token`。
ExternalSecret 使用 `ClusterSecretStore/openbao`,每小时同步到
`monitoring/alertmanager-telegram` Secret 的同名字段。
- VMAlertmanager 挂载 Secret,使用 `bot_token_file` 读取,不在 Git 中保存 token。
- critical 首次分组等待 10 秒,未恢复每小时提醒;warning 等待 1 分钟,
未恢复每 4 小时提醒。分组键为 `alertname, cluster, job, severity`,
组内变更通知间隔 5 分钟;两类均发送恢复通知。info、缺失或其他 severity 暂不推送。
- 采用 Alertmanager 默认 Telegram 消息模板;同容器 CrashLoop 抑制重复重启通知,
具体匹配范围见基础监控运维指南。
配置变更通过既有 Flux 流程发布,先确认 ExternalSecret Ready 和目标 Secret
投射成功,再确认 Alertmanager 加载配置及到 Telegram API 的出站网络。
首次启用可能推送当时已有的 warning/critical 告警;发送测试告警需要维护者同意,
并在频道确认故障与恢复消息均收到。静态检查不能代替这一步。
收不到通知时依次检查 ExternalSecret 状态、Alertmanager 配置加载与发送错误、
bot 的频道发布权限以及手机频道通知设置。轮换 token 后需等待或触发 ESO 同步,
并验证 Alertmanager 使用新 token;必要时重载或重启,不打印 Secret 内容。
## 从告警进入 Grafana
Telegram 新通知的 Source 指向 Grafana `/explore`,使用 VictoriaMetrics 数据源,
携带原始告警表达式,时间范围从该告警触发时刻到现在。首次访问需要登录 Grafana;
原有 Telegram 消息中的旧 Pod 地址不会被追溯修改。
Source 查询指标不依赖 Alertmanager 数据源。
Grafana 同时 provision `Alertmanager` 数据源,通过服务端代理连接
`http://vmalertmanager-main.monitoring.svc:9093`,实现类型为 `prometheus`。
进入 **Alerting**,在支持选择 Alertmanager 的页面切换到 **Alertmanager**,
可查看通知策略、接收端并管理静默。Prometheus 实现的接收端、通知策略和模板为只读,
持久修改仍通过 Git/Flux;告警规则继续优先使用 `PrometheusRule`,由 vmalert 执行。
本数据源未启用转发 Grafana-managed alerts。
配置来源:[homelab-infra PR #152](https://git.ddupan.top/panxiao81/homelab-infra/pulls/152)。
2026-09-25 现场确认 Flux 已应用 `dbf66590acea4a681e2e3bb6965f9a19ece4190e`,
Grafana HelmRelease Ready、两个 Deployment 就绪;68 条规则无评估错误。
实际 Alertmanager 告警的 generatorURL 已指向 Grafana,解码后的表达式与 vmalert 原表达式一致。
Grafana API 已确认 provisioned 数据源,并通过其代理成功读取 `/api/v2/status`、
`/api/v2/alerts` 和 `/api/v2/silences`。现场插件的 Save & test 使用前端代理请求 status;
通用 `/api/datasources/uid/alertmanager/health` 不适用于这个前端插件,会返回 Plugin unavailable。
本轮没有执行浏览器 OIDC 登录与手工创建静默,不将 API 验证写作浏览器端验收。
功能边界见 [Grafana Alertmanager 文档](https://grafana.com/docs/grafana/latest/datasources/alertmanager/)。
## 采集失败的定位与处理
`TooManyScrapeErrors` 使用 vmagent 的采集失败计数判断最近 5 分钟是否出现错误,
持续 15 分钟后触发。告警中的 `instance` 是 vmagent 自己,并非失败目标地址;
先检查 vmagent `/api/v1/targets` 中非 up 目标的 `scrapeUrl` 与 `lastError`。
目标恢复后还要等待 5 分钟回看窗口消退,Telegram 恢复通知另受组内间隔影响。
- k3s 的 kubelet `/metrics` 还包含 apiserver/etcd 指标,实测约 16.1 MiB,
超过 vmagent 默认 16 MiB 限制。`VMNodeScrape/kubelet` 单独设置
`spec.max_scrape_size: "32MiB"`;其他采集任务保留默认值。
再次超限时先统计指标族和响应大小,不直接无限增大全局限制。
- 独立 Docker cAdvisor 尚未部署,旧 `192.168.10.127:8080/metrics` 实际返回 nginx 404,
已从 `VMStaticScrape/docker-hosts` 移除。该配置仍保留已有 :9100 主机目标,
Kubernetes 容器指标继续由 `VMNodeScrape/cadvisor` 的 `/metrics/cadvisor` 提供。
后续需要 Docker 容器指标时,先部署 exporter 并验证端口,再增加采集目标。
配置依据:[homelab-infra PR #148](https://git.ddupan.top/panxiao81/homelab-infra/pulls/148),
2026-09-25 已合并并由 Flux 应用 `a43b7d3c26f9724b9d5b2ad45058f2d1632741af`。
现场确认 kubelet 恢复 up,旧 :8080 目标消失。此次验收期间另发现共享 etcd
`10.60.0.20:2381` 拒绝连接,因此不能将本次两项修复等同于全部采集目标健康或
`TooManyScrapeErrors` 已恢复;后续状态需重新检查 targets,etcd 的操作背景另行对齐。
## 出问题时与维护入口
- 域名打不开:先区分内网 DNS、到 LAN 的路由和浏览器证书错误。
- 登录后无权限:检查 Grafana 的账号/角色授权,Authelia 登录不等于管理员权限。
- 看板空白:检查时间范围、数据源和筛选条件,再区分缺少采集与查询失败。
- 指标与日志不一致:先对齐时间和目标实例,再判断是否为采集范围不同。
部署、采集与恢复入口为 homelab-infra `platform/observability/README.md`;
内存指标解释见 `platform/observability/metrics/exporters/README.md`。
看板配置由 Git/ConfigMap 管理,网页临时调整不作为持久配置的权威来源。
旧 Compose 栈与数据已[清理](victoriametrics-legacy.md),不要再使用旧实例作为排障入口。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#grafana)。
+86
View File
@@ -0,0 +1,86 @@
---
title: Hydra 与 OIDC 上游适配器
lifecycle: experimental
evidence: live-verified
last_reviewed: 2026-09-25
last_verified: 2026-09-25
sources:
- https://git.ddupan.top/panxiao81/iam-login/pulls/2
- https://git.ddupan.top/panxiao81/iam-login/commit/9cf2d235dff0cd33f98012b0a114f14a8f9bfcda
- https://git.ddupan.top/panxiao81/homelab-infra/pulls/142
- https://git.ddupan.top/panxiao81/homelab-infra/pulls/143
- 2026-09-25 部署、discovery、重定向与网络隔离检查
- 维护者于 2026-09-25 确认 Hydra 登录成功返回原 Gitea 账号且仓库权限正常
---
# Hydra 与 OIDC 上游适配器
第一轮人类登录 PoC:Hydra 负责 OIDC 签发,薄的 Login/Consent 服务通过标准 OIDC
验证上游身份。当前配置的上游是 Authelia,它继续连接 Samba AD 并执行人类 MFA。
适配器没有直接连接 LDAP,也不与 Authelia 专有认证协议绑定。
本服务独立于 Ayatori。现役 PoC 代码仍作为 homelab-infra 中的独立 Go module 保存。
下一阶段直接连接 AD 的 Java/Spring 登录服务已建立独立仓库
[iam-login](https://git.ddupan.top/panxiao81/iam-login),已建立 Spring Native 构建验证基础,人类界面方向见
[浏览器登录设计](../architecture/independent-iam-draft.md#人类浏览器登录界面),
尚未替换现役 Go/Authelia 链路。应用代码、测试与 Native 构建发布归新仓库,环境部署归
homelab-infra;首轮实现由 [issue #1](https://git.ddupan.top/panxiao81/iam-login/issues/1) 跟踪。
完整的多主体 IAM 仍是[草案](../architecture/independent-iam-draft.md);
本轮不实现 SPIFFE 登录、agent 专用认证、动态授权或统一组迁移。
## 入口与首次使用
| 入口 | 用途 |
|---|---|
| <https://hydra.ad.ddupan.top> | Hydra 公共 OAuth2/OIDC API |
| <https://hydra-login.ad.ddupan.top> | Login/Consent 适配器,仅处理具体流程路径 |
| <https://git.ddupan.top/user/oauth2/hydra> | 从 Gitea 发起 Hydra 人类登录 |
Hydra 两个域名仅通过 LAN/Tailscale 可达,无公网 tunnel。请从 Gitea 的 `hydra`
登录源进入,在 Authelia 完成既有认证,然后返回 Gitea;旧 `authelia` 登录源保留。
Gitea 继续按原有账号关联、仓库权限与 gitea-admins 组映射执行授权。
```text
Gitea → Hydra → OIDC Login/Consent → Authelia → Samba AD
← OIDC ← 已验证的人类身份 ← OIDC callback
```
## 验证范围
2026-09-25 已现场验证:Hydra 数据库迁移成功、两个 Deployment 就绪、ESO SecretSynced、
TLS discovery 的 issuer/endpoints 正确、Flux hydra Kustomization Ready/Healthy;
HTTP 登录链路可从 Hydra 经适配器到达 Authelia 登录页。
无效 login、callback、consent 请求返回 403。Gitea Pod 能访问公共 discovery,不能
直连 Hydra admin Service;公共 HTTPS 入口的 admin API 返回 404。
Gitea 的新增登录源经 PR #143 接入,Helm revision 19 UpgradeSucceeded、Pod Ready;
登录页同时显示 hydra/authelia,从真实 Gitea 入口到达 Authelia 的整段跳转已验证。
**第一轮人类登录 PoC 已通过验收。** 维护者于 2026-09-25 实际使用 Hydra 登录入口后
确认:“已成功返回原账号,仓库权限正常”。这补齐了人类认证后的回调、原账号关联与
仓库权限验收;依据为维护者实际操作反馈,而非 agent 代为输入人类凭据。
`last_verified` 覆盖上述明确列出的检查及维护者登录反馈,不表示机器或 agent 路径已验证。
## 实现与维护
- Hydra 固定 `v26.2.0` 与镜像 digest,使用独立 hydra PostgreSQL database/role。
- 源码 `apps/hydra/login-consent`:标准 OIDC 上游适配器。校验 ID token issuer、audience、
签名、有效期和 nonce,使用 PKCE S256 与单次、cookie 绑定的 state。
- 当前只允许 Gitea client 和 openid/profile/email/groups;按请求 scope 释放 claims,
不签发 refresh token,不提供通用自动 consent。主体为上游 issuer/sub 的稳定哈希。
- 单副本短期登录事务保存在内存;重启使正在进行的登录失效,用户重新发起即可。
- Hydra admin 无 HTTPRoute,NetworkPolicy 仅允许适配器访问;维护时通过受控本地
kubectl port-forward,不对外开放 admin。
- 秘密保存在 OpenBao `kv/k8s/hydra`,ESO 投射给 Hydra/适配器和 Gitea。禁止重建
system_secret 来处理普通启动问题。
- Authelia 的新 hydra-login client 通过现有 Helm release 的增量 values 更新,保留全部
已有客户端与 two_factor 策略;Authelia 暂未由 Flux 接管。
源码、构建、claims/client 配置和恢复说明见
[Hydra README](https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/apps/hydra/README.md)。
Hydra 部署见 [PR #142](https://git.ddupan.top/panxiao81/homelab-infra/pulls/142),
Gitea 接入见 [PR #143](https://git.ddupan.top/panxiao81/homelab-infra/pulls/143)。
依赖共享 PostgreSQL、OpenBao/ESO、Authelia、Envoy、Samba DNS 与 zot。独立于 Ayatori
不等于已完成共享基础设施之外的灾备;恢复需保留 Hydra 数据库和秘密。
回退时先撤 Gitea 新登录源,沿用旧 Authelia 入口,不删除用户或原有认证配置。
+36 -31
View File
@@ -1,49 +1,50 @@
# 服务总览
审阅日期:2026-09-16。以下覆盖源码工作区 apps/、platform/、infrastructure/ 的一级组件,以及集群入口。
**除旧 VictoriaMetrics Compose 已获授权做有限现场检查外,其余条目未在本轮现场验证。**
审阅日期:2026-09-18。以下覆盖源码工作区 apps/、platform/、infrastructure/ 的一级组件,以及集群入口。
**除旧 VictoriaMetrics Compose 已获授权检查并清理外,其余条目未在本轮现场验证。**
状态栏区分维护者说明、文档、ticket、配置与现场证据,不提供持续的实时健康判断。
SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护者说明更新,
独立项目按指定 README 收录。其余条目仍为初轮工作区盘点,查询前先向维护者对齐。
来源路径相对于 [homelab-infra](https://git.ddupan.top/panxiao81/homelab-infra);包含未提交内容,见首页证据边界。
入口按来源记录列出,访问范围和可达性仍需验证。缺口详情见[待核实清单](../verification.md)。
入口按已有来源记录列出,未记录的内容保持未知,不自动生成现场核实任务。
本轮状态对齐已[完成](../verification.md);后续写作见[文档完善清单](../documentation-backlog.md)。
## 应用
| 组件 | 用途 | 记录入口 | 状态依据 | 来源 | 文档缺口 / 下一步 |
|---|---|---|---|---|---|
| [hydra](hydra.md) | OIDC 签发与通用上游适配器,人类登录 PoC | `hydra.ad.ddupan.top / hydra-login.ad.ddupan.top` | experimental;9 月 25 日基础设施验证及维护者真实人类登录验收通过 | `apps/hydra/`、PR #142/#143 | 第一轮人类 PoC 完成;机器与 agent 接入另行推进 |
| [authelia](authelia.md) | 唯一主 OIDC broker、统一登录 | `auth.ddupan.top` | active;维护者于 2026-09-16 明确已在工作 | 维护者说明、`apps/authelia/` | 同步源码 README 中过时的 OIDC 阶段说明 |
| [blocky](lan-dns.md) | LAN 主 DNS、广告过滤、分流 | `192.168.10.127:53` | 维护者说明已作为 DHCP 主 DNS,上游为路由器 | 维护者 2026-09-16 说明、`apps/blocky/README.md` | 无需逐台确认主机;旧源码说明待同步 |
| codex-proxy | 代理服务,具体接口待确认 | `待核实` | 仅发现配置 | `apps/codex-proxy/docker-compose.yml` | 缺 README 与使用说明 |
| gitea | 代码托管与 Actions | `git.ddupan.top` | 记录已部署 | `apps/gitea/README.md` | 补首次使用与 runner 选择 |
| [gitea](gitea.md) | 代码托管与 Actions | `git.ddupan.top` | 记录已部署 | `apps/gitea/README.md` | 已有登录、最小 CI 与 runner 选择指南 |
| http-echo | Flux 部署与漂移修复 canary | `集群内` | 记录已验证 | `apps/http-echo/README.md` | 已有验证步骤 |
| litellm-gateway | 模型 API 网关,实际消费者待确认 | `待核实` | 仅发现配置 | `apps/litellm-gateway/docker-compose.yml` | 缺 README 与接入说明 |
| marker | GPU 文档转换 API | `集群内端口 8001` | 配置与部署指南;上线待核实 | `apps/marker/README.md` | 缺 API 使用例子 |
| [litellm-gateway](litellm-gateway.md) | 模型 API 网关,实际消费者未记录 | `宿主 TCP 4000;地址未记录` | 仅发现配置 | `apps/litellm-gateway/docker-compose.yml` | 已有参数、请求示例与依赖说明 |
| [marker](marker.md) | GPU 文档转换 API | `集群内端口 8001` | 配置与部署指南;未附上线记录 | `apps/marker/README.md` | 已有转换示例;部署镜像仍为占位符 |
| netboot | PXE 与系统安装 | `192.168.10.127` | 有部署及使用记录 | `apps/netboot/README.md` | 已有客户端启动说明 |
| netbox | 网络资产与地址管理评估 | `netbox.ad.ddupan.top` | 记录已部署;评估用途 | `apps/netbox/README.md` | 补面向浏览者的使用路径 |
| openviking | 上下文检索服务 | `记录端口 1933 / 8020` | 配置与部署指南;上线待核实 | `apps/openviking/README.md` | 缺导入、查询的完整例子 |
| ps3netsrv | PS3 网络内容服务 | `待核实` | Docker 运维文档记录运行 | `apps/ps3netsrv/docker-compose.yml` | 缺客户端使用与挂载说明 |
| seaweedfs | S3 对象存储 | `s3.ad.ddupan.top` | zot 文档记录已使用 | `apps/seaweedfs/README.md` | 补客户端接入、备份与恢复 |
| shared-postgresql | 共享 PostgreSQL / CNPG | `shared-db namespace` | 历史迁移记录已完成 | `apps/shared-postgresql/migration.md` | 缺服务首页、租户接入说明 |
| smtp-relay | 应用经 Microsoft 365 发信 | `smtp-relay.smtp-relay.svc.cluster.local:25` | 有配置与测试指南;上线待核实 | `apps/smtp-relay/README.md` | 核实发信链路与消费者 |
| tailscale | 远程网络与子网路由 | `Tailscale 网络` | 有配置;本轮未读敏感安装脚本 | `apps/tailscale/subnet-routes.sh` | 缺 README、路由与客户端说明 |
| victoriametrics | 旧 Compose 监控栈 | `待核实` | 文档称被平台栈替代;残留待查 | `apps/victoriametrics/compose.yaml` | 明确退役或现存职责 |
| vlmcsd | KMS 兼容服务,使用范围待确认 | `待核实` | 仅发现配置 | `apps/vlmcsd/compose.yaml` | 缺 README 与状态说明 |
| zot | OCI 镜像与制品仓库 | `zot.ad.ddupan.top / zot-push.ad.ddupan.top` | 文档记录 9 月 16 日验收 | `apps/zot/README.md` | 已有拉取示例;长期 CI 发布仍待接入 |
| [netbox](netbox.md) | 网络资产与地址管理评估 | `netbox.ad.ddupan.top` | 记录已部署;评估用途 | `apps/netbox/README.md` | 已有浏览与 Git 修改入口指南 |
| [nexus](nexus.md) | CI 包代理与统一制品仓库 POC | `nexus.ad.ddupan.top` | 2026-09-20 已现场验证 Ansible、Go、OCI 与 BuildKit cache | `apps/nexus/README.md` | 补 publisher account、外部 PostgreSQL 与备份恢复测试 |
| [openviking](openviking.md) | 上下文检索服务 | `记录端口 1933 / 8020` | 配置与部署指南;未附上线记录 | `apps/openviking/README.md` | 已有导入、任务查询、检索与原文读取指南 |
| [ps3netsrv](ps3netsrv.md) | PS3 网络内容服务 | `宿主 TCP 38008;地址未记录` | Docker 运维文档记录运行 | `apps/ps3netsrv/docker-compose.yml` | 已有客户端与内容目录指南 |
| [seaweedfs](seaweedfs.md) | S3 对象存储 | `s3.ad.ddupan.top` | zot 文档记录已使用 | `apps/seaweedfs/README.md` | 已有客户端读写指南与备份边界说明 |
| [shared-postgresql](shared-postgresql.md) | 共享 PostgreSQL / CNPG | `shared-db namespace` | 历史迁移记录已完成 | `apps/shared-postgresql/migration.md` | 已有连接、应用接入与共享资源边界指南 |
| [smtp-relay](smtp-relay.md) | 应用经 Microsoft 365 发信 | `smtp-relay.smtp-relay.svc.cluster.local:25` | 有配置与测试指南;未附上线记录 | `apps/smtp-relay/README.md` | 已有应用参数、测试邮件与投递边界指南 |
| [tailscale](tailscale.md) | 远程网络与子网路由 | `Tailscale 网络` | 有配置;本轮未读敏感安装脚本 | `apps/tailscale/subnet-routes.sh` | 已有远程访问与路由边界指南 |
| [vlmcsd](vlmcsd.md) | KMS 兼容服务,使用范围未记录 | `宿主 TCP 1688;地址未记录` | 仅发现配置 | `apps/vlmcsd/compose.yaml` | 已有协议入口与客户端指南;未查询现场 |
| [zot](zot.md) | OCI 镜像与制品仓库 | `zot.ad.ddupan.top / zot-push.ad.ddupan.top` | 文档记录 9 月 16 日验收 | `apps/zot/README.md` | 已有拉取与发布模板;实际 publisher 授权以项目配置为准 |
## 平台
| 组件 | 用途 | 记录入口 | 状态依据 | 来源 | 文档缺口 / 下一步 |
|---|---|---|---|---|---|
| cert-manager | 签发与续期 TLS 证书 | `ClusterIssuer API` | 记录已接管 Flux | `platform/cert-manager/README.md` | 已有签发和验证说明 |
| envoy-gateway | LAN HTTP 入口与认证集成 | `192.168.10.127:443` | 记录已接管 Flux | `platform/envoy-gateway/README.md` | 已有服务接入说明 |
| external-secrets | OpenBao 到 Kubernetes 的秘密投射 | `Kubernetes API` | Helm 记录已接管;对象范围需区分 | `platform/external-secrets/README.md` | 补新增秘密引用的使用流程 |
| gitea-runner | 可信 Gitea Actions 任务执行 | `Gitea Actions` | 记录已接管 Flux | `platform/gitea-runner/README.md` | 补 workflow label 与使用限制 |
| k3s | 集群 CoreDNS 定制 | `集群内 DNS` | 仅发现 DNS 配置 | `platform/k3s/Corefile.desired` | 缺组件 README |
| [cert-manager](../guides/publish-service.md) | 签发与续期 TLS 证书 | `ClusterIssuer API` | 记录已接管 Flux | `platform/cert-manager/README.md` | 已有新服务证书复用与接入指南 |
| [envoy-gateway](../guides/publish-service.md) | LAN HTTP 入口与认证集成 | `192.168.10.127:443` | 记录已接管 Flux | `platform/envoy-gateway/README.md` | 已有 DNS、路由、认证与发布路径指南 |
| [external-secrets](external-secrets.md) | OpenBao 到 Kubernetes 的秘密投射 | `Kubernetes API` | Helm 记录已接管;对象范围需区分 | `platform/external-secrets/README.md` | 已有字段投射示例与 ownership 边界 |
| gitea-runner | 旧常驻 Gitea Actions runner | 纯 `self-hosted` | 维护者说明准备退役,尚未标为已退役 | `platform/gitea-runner/README.md`、维护者说明 | 新 workflow 改用 [动态 Pod/VM](gitea-dynamic-runner.md) 的明确 labels |
| [k3s DNS](k3s-dns.md) | 集群 CoreDNS 定制 | `集群内 DNS` | 仅发现 DNS 配置 | `platform/k3s/Corefile.desired` | 已有集群 DNS 使用与配置边界说明 |
| [nats](nats.md) | 集群共享消息与 JetStream 队列 | `nats.ad.ddupan.top:4222` | 已部署;维护者说明目前唯一消费者为 Dynamic Runner | 维护者 2026-09-16 说明、`platform/nats/README.md` | runner 消息队列约定以独立项目文档为准 |
| observability | Grafana、指标、日志和追踪 | `grafana.ad.ddupan.top` | 记录已接管 Flux;9 月 16 日变更入口 | `platform/observability/README.md` | 补看板和查询使用指南 |
| openebs | k3s 本地 ZFS 持久卷 | `localpv-zfs-ceph StorageClass` | 记录已接管 Flux | `platform/openebs/README.md` | 已有运维检查;补 PVC 使用边界 |
| [observability / Grafana](grafana.md) | Grafana、指标、日志和追踪 | `grafana.ad.ddupan.top` | 记录已接管 Flux;9 月 16 日变更入口 | `platform/observability/README.md` | 已有看板、指标与日志查询指南 |
| [openebs](openebs.md) | k3s 本地 ZFS 持久卷 | `localpv-zfs-ceph StorageClass` | 记录已接管 Flux | `platform/openebs/README.md` | 已有 PVC 示例、绑定与数据回收边界 |
| [spire](spire.md) | 跨基础设施的统一机器身份入口 | `Workload API / spire-oidc.ad.ddupan.top` | #34 记录基础设施与最小 OpenBao PoC 已完成;后续集成进行中 | [#34](https://git.ddupan.top/panxiao81/homelab-infra/issues/34)、[RUNBOOK](https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/platform/spire/RUNBOOK.md) | 已有接入指南;动态任务以 ticket 为准 |
## 基础设施
@@ -52,14 +53,14 @@ SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护
|---|---|---|---|---|---|
| cloudflared | 公网 Tunnel 与 DNS | `Cloudflare 边缘配置` | 有现有资源接管记录 | `infrastructure/cloudflared/terraform/README.md` | 明确配置权威位置与服务发布流程 |
| [dns](lan-dns.md) | 跨视图 DNS 声明 | `records.yml` | LAN 角色已按维护者说明对齐;声明接管范围未重查 | `infrastructure/dns/README.md`、维护者说明 | 同步旧描述;补新增记录流程 |
| docker | 宿主 Docker 网络管理 | `laptop` | 记录已迁移地址池 | `infrastructure/docker/README.md` | 已有 DN42 与挂载路径约束 |
| docker | 宿主 Docker 网络管理 | `laptop` | 记录已迁移地址池 | [架构约束](../architecture/constraints.md) 与 IaC | Docker bridge 使用 `172.28.0.0/16`,避免 DN42 |
| kata-lab | Kata VM 试验环境 | `历史 VMID 147` | 记录 9 月 14 日已销毁 | `infrastructure/kata-lab/README.md` | 保留验证历史,勿当现役 VM |
| kata-lxc-lab | LXC 内 Kata worker 试验 | `pve2 / 记录地址 192.168.10.128` | 记录 PoC 验证;非正式生产服务 | `infrastructure/kata-lxc-lab/README.md` | 明确与 microVM runner 的职责 |
| microvm-runner(历史目录名) | 动态 runner 的 homelab 基础设施记录 | 当前项目接口见 [Dynamic Runner](gitea-dynamic-runner.md) | 独立项目已更名并扩展到 Pod/VM,正在积极开发 | `infrastructure/microvm-runner/README.md`、独立项目文档 | 具体启用范围和实现进度以独立项目文档为准 |
| oci | 云主机、网络与站点互联 | `OCI ap-osaka-1` | 有恢复、接管与网络实施记录 | `infrastructure/oci/README.md` | 补跨站点使用入口 |
| openbao | 秘密管理与内部 CA | `bao.ad.ddupan.top` | 有部署与接管记录 | `infrastructure/openbao/README.md` | 补日常使用和恢复入口 |
| proxmox | PVE、虚拟化与主机基础设施 | `PVE 管理入口` | 已有基础设施;README 混有设计设想 | `infrastructure/proxmox/README.md` | 分离当前环境与 workload identity 设想 |
| samba-ad | AD 身份、域 DNS 与域成员管理 | `dc1 / 192.168.10.5` | 有部署记录;维护者说明 DNS 部分已完成 | `infrastructure/samba-ad/README.md`、[LAN DNS](lan-dns.md) | 补入域和日常管理入口 |
| [oci](oci.md) | 云主机、网络与站点互联 | `OCI ap-osaka-1` | 有恢复、接管与网络实施记录 | `infrastructure/oci/README.md` | 已有登录、站点网络与维护入口 |
| [openbao](openbao.md) | 秘密管理与内部 CA | `bao.ad.ddupan.top` | 有部署与接管记录 | `infrastructure/openbao/README.md` | 已有登录、取密与运维入口指南 |
| [proxmox](proxmox.md) | PVE、虚拟化与主机基础设施 | `PVE 管理入口` | 已有基础设施 | `infrastructure/proxmox/ansible/` 与 `README-ha.md` | 已有管理入口;sandbox LB/根盘恢复流程见服务页;身份与 runner 设计见独立项目 |
| [samba-ad](samba-ad.md) | AD 身份、域 DNS 与域成员管理 | `dc1 / 192.168.10.5` | 有部署记录;维护者说明 DNS 部分已完成 | `infrastructure/samba-ad/README.md`、[LAN DNS](lan-dns.md) | 已有入域、目录浏览与日常管理入口 |
## 集群
@@ -69,9 +70,13 @@ SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护
## 计划、归档与范围外
- codex-proxy:维护者于 2026-09-16 表述为“应该是退役的”,按退役方向归档;源码目录仍保留,未确认现场清理情况,不再作为新接入对象。
- [旧 VictoriaMetrics Compose](victoriametrics-legacy.md):旧配置和三个数据卷已于 2026-09-16 按维护者要求删除;现役监控在 platform/observability。
- [e5renew、research-auto](external-consumers.md):GitHub 上的外部消费者,不属于 homelab 基础设施;仅保留归属入口。
- [Gitea Dynamic Runner](gitea-dynamic-runner.md):正在积极开发的动态 Pod/VM runner,原名 gitea-microvm-runner;具体启用范围、调度和队列约定以项目文档为准。
- [PostgreSQL Tenant Operator](postgresql-tenant-operator.md):计划中的 DBaaS 中间层,管理共享实例中的数据库与账号;README 记录为 API 骨架阶段,不代表服务已上线。
- [PostgreSQL Tenant Operator](postgresql-tenant-operator.md):计划中的 DBaaS 中间层,管理共享实例中的数据库与账号;现转入 Ayatori Database,采用独立 Database 资源与 Tenant 申请;设计修订不代表服务上线。
- [workload-sts](../architecture/workload-sts-history.md):已归档的早期机器身份方案;停止开发、不部署 PoC,由 SPIFFE/SPIRE 替代。
- Backstage:规划中的服务目录与文档入口;本轮未发现独立部署目录。
- Keycloak、Casdoor:`archive/` 下有明确退役记录,替代入口为 Authelia。
@@ -79,4 +84,4 @@ SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护
- `docs/superpowers/`:已退役工作流,记录已完成的 CNPG/ZFS 迁移。
- `docs/cicd.md`、`docs/homelab-gitops-redesign.md`:部分实施设计,不代表所有阶段都上线。
- `docs/gitea-upgrade-plan.md`:包含已完成升级记录,现状以服务 README 和现场为准。
- 仓库外服务与独立源码仓库见[盘点盲区](../verification.md#盘点盲区)。
- 仓库外服务与独立源码仓库见[已确认的归属与范围](../verification.md#已确认的归属与范围)。
+66
View File
@@ -0,0 +1,66 @@
---
title: k3s 集群 DNS 使用说明
lifecycle: unknown
evidence: configuration
last_reviewed: 2026-09-16
last_verified: null
---
# k3s 集群 DNS
本页说明 Pod 的 DNS 使用路径,依据 homelab-infra `platform/k3s/Corefile.desired` 与
`coredns-custom.yaml`。这些文件是配置意图与历史故障处理记录,未现场确认是否与运行配置完全一致。
LAN 主机通过 DHCP 使用 Blocky/路由器的现状见 [LAN DNS](lan-dns.md),不能据此推导所有 Pod 的转发链。
## 应用如何使用
Pod 通常通过 Kubernetes DNS 解析 Service。跨 namespace 使用完整地址,例如
`shared-postgresql-rw.shared-db.svc.cluster.local`;同 namespace 的短名称按 Pod DNS 搜索域处理。
这类集群内部名称不是远程客户端的公共入口。
集群内访问 Authelia 或 Gitea 时继续使用 `auth.ddupan.top`、`git.ddupan.top` 的原有 URL,
避免把 OIDC issuer、证书名称或 Git remote 改成 IP 来绕过解析问题。
受权排障时,可在已有且具备 `nslookup` 的应用容器中执行以下只读查询:
```bash
nslookup kubernetes.default.svc.cluster.local.
nslookup dc1.ad.ddupan.top.
nslookup auth.ddupan.top.
nslookup git.ddupan.top.
```
末尾的点表示绝对域名,用于减少搜索域扩展对诊断的干扰。
四个查询分别覆盖集群 Service、AD 域和两个分流入口;本轮没有执行,也没有为此创建调试 Pod。
DNS 成功只证明解析路径,不证明应用认证和业务请求成功。
## 文件中声明的分流
| 名称范围 | 配置意图 |
|---|---|
| `cluster.local` 与集群反向记录 | CoreDNS Kubernetes 插件处理 |
| `ad.ddupan.top` | 直接转发 Samba AD DNS `192.168.10.5` |
| `auth.ddupan.top`、`git.ddupan.top` | A 记录返回 Envoy LAN 地址 `192.168.10.127`;AAAA 返回无数据 |
| `lab.ddupan.top`、`tail7e769.ts.net` | 本地返回 NXDOMAIN,阻止历史搜索域排列请求继续转发 |
| 其余请求 | 默认 Corefile 转发至 `/etc/resolv.conf` |
最后一项的实际上游由运行环境的 resolver 文件决定。本轮没有读取现场文件,
不能将源码注释中的历史路由器上游描述当成今天所有节点的 resolver 配置。
对被本地拒绝的后缀新增用途前,应审查这一历史规则,而不是直接在外部 DNS 增加记录后假定 Pod 能解析。
## 缓存和修改入口
`Corefile.desired` 的默认 server block 配置 `cache 30` 与 `serve_stale 1h immediate`,
允许在该规则覆盖范围内暂用过期缓存条目;其他独立 server block 不自动继承这条缓存规则。
因此修改 DNS 记录后,缓存结果可能与权威记录暂时不同。
语义见 [CoreDNS cache](https://coredns.io/plugins/cache/)。
`coredns-custom.yaml` 声明 `kube-system/coredns-custom`,由 Corefile 的 custom import 使用。
`Corefile.desired` 的文件名本身不证明它已由 Flux 管理或已经应用。
变更前先确认该对象的管理入口,再审查影响范围;不要整份替换 CoreDNS 配置来修一个域名。
故障定位先区分集群 Service 解析、AD 转发、固定分流、默认上游和客户端搜索域。
依赖包括 CoreDNS、Kubernetes API、网络、Samba AD DNS 及默认上游;
Authelia/Gitea 的业务可达性还依赖 Envoy 和各自后端。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#k3s-dns)。
+16 -2
View File
@@ -45,16 +45,30 @@ Samba AD → 保留域 DNS 职责,相关配置已完成
主机通过 DHCP 自动获取 DNS 配置:主 DNS 为 Blocky,副 DNS 为路由器。
当前知识库以此作为 LAN 客户端配置口径,无需另行进行主机覆盖盘点。
## NEC IX DHCP 地址池
2026-09-14 将主 LAN 动态池从 `192.168.10.10–250` 收窄为
`192.168.10.128–250`,并为 Buffalo AP(`d4:2c:46:09:07:b0`)固定分配
`192.168.10.10`。`.251–.254` 保留,尚未分配;不能因为扫描无响应就将其用于新设备。
DHCP 下发网关 `192.168.10.1`、主 DNS `192.168.10.127`、备用 DNS
`192.168.10.1`,租期为 4 小时。
地址池修改会清空 NEC IX 当前租约表,但终端可能继续使用旧地址直到续租。
变更后 Kata LXC 实验节点已续租为 `.128`;迁移其他动态客户端前应先检查活动任务,
并在续租后分别验证主机网络和其内部 k3s 等服务。地址池及预留段的声明同时维护在
`apps/netbox/terraform/topology.yml`。
回滚时不能直接恢复整份路由器配置;应先确认 `.10–.127` 没有静态占用,再在 DHCP
profile 中恢复原范围并移除 AP 固定绑定,保存后重新核对租约、DNS 和 NetBox 声明。
## 维护入口与待补充范围
以下路径相对于 homelab-infra,保留部署与操作细节的原有归属:
- `apps/blocky/README.md`:Blocky 部署、分流和检查方法。
- `infrastructure/samba-ad/README.md`:域 DNS 与 Samba 配置。
- `infrastructure/samba-ad/router-dhcp-nec-ix.md`:路由器 DHCP 记录。
- `infrastructure/samba-ad/router-dns-nec-ix.md`:路由器 DNS 记录。
- `infrastructure/dns/README.md`、`records.yml`:跨视图 DNS 声明与所有权。
本次只更新知识库;原工作区中“Blocky 未成为正式 resolver”的旧描述尚待同步。
路由器自身的更上游和 AD/DN42 条件转发明细未在本次补充,也不因此自动产生核查任务。
需要进一步查询时,先向维护者确认当前工作和范围,不因旧文档差异直接发起现场检查。
+70
View File
@@ -0,0 +1,70 @@
---
title: LiteLLM 网关使用指南
lifecycle: unknown
evidence: configuration
last_reviewed: 2026-09-16
last_verified: null
---
# LiteLLM gateway
为客户端提供模型 API 代理。维护者于 2026-09-16 表示没有需要补充的动态改动或退役事项;
本页依据 `apps/litellm-gateway/docker-compose.yml` 与 `config.yaml` 整理,不代表已验证运行状态。
## 接入参数
Compose 映射宿主 TCP `4000` 到网关 `4000`,没有在这些文件中记录统一访问域名。
先由维护者提供实际 base URL、客户端认证要求及可用模型;不能把宿主端口自动当成公网入口。
网关客户端的认证与网关访问上游模型的认证是两层配置,不能把服务端认证文件交给消费者。
配置中的模型别名包括 `chatgpt/gpt-5.4` 和 `hf/google/embeddinggemma-300m` 等,
分别面向聊天和 embedding;这里只表示路由声明,不保证上游账号有权限或模型当下可用。
完整别名以 `config.yaml` 为准。不要因名字含有 codex,就把这个网关与已退役的 codex-proxy 混为一体。
## 第一次聊天请求
在已获授权的客户端环境中,将 `LITELLM_BASE_URL` 设置为维护者提供的 API 根地址,
`LITELLM_MODEL` 设置为获准使用的聊天模型别名。
如果该入口要求 Bearer key,通过既有秘密注入方式提供 `LITELLM_API_KEY`;是否需要 key 以实际接入约定为准。
下面使用 Python 标准库,token 不放在命令行中;请求会调用上游模型并消耗对应配额。
```python
import json
import os
import urllib.request
base = os.environ["LITELLM_BASE_URL"].rstrip("/")
headers = {"Content-Type": "application/json"}
key = os.environ.get("LITELLM_API_KEY")
if key:
headers["Authorization"] = "Bearer " + key
payload = {
"model": os.environ["LITELLM_MODEL"],
"messages": [{"role": "user", "content": "Reply with OK."}],
}
request = urllib.request.Request(
base + "/chat/completions",
data=json.dumps(payload).encode(),
headers=headers,
method="POST",
)
with urllib.request.urlopen(request, timeout=60) as response:
result = json.load(response)
print(result["choices"][0]["message"]["content"])
```
预期收到模型回复。接口结构参考 [LiteLLM 客户端文档](https://docs.litellm.ai/docs/proxy/user_keys),
本轮没有执行请求。该示例面向聊天模型,不能直接拿 embedding 模型替换。
## 依赖与排障
这套 Compose 包含独立的 PostgreSQL 16 和 Prometheus,数据库卷为 `postgres_data`,
指标卷为 `prometheus_data`;这里的数据库不是[集群共享 PostgreSQL](shared-postgresql.md)。
Compose 还挂载配置文件及宿主 `auth.json`,后者属于上游认证材料,不进入 wiki、日志或 AI 上下文。
镜像配置使用 `dev` 标签,接入行为需与实际部署版本相符,不能仅凭最新上游文档认定功能已启用。
连接失败先核对宿主与端口;401/403 需区分网关认证和上游认证;模型错误先核对别名及上游权限;
超时或限额错误再检查上游响应。不要通过打印认证文件或完整带鉴权请求排障。
部署来源为 homelab-infra `apps/litellm-gateway/`;消费者清单与备份情况未在所读文件中记录。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#litellm-gateway)。
+65
View File
@@ -0,0 +1,65 @@
---
title: Marker 文档转换指南
lifecycle: unknown
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# Marker
Marker 用 GPU 将 PDF 转为 Markdown 等格式。本页依据 homelab-infra `apps/marker/README.md`、
Dockerfile 与 Kubernetes manifests,以及下列上游 API 源码整理,未查询运行环境。
源码 Deployment 仍使用 `<your-registry>/marker:latest` 占位符,不能据此认定服务已经上线。
## 使用前提与入口
先由维护者完成镜像构建、部署与可达性确认,再使用集群内入口
`http://marker.default.svc.cluster.local:8001`。所读配置没有记录外部域名或客户端认证流程。
普通应用无需重新执行 README 中的部署步骤。
镜像未固定 `marker-pdf` 版本,示例必须与实际部署的 `/docs` 接口说明核对。
上游当前 `marker_server` 默认绑定 `127.0.0.1`,而本地配置只传 `--port`;
如果所构建版本也如此,维护者需设置 `--host 0.0.0.0` 才能供 Service 访问。
这是部署前检查点,本轮未修改 manifest 或判定现场故障。
## 转换一个 PDF
在能访问该 Service 的客户端,准备一份适合测试的 `sample.pdf`,设置 `MARKER_BASE_URL`
为已确认的入口。上传会处理文件并占用 GPU,先以单个小文件串行验证:
```bash
curl --fail --silent --show-error \
-F '[email protected];type=application/pdf' \
-F 'output_format=markdown' \
"${MARKER_BASE_URL:?请设置已确认的入口}/marker/upload" \
-o marker-result.json
```
检查转换是否成功,再将 Markdown 保存到本地:
```python
import json
from pathlib import Path
result = json.loads(Path("marker-result.json").read_text())
if result.get("success") is not True:
raise SystemExit("转换失败,请检查返回的 error 字段")
Path("sample.md").write_text(result["output"])
```
接口和返回结构依据 [Marker server 源码](https://github.com/datalab-to/marker/blob/master/marker/scripts/server.py)。
HTTP 成功不等于转换成功,需要检查 `success`。返回还可能包含图片数据;仅写出 `output`
不会将图片自动保存为独立附件。需要完整图文时应按实际版本返回的图片字段另行保存并核对引用。
## 资源与文档边界
本地 README 的目标是适配 4 GB 显存,保持单副本、单 worker,并避免并发转换。
显存不足时先缩小测试文件或处理范围,不直接增加副本或并发。
Pod 没有业务 PVC,消费者应保存转换结果,不能将容器临时目录当文档库。
转换结果需要复核表格、代码、顺序及遗漏,再写入知识库;转换工具不确认文档事实或当前服务状态。
连接失败检查部署入口与监听地址,转换失败检查文件、模型加载及 GPU 资源。
依赖为 Kubernetes、GPU 设备支持、模型与临时磁盘;部署维护入口为 `apps/marker/README.md`。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#marker)。
+8 -1
View File
@@ -2,7 +2,7 @@
title: NATS
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_reviewed: 2026-09-25
last_verified: null
sources:
- 维护者于 2026-09-16 提供的部署与消费者说明
@@ -40,3 +40,10 @@ Dynamic Runner 的 stream、subject、durable 名称、worker 配置和具体启
知识库只保留[Dynamic Runner 的用途与职责边界](gitea-dynamic-runner.md)。
涉及 runner 的实际配置和实现进度时,先按项目文档接续工作;需要扩大查询范围时再向维护者确认。
## 指标与告警
2026-09-25 已现场确认既有 :7777 prom-exporter 经 PodMonitor → VMPodScrape 接入中央采集,
job 为 `nats/nats`,target up 且 nats_* 指标有当前样本。已有采集不可用/整个 job 消失告警;
JetStream 容量、consumer 积压等业务规则仍待第二批。
转换器故障处理与验证依据见 [基础监控运维](../guides/monitoring-foundation.md#nats-转换故障经验)。
+59
View File
@@ -0,0 +1,59 @@
---
title: NetBox 使用指南
lifecycle: experimental
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# NetBox
NetBox 用于浏览网络设备、接口与 IP 地址关系,目前是已部署的评估环境。
权威拓扑保存在 homelab-infra 的 `apps/netbox/terraform/topology.yml`,NetBox 是它的派生镜像。
已有配置生成试验,不代表真实网络已由 NetBox 自动驱动。
本页依据工作区 `apps/netbox/README.md` 及相关设计记录整理;本轮没有登录或查询现场。
## 打开与登录
在能访问 LAN 的环境打开 [NetBox](https://netbox.ad.ddupan.top),通过 Authelia 登录并完成二次认证。
源码记录入口访问限制为 AD 的 `netbox-admins` 组;有 AD 账号本身并不足以获得访问权限。
这里使用网关的 Authelia **forward-auth**,NetBox 接收经网关认证的用户与组信息。
NetBox 没有独立的 OIDC client;不要因 Authelia 是主 OIDC broker 就替它配置另一套 OIDC 登录。
正常使用从域名入口进入,不能绕过网关或自行构造 Remote-User 等身份头。
## 第一次浏览设备与地址
1. 在 Devices 列表中搜索要了解的设备,打开详情,查看角色、主要地址与 Interfaces。
2. 从接口查看关联的 IP 地址;有连接记录时,再沿关联对象查看另一端。
3. 在 IPAM 的 Prefixes 中搜索目标网段,例如源拓扑记录中的 `192.168.10.0/24`。
4. 查看该前缀下的地址记录,再打开地址详情,确认其关联接口和设备。
这条路径用于回答“这个地址记录给谁、接口属于哪台设备”等问题。
NetBox 中的地址状态来自资产记录,不会自动证明主机在线、地址当前无占用或 DHCP 已下发。
排查实时故障仍需相应运行证据;AI 查询现场前须按本库规则先与维护者对齐范围。
对象概念可参考 [NetBox IPAM 文档](https://netbox.readthedocs.io/en/stable/features/ipam/)。
## 发现记录需要修改时
先在 Git 中修改 `apps/netbox/terraform/topology.yml`,由维护者按该目录 README
审查 Terraform plan 并同步镜像;不要把 UI 编辑作为持久修改入口。
镜像中的手工改动可能与下次同步冲突;从拓扑文件移除对象也可能在 plan 中产生删除,需审查影响。
资产记录不保存 Wi-Fi 密码等秘密,凭据由 [OpenBao](openbao.md) 等既有秘密管理流程提供。
面向 VyOS OSPF 与 Samba AD DNS 的生成脚本属于评估成果,运行生成器与实际应用网络配置是不同步骤;
看到 NetBox 记录更新,不能宣称路由、DNS 或 DHCP 已同步。
## 遇到问题先看哪里
- 无法访问域名:检查 LAN DNS、路由及共享 Envoy 入口。
- 登录后被拒绝:核对 Authelia 访问规则及 AD 组;不要通过直接访问后端绕过认证。
- 记录缺失或不一致:对照 Git 拓扑和上一次同步记录,区分来源缺失与镜像尚未同步。
- 数据库或应用异常:转到部署 README,检查对应依赖和恢复流程。
部署、依赖、认证边界、拓扑同步与配置生成细节见 homelab-infra `apps/netbox/README.md`。
应用使用数据库与 Redis,登录链路依赖 LAN DNS、Envoy、Authelia 和 Samba AD。
本地管理员属于故障恢复入口,日常浏览不使用该路径。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#netbox)。
+120
View File
@@ -0,0 +1,120 @@
---
title: Nexus Repository POC
lifecycle: experimental
evidence: live-verified
last_reviewed: 2026-09-20
last_verified: 2026-09-20
sources: []
---
# Nexus Repository POC
Nexus Repository Community Edition POC 为一次性 CI runner 提供共享的 Ansible Galaxy、
Go Modules、OCI 与 BuildKit 缓存,减少每个 job 从公网重新下载依赖的时间。GitOps 已部署,
上述代理与缓存链路均已完成现场验证;数据库和备份仍是 POC,现役 zot 保持不变。
## 从哪里使用
- 入口:`https://nexus.ad.ddupan.top`,仅 LAN。
- 人类管理:当前使用本地管理员,凭据受管于 OpenBao `kv/infra/nexus`;尚未配置 LDAP。
后续正式化优先使用 Samba AD LDAP。Community
Edition 不提供原生 OIDC/SAML,因此不能把 Authelia OIDC 写成已支持入口。
- CI 读取:`ansible-public`、Ansible 返回制品 URL 使用的成员 proxy 与 `go-public` 已开放
LAN 匿名只读;`oci-public` 与其 `oci-proxy` 成员同样匿名只读,`oci-hosted` 不开放匿名。
Terraform 明确收窄权限,未使用默认的全仓库匿名角色。
- CI 发布:目标是少量按信任边界划分的本地 service account,凭据由 OpenBao 保存;
当前 POC 尚未创建 publisher 或授予写权限。
不能在整个入口套用 Authelia browser forward-auth:`ansible-galaxy`、Go 和 OCI 客户端
不会完成浏览器登录。若以后给 UI 单独加 RUT/forward-auth,必须使用与 package API 分离
且不可绕过的入口,并先完成 Header 信任边界审计。
## 第一次使用
部署与 Terraform 初始化完成后,Ansible 客户端将 Galaxy server 指向:
```ini
[galaxy]
server_list = nexus
[galaxy_server.nexus]
url = https://nexus.ad.ddupan.top/repository/ansible-public/
```
然后在已有 `collections/requirements.yml` 的项目中运行:
```bash
ansible-galaxy collection install -r collections/requirements.yml \
-p .ansible/collections
```
2026-09-20 使用两个全新客户端目录下载 `community.general:11.2.0`:冷缓存 8.49 秒、
热缓存 1.89 秒,两份 tarball SHA-256 一致。Nexus Ansible format 返回的制品 URL 指向
成员 proxy,因此匿名角色必须同时具备 group 与该 proxy 的只读权限。
Go POC 使用:
```bash
GOPROXY=https://nexus.ad.ddupan.top/repository/go-public/ go mod download
```
私有 module 的 `GOPRIVATE`、认证和 fallback 需由实际 workflow 明确配置,不能把内部 module
路径意外发送到公共 proxy。
2026-09-20 使用两个全新 Go module cache 下载 `golang.org/x/[email protected]`:冷缓存
2.92 秒、热缓存 1.51 秒,均通过 `go-public` 匿名入口完成。
OCI 使用 path-based routing。公共镜像从
`nexus.ad.ddupan.top/oci-public/<namespace>/<image>:<tag>` 匿名拉取;写入使用
`nexus.ad.ddupan.top/oci-hosted/<namespace>/<image>:<tag>` 并要求认证。2026-09-20 验证:
- Alpine 代理冷拉 4.75 秒、热拉 0.80 秒,digest 一致;
- hosted push/pull 成功,匿名 pull 返回 401;
- amd64/arm64 OCI image index 可 push 与 inspect;
- Helm OCI chart push/pull digest 及本地 tarball SHA-256 一致;
- Cosign 签名和公钥验证成功,OCI 1.1 referrers 返回一个 Sigstore bundle;
- BuildKit `mode=max` registry cache 成功导出;销毁首个 builder 后,新 builder 从 Nexus
导入缓存,两个 `RUN` step 均命中 `CACHED`。
## POC 限制
- 单副本、50 GiB OpenEBS RWO PVC,资源上限 2 CPU / 4 GiB。
- 当前使用 embedded H2,仅用于 POC;正式保存唯一制品前迁移至外部 PostgreSQL。
- 当前没有独立备份或恢复验收,PVC 不能被视为备份。
- Terraform provider 管理 Ansible/Go、Realm 与权限;provider 1.17.0 尚未暴露 Nexus 3.94
新增的原生 OCI repository resource,因此 OCI 仓库由实例 Swagger 固定 schema 的幂等 REST
调和器管理,不通过 UI 留下非声明式配置。
- 尚未创建正式 publisher service account;本轮写入测试临时使用受管管理员凭据。
## 出问题时
先检查 Flux、Pod、PVC、Route 与最近日志:
```bash
kubectl -n flux-system get kustomization nexus
kubectl -n nexus get pod,pvc,service,httproute
kubectl -n nexus logs deployment/nexus --tail=100
```
首次启动可能持续数分钟。PVC 未 Bound 时先查 OpenEBS;Route 未 Accepted/ResolvedRefs 时查
Gateway parentRef 与 Service;公网依赖获取失败时区分 Nexus 本身、LAN DNS 和已知不稳定
WAN,不以重建 PVC 作为排障手段。
## 运维入口
实现入口为 homelab-infra 已合并的 `apps/nexus/` 与
`clusters/homelab/apps/nexus.yaml`。DNS 记录位于 `infrastructure/dns/records.yml`。
源码 README 维护部署、初始化、Terraform、验收与恢复边界。
部署依赖 Envoy Gateway、OpenEBS 和 LAN DNS;Terraform 管理依赖 Nexus 初始化后的受限管理
账号及 OpenBao 注入凭据。现阶段不依赖共享 PostgreSQL,正式化时才建立独立数据库与 role。
## 当前状态与证据
2026-09-20 现场确认 Flux Kustomization Ready、Nexus Pod Ready、50 GiB PVC Bound,HTTPRoute
经 HTTPS 状态 API 返回 200;Samba DNS apply 后复查 `changed=0`。Terraform 已创建 Ansible、
Go proxy/group、OCI Bearer Token Realm 和最小匿名只读角色,二次 plan 为 `No changes`;OCI
REST 调和器复查三个仓库均为 `in sync`。Ansible、Go、OCI、Helm、Cosign/referrers 与
BuildKit cache 的上述客户端测试均成功。实现来源为 homelab-infra PR #103、#108 与 #109。
尚未验证备份恢复或外部 PostgreSQL,也未创建正式 publisher account、修改或迁移 zot,
因此本页的 `live-verified` 仅覆盖已明确列出的 POC 范围。
+71
View File
@@ -0,0 +1,71 @@
---
title: OCI 登录与维护入口
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# OCI 云上基础设施
OCI 部分由独立 Terraform root 管理云 API 资源,实例内的软件与网络配置由 Ansible 管理。
本页仅提取 homelab-infra 工作区 `infrastructure/oci/README.md` 与 `ansible/README.md`
中已有的使用路径,不查询云资源、SSH、WireGuard 或 BGP 状态。
已核对 Terraform 的 OCI backend、provider profile 与两台实例的 `prevent_destroy` 声明。
README 有工作区修改,Ansible/Terraform 目录包含尚未提交内容;正式版本来源仍需补全。
维护者于 2026-09-16 明确:本组件优先 IaC,以代码为准。Ansible/Terraform 的声明及任务
是配置依据,README 负责解释;代码存在不等于本轮已验证部署结果。
## 第一次登录
源码记录大阪区域 `ap-osaka-1`,提供两个 DNS 登录入口:
```bash
ssh [email protected]
ssh [email protected]
```
选择自己获准访问的实例,用既有 SSH agent/key 登录;不复制私钥或禁用 host-key 校验。
以上名称对应直连公网 A 记录,不能当成 Cloudflare HTTP 代理入口。
实际权限、主机密钥与登录成功情况本轮未验证;首次使用从维护者取得可信主机信息。
DNS 记录的声明源为 `infrastructure/dns/records.yml`。
源 README 记录 DNS 尚未纳入 OCI Terraform state,公网 IP 变更时需协调更新记录,
不能认为修改实例就自动完成 DNS 同步。
## 访问家中网络与 DN42
站点网络细节统一查阅 `infrastructure/oci/ansible/README.md`,其中包含 VyOS、OCI AMD、
WireGuard、BGP 和 DN42 的地址、过滤与检查步骤。本页不维护第二份邻居或路由实时清单。
使用已有网络的应用无需自行创建 WireGuard peer 或修改 BGP。
遇到私网不可达,先区分 DNS、目标服务、路由、隧道与过滤;隧道握手成功不代表业务前缀已安装。
内部家中/OCI 业务前缀不得通告给外部 DN42 邻居,不能为临时接通扩大所有前缀的 export 规则。
Docker 地址池还须避开 DN42 `172.20.0.0/14`,相关记录见 `infrastructure/docker/README.md`。
## 管理变更走哪个入口
| 修改内容 | 原有管理入口 |
|---|---|
| 实例、VCN、NSG、云路由等 API 对象 | `infrastructure/oci/terraform/` |
| 主机/路由器软件、隧道及 BGP 配置 | `infrastructure/oci/ansible/` |
| DNS 名称 | `infrastructure/dns/records.yml` 与所属 DNS 后端 |
Terraform 使用 OCI Object Storage 的既有远端 state,认证依赖本机 OCI profile。
新 checkout 按源 README 准备受限 metadata 输入后才能 plan,不能复制 wiki 中不存在的“通用 tfvars”。
恢复目录的 state 副本不作为日常 backend,也不能上传覆盖远端对象。
维护者审查 plan 或 Ansible check/diff 后再实施对应变更;plan/state/metadata 可能包含秘密,不进 Git 或公开文档。
保留实例 `prevent_destroy`,遇到替换计划先查原因,不能为了让 apply 通过直接移除保护。
所读 README 的历史配额与免费机型检查不是持续费用保证,新增资源时另行核对。
## 恢复与依赖
实例登录依赖 DNS、公网路径、SSH 授权与主机;站点访问另依赖家中路由器、云端网络规则和路由协议。
云 API 状态正常与客户机内部服务正常是不同层面的证据。
恢复设计和接管历史见 `infrastructure/oci/README.md`,网络维护及私钥边界见 `ansible/README.md`。
不把旧 state 恢复步骤、迁移收尾 playbook 或历史验证命令当作每次登录前要执行的初始化。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#oci)。
+88
View File
@@ -0,0 +1,88 @@
---
title: OpenBao 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# OpenBao
OpenBao 提供秘密管理与内部 CA,部署在 Kubernetes 之外的独立主机上。
日常使用是以自己的身份登录,按已有 policy 读取秘密或申请短期凭据。
本页依据 homelab-infra 工作区 `infrastructure/openbao/README.md` 整理,
CLI 语法参考下列官方文档。本轮未登录服务、读取秘密或验证现场。
## 人的登录入口
前提是客户端能解析并访问内部域名,已安装 `bao` CLI,且账号具备相应 OIDC 授权。
```bash
export BAO_ADDR=https://bao.ad.ddupan.top:8200
bao login -method=oidc -no-print
```
按提示通过浏览器进入 Authelia,完成登录和二次认证。
使用域名进行 TLS 校验,不用 IP 地址代替,也不关闭证书校验。
`-no-print` 避免显示 token,但成功登录后仍会把它存入本机 token helper,供后续命令使用。
因此应在自己的受控会话中登录。参见 [OpenBao login](https://openbao.org/docs/commands/login/)。
登录成功后,只查看当前会话的权限与有效期:
```bash
bao token lookup -field=policies
bao token lookup -field=ttl
```
这两个命令不打印完整 token;字段选项见
[token lookup](https://openbao.org/docs/commands/token/lookup/)。能登录不代表能读取任意秘密。
## 按授权路径读取一个字段
先由服务所有者提供准确的 mount、秘密路径和字段名。
下例 `YOUR_AUTHORIZED_PATH` 是占位符,须替换为 `kv` mount 下已授权且存在的路径;
`password` 也应替换为实际字段名。命令仅适合已获相应权限的会话。
```bash
set +x
APP_PASSWORD="$(bao kv get -mount=kv -field=password YOUR_AUTHORIZED_PATH)"
# 在当前会话中交给实际消费者;不要 echo,也不要放入命令行参数或日志。
unset APP_PASSWORD
```
示例只演示接收字段后清除变量,不会配置任何应用;接入脚本还应检查命令失败并停止后续操作。
`kv get` 会处理 KV 引擎的 API 路径,CLI 的相对路径无需自行插入 `data/`。
参见 [OpenBao kv get](https://openbao.org/docs/commands/kv/get/)。
Kubernetes 应用通常消费 ESO 投射的 Secret。修改秘密应通过其受管来源及对应服务的轮换流程,
不能只编辑 ESO 生成的副本。不要把完整秘密内容粘贴到 AI 上下文、issue 或 wiki。
## 机器身份的使用边界
| 调用者 | 本库已记录的认证路径 |
|---|---|
| 人 | Authelia OIDC 登录 |
| laptop 本地 AI agent | 独立客户端证书,cert auth role 为 `local-agent` |
| SPIFFE workload | 按 [SPIRE 接入说明](spire.md) 与对应 OpenBao role 配置换取 token |
源码记录的本地 agent 证书与私钥由 Ansible 安装在 `/etc/homelab-agent/openbao/`,
不要复制到仓库或 workflow。其 token TTL 为 15 分钟、最长 1 小时;权限包括受限的 SSH 签名、
自身证书续期及 `kv/agents/local/*`,明确不包含 `kv/k8s/*`。
证书注册、登录与续期按源码 README 操作,不能从 SPIFFE 的整体设计推断该路径已迁移。
SPIFFE 验证机器身份,OpenBao 自己签发 token 并维护 policy。
Dynamic Runner 提供执行环境和 workload 身份,具体向 OpenBao 请求什么 token 由 workflow 决定。
## 权限申请与故障入口
申请权限时提供调用者身份、准确路径、所需动作、有效期及用途,由维护者调整受管 role/policy。
遇到拒绝访问先核对上述信息及会话有效期,不用管理员 token 代替应用身份。
连接失败时先区分内部 DNS、网络、TLS 与认证问题;OIDC 回调问题需结合客户端浏览器所在位置排查。
部署、PKI、SSH 签名、本地 agent 身份和恢复细节见 homelab-infra
`infrastructure/openbao/README.md`。服务依赖主机持久存储及 Raft 数据,人的登录还依赖 Authelia。
根密钥与恢复身份不应依赖 Kubernetes 或只能由 OpenBao 自身解密的秘密;
日常登录成功不等于已完成备份或灾难恢复验收。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#openbao)。
+78
View File
@@ -0,0 +1,78 @@
---
title: OpenEBS PVC 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# OpenEBS 本地持久存储
应用通过 PVC 申请持久存储。homelab 使用的 StorageClass 为 `localpv-zfs-ceph`,
provisioner 为 `zfs.csi.openebs.io`,底层来自宿主 `data/ceph` ZFS pool/dataset。
名称中的 `ceph` 不代表它提供 Ceph 分布式存储能力。
本页依据 homelab-infra `platform/openebs/README.md` 与 `storageclasses.yaml` 整理,
未查询 PVC、宿主存储或现场容量。源码 README 的历史消费者列表包含已退役项目,
当前服务归属以[服务总览](index.md)为准,不照抄为现役卷清单。
## 为应用声明 PVC
先确定容量、namespace、备份需求及应用调度约束。
以下在应用已有 namespace 中申请 1 GiB,容量和名称需按实际用途替换:
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: your-app-data
namespace: your-app
spec:
accessModes:
- ReadWriteOnce
storageClassName: localpv-zfs-ceph
resources:
requests:
storage: 1Gi
```
在应用 Pod spec 中引用该 PVC,容器再用 `volumeMounts` 挂载:
```yaml
volumes:
- name: data
persistentVolumeClaim:
claimName: your-app-data
```
```yaml
volumeMounts:
- name: data
mountPath: /var/lib/your-app
```
后两段分别是 Pod 与容器配置片段,不是独立 Kubernetes 对象。
应用与 PVC 必须位于同一 namespace;挂载路径及文件权限以应用要求为准。
把声明纳入应用既有的 GitOps/部署入口,本轮未创建或挂载 PVC。
## 等待绑定与节点约束
StorageClass 配置 `WaitForFirstConsumer`,PVC 在没有可调度消费者时保持 Pending 不一定是故障。
检查时结合消费 Pod 的调度事件、StorageClass、节点与存储池容量,不能通过删除重建业务 PVC 试错。
此为节点本地存储,数据可用性依赖对应宿主;应用不能假设跨节点重调度后自动获得同一份数据。
绑定与回收语义参见 [Kubernetes StorageClass 文档](https://kubernetes.io/docs/concepts/storage/storage-classes/)。
## 扩容、删除与恢复
配置允许卷扩容,但扩容需要按 CSI、文件系统和应用要求确认结果;不要将其理解为支持任意缩容。
默认 `reclaimPolicy: Delete`:删除 PVC 可能触发其 PV 与底层数据删除,
实际处理还应检查该 PV 自身的回收策略。应用退役前需明确数据保留或删除决定。
本地持久卷不是独立备份,也不自动提供多副本高可用。
为数据库等应用选择备份和恢复方式时,需考虑应用一致性及宿主故障,而不只看 PVC 是否 Bound。
运维与 break-glass 入口为 `platform/openebs/README.md`。
StorageClass 独立于 Helm release 管理;不要通过卸载 chart、删除 CRD 或业务卷验证升级。
依赖包括 OpenEBS ZFS CSI、宿主 ZFS、文件系统与 Kubernetes 调度。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#openebs)。
+102
View File
@@ -0,0 +1,102 @@
---
title: OpenViking 导入与查询指南
lifecycle: unknown
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# OpenViking
OpenViking 为文档和 agent 上下文提供导入与检索能力。
本页依据 homelab-infra `apps/openviking/README.md`、Compose 和上游接口文档整理,未访问实例。
仓库提供部署方案,未据此断言服务已上线或 wiki 已自动同步到索引。
## 入口与数据位置
| 用途 | Compose 默认值 |
|---|---|
| HTTP API | 宿主端口 `1933` |
| Console/UI | 宿主端口 `8020` |
| embedding endpoint | 宿主回环地址 `127.0.0.1:8081` |
| 持久数据与配置 | `./data` |
| embedding 模型缓存 | `./models` |
这些端口可被环境配置覆盖,实际宿主地址、客户端 key 与权限由维护者提供。
服务端 VLM 使用 `openai-codex` provider,本地 embedding 服务使用 llama.cpp CUDA 镜像;
客户端 API key 与服务端模型认证不是同一份凭据,不将服务端 OAuth 数据交给检索客户端。
当前镜像标签为 `latest`,接口需与实际部署版本核对。
## 导入、等待、查询与读取
先设置 `OPENVIKING_BASE_URL` 为已授权的 API 根地址;入口需要 key 时,通过既有秘密注入方式
提供 `OPENVIKING_API_KEY`。以下 Python 标准库片段共用同一会话;只处理一份公开上游 README,
会写入索引并触发模型处理。本轮没有执行导入或请求。
```python
import json
import os
import urllib.parse
import urllib.request
base = os.environ["OPENVIKING_BASE_URL"].rstrip("/")
headers = {"Content-Type": "application/json"}
if os.environ.get("OPENVIKING_API_KEY"):
headers["X-API-Key"] = os.environ["OPENVIKING_API_KEY"]
def request(path, payload=None):
data = None if payload is None else json.dumps(payload).encode()
req = urllib.request.Request(base + path, data=data, headers=headers)
with urllib.request.urlopen(req, timeout=120) as response:
return json.load(response)
result = request("/api/v1/resources", {
"path": "https://raw.githubusercontent.com/volcengine/OpenViking/refs/heads/main/README.md"
})
print(json.dumps(result, ensure_ascii=False, indent=2))
```
从返回数据取得 `task_id` 与资源 URI。`accepted` 只表示已接收,随后用同一会话查询任务:
```python
task_id = "REPLACE_WITH_RETURNED_TASK_ID"
print(request("/api/v1/tasks/" + urllib.parse.quote(task_id, safe="")))
```
任务到达 `completed` 后再搜索;`failed` 或 `cancelled` 应先处理原因,不能当作入库成功。
避免因请求超时直接反复导入同一来源。参见上游
[资源 API](https://github.com/volcengine/OpenViking/blob/main/docs/en/api/02-resources.md) 和
[任务 API](https://github.com/volcengine/OpenViking/blob/main/docs/zh/api/17-tasks.md)。
```python
print(request("/api/v1/search/find", {
"query": "What is OpenViking?", "limit": 5
}))
```
从搜索结果中选择一个文件 URI,读取正文:
```python
uri = "REPLACE_WITH_RETURNED_FILE_URI"
query = urllib.parse.urlencode({"uri": uri})
print(request("/api/v1/content/read?" + query))
```
检索和读取方式见[上游检索文档](https://github.com/volcengine/OpenViking/blob/main/docs/en/api/06-retrieval.md)。
返回目录时先查看其概览或子项再选文件,不把任意目录 URI 当正文文件使用。
HTTP 成功之外,还要检查各次响应中的应用状态与错误信息;响应封装以部署版本为准。
## 人与 AI 如何使用检索结果
检索结果用于定位资料,最终结论回到原始 Markdown、源码 README 或 ticket 核对日期与证据。
本 wiki 的 Git 仓库仍是正式文档来源;索引不是自动获得权威性的另一份状态记录。
尚未建立本库自动导入、增量更新或删除同步的已验证流程,不能把旧索引结果当作当前事实。
导入前明确资料范围及模型处理边界。不要将凭据、Terraform state 或含秘密的整个工作目录批量导入。
本地 embedding 不意味着所有语义处理都在本地完成,VLM 仍使用 README 所述的上游认证路径。
连接失败核对宿主端口;导入失败区分来源可达性与解析;任务卡住或结果缺失再查看 VLM、embedding
与队列处理。数据在 `./data`,模型缓存可重新下载,两者不能按同一种可丢弃缓存处理。
部署、模型初始化与认证维护回到 `apps/openviking/README.md`。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#openviking)。
+136 -10
View File
@@ -2,7 +2,7 @@
title: PostgreSQL Tenant Operator(计划中的 DBaaS)
lifecycle: planned
evidence: documented
last_reviewed: 2026-09-16
last_reviewed: 2026-09-25
last_verified: null
sources:
- https://git.ddupan.top/panxiao81/postgresql-tenant-operator
@@ -21,20 +21,124 @@ homelab 资源有限,为每个应用维护一套数据库会浪费资源。绝
计划自行实现这个中间层,让下游通过统一接口申请可消费的数据库,降低共享实例的管理成本。
这段现状和设计动机由维护者于 2026-09-16 提供;本轮没有查询数据库或集群。
现有实例的日常接入见[共享 PostgreSQL 使用指南](shared-postgresql.md)。
现有实例的源码入口为 homelab-infra 的 `apps/shared-postgresql/`。
## 当前进度
2026-09-16 查阅[项目 README](https://git.ddupan.top/panxiao81/postgresql-tenant-operator/src/branch/main/README.md)
与架构文档时,项目记录为 **API 骨架阶段,尚未对 PostgreSQL 或 OpenBao 执行写操作**。
已批准的设计合同不等于已经实现的功能,本文不表示 DBaaS 已上线。
项目首页还注明 `config/samples` 保留旧 API 骨架,不能将其直接当作最终使用接口。
维护者于 2026-09-20 提供的阶段状态如下:
- 已合并 Instance 的 Endpoint、凭据引用、身份/版本、定义与观测目标等值对象;
- 已合并扩展支持能力模型,以及 Instance 最小生命周期与状态 checkpoint;
- CI PR #14 已合并:lint/test 使用 Pod runner,e2e 使用 VM runner;当前没有开放 PR;
- 上述领域基础尚未接入实际运行链路,不能理解为新设计已经可用;
- 仍缺完整 Ready 判定、Kubernetes Secret 管理凭据与连接刷新、应用层/数据库 adapter/controller
接入、CRD 与批准规格对齐及集成验证;
- Tenant 的完整创建、凭据交付和 Retain/Delete 生命周期仍未完成;
- 旧运行链路仍包含直接读取 OpenBao 管理凭据的逻辑。
本地暂停在 `feature/instance-extension-observations`,有两个未提交文件,实现 Instance 接收扩展
观测及其测试。该部分此前只通过领域包 lint,未运行本地测试、未提交、未推送;分支仍基于 #13,
未包含刚合并的 CI 改动。该工作区必须原样保留,不能作为已合并能力或迁移来源。
已批准的设计合同不等于已经实现的功能,本文不表示 DBaaS 已上线。生成的 CRD/API 与 samples
仍可能落后于批准规格,不能直接作为最终使用接口。
2026-09-20,维护者决定将该项目合并为 Ayatori 的 Database 领域模块。已批准的规格、领域模型、
状态机和测试继续作为迁移合同;不会把独立仓库的 manager、生成文件和当前工作树整仓复制。
首个迁移基线使用包含已合并 Instance 领域基础与 CI #14 的最新 main commit,再按领域层、API、
adapter 和 controller 的纵向切片进入 Ayatori;暂停中的两个未提交文件不进入首个切片。旧仓库
在迁移完成并验收前仍是现有设计与代码的来源,本决定不表示 DBaaS 已上线。
维护者同时确认目前没有可用版本,也没有 PostgreSQL 实例或 Tenant 被该 operator 托管。因此
合并不承担旧运行链路、旧 CRD/status 或数据的兼容责任:直接读取 OpenBao 管理凭据的旧路径可以
删除,未投入使用且落后于规范的 CRD/samples/实现结构不保留兼容层。
2026-09-20 的迁移决定原要求整体沿用源设计。2026-09-24,维护者明确批准下述资源/申请
分离修订,替代 registry、自动所有权恢复与原 Retain 合同;管理凭据、TLS、OpenBao/ESO 和
其他适用安全边界继续保留。这是显式设计修订,不是已完成运行验证。
原 `database.ddupan.top/v1alpha1` API group 也不保留。Ayatori 中的目标 API 使用
`database.ayatori.ddupan.top/v1alpha1`,并纳入统一的 `api/database/v1alpha1` 与 Database 模块
结构;由于不存在已部署消费者,不建立 alias 或 conversion 入口。
合并边界记录在 Ayatori PR
[#3 的 ADR-0008](https://git.ddupan.top/panxiao81/ayatori/src/commit/33fb3ec9725dca8a10f2ad4bcd71cf83413932ee/docs/decisions/0008-merge-postgresql-tenant-operator.md);
该决定已于 2026-09-21 合并 main,链接固定到合并版本;设计合并不表示 Database 实现已完成。
## 当前资源模型(2026-09-24 已确认)
参考 [Kubernetes 官方 PV/PVC](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) 的
资源/申请分离:Instance 是资源来源与管理入口;独立 Database 类似 PV;Tenant 是类似 PVC
的用户申请。Instance 一对多 Database,每个 Database 同时最多绑定一个 Tenant。
Database 自带 instanceRef,手工登记不依赖 Tenant;动态申请由 Tenant 选择 Instance,
引用已有 Database 时从资源获取 Instance,不重复声明另一份来源。
Retain 在申请删除后保留 Database 对象和外部数据,进入 Released,等待管理员处理数据、
旧访问权限和凭据后显式授权重新绑定。已有数据库可由管理员显式登记导入,初始验证不改密、
不改 owner;发现未知同名资源仍报 Conflict。回收策略位于资源侧,Database 不随 Tenant GC。
撤销 PostgreSQL ownership registry 和任意 status 丢失自动重建所有权的要求。CR 记录持久
身份、绑定和进度;普通失败幂等重试,无法确认外部创建结果时报告足够人工诊断的冲突。
不引入 CSI 协议、存储调度或通用 Claim。绑定字段和凭据重新交付协议仍需细化。
2026-09-25,维护者确认第一版 Database 的生命周期边界包含一个数据库、一个兼任 owner
的登录账号及其应用凭据;Tenant 负责申请与交付。不预留多账号字段或新增 Role/Credential
CRD;一库多账号若有实际需求,再通过后续 API 版本演进。此决定不扩大导入管理授权。
同日确认 Instance 与 Database 为 cluster-scoped,Tenant 为 namespaced。Database 由平台
管理员管理,不属于应用 namespace,也不需要资源专用 namespace。Tenant 按名称引用
Database,资源侧绑定记录包含 Tenant namespace/name/UID;普通申请者不能自行修改回收
策略或将 Released 资源重新开放。具体字段与 RBAC 规则仍待细化。
绑定采用资源侧先写:动态 Database 名称由 Tenant UID 确定;先写 Database 的 Tenant
namespace/name/UID,再写 Tenant status 的 Database name/UID,双向一致后才供应或交付。
API 版本冲突重新读取判断,已被其他 Tenant 占用则报冲突;资源侧成功、申请侧失败由
reconcile 核对身份后补齐,不回滚资源侧绑定。绑定不等于 Ready;外部数据库创建结果
不确定仍交给人工处理,不增加事务队列或 registry。该顺序由维护者于同日确认。
同日进一步明确:不增加允许绑定名单或逐 Tenant 审批,有权创建 Tenant 的申请者可显式
申请未绑定且可用的 Database;Released 仍需管理员处理旧访问后重新开放。
回收策略默认 Retain,资源管理者可在删除流程开始前修改;进入删除流程后固定,指定
Delete 即为删除授权,不加第二次审批。动态凭据路径按 Database UID 确定,导入显式关联
已有凭据位置;Released 不自动改密,重新开放前由管理员处理旧访问。
对应 Ayatori `docs/database/specification.md`、`domain-model.md` 与 `api-reference.md`
已推送为 [7e9e8e8](https://git.ddupan.top/panxiao81/ayatori/commit/7e9e8e828bfcbdc8d4e2fcb6bc3d13727712a82c),
已随 [Ayatori PR #10](https://git.ddupan.top/panxiao81/ayatori/pulls/10) 通过三项 CI 并合并 main,
合并版本为 [55b269c](https://git.ddupan.top/panxiao81/ayatori/commit/55b269ce2eb40f6b44c1afe838389093efdac98e)。
Ayatori main 已加入三资源 Go 类型、生成 CRD、Scheme 注册与 YAML 示例,尚未部署为业务服务。
`make test` 使用真实 API server 验证作用域、默认值、声明
校验、status 隔离、绑定写入版本冲突与示例。绑定 controller 已接入 manager:动态资源按
Tenant UID 命名,先写资源侧绑定,再回读补齐 Tenant status;进入 Binding 后固定申请目标,
拒绝 Released、旧 UID 和陈旧 Ready 观察。真实 API server 覆盖部分写入故障后新 reconciler
补齐、双 Tenant 竞争及实际 manager 在生成 RBAC 角色下的 watch;绑定角色不能读取 Secret。
Bound 仍为 Ready=False,尚无供应或凭据投射。已有 finalizer 保护,但删除清理未实现:
Tenant 删除保持 DeletionPending,资源和申请的 finalizer 不自动移除,不能视为可用的
Retain/Delete 生命周期或部署为业务 DBaaS。具体字段和未完成边界见
源码 [API 合同](https://git.ddupan.top/panxiao81/ayatori/src/commit/7e9e8e828bfcbdc8d4e2fcb6bc3d13727712a82c/docs/database/api-reference.md)
的“当前 API 切片”。
绑定代码按维护者要求分层:领域层负责纯规则,application service 协调绑定步骤和回读,
Kubernetes adapter 负责 CR 映射、版本保护及 Conditions/status/finalizer 呈现,controller
只连接事件、用例与重试。service 和领域层不依赖 Kubernetes 类型,不新增通用事务或
Repository 框架;该重构不扩展上述运行能力。对应源码 `docs/database/domain-model.md`
已随上述提交保存,见 [领域模型](https://git.ddupan.top/panxiao81/ayatori/src/commit/7e9e8e828bfcbdc8d4e2fcb6bc3d13727712a82c/docs/database/domain-model.md)。
本轮依据为维护者设计讨论和 Ayatori 已推送的
[ADR-0009](https://git.ddupan.top/panxiao81/ayatori/src/commit/6db8a495fb9f8981d336c9e6288253628ab478b6/docs/decisions/0009-database-resource-and-claim.md)、
[系统规格](https://git.ddupan.top/panxiao81/ayatori/src/commit/6db8a495fb9f8981d336c9e6288253628ab478b6/docs/database/specification.md)。
registry 实现、迁移与 Instance 初始化依赖已在
[23a2d81](https://git.ddupan.top/panxiao81/ayatori/commit/23a2d81b5041f8589baab1c234136cd2c701bb06)
撤除;本地测试与真实 PostgreSQL/API server 集成验证通过,但新三资源链路尚未完成。
上述设计与撤除已随 [PR #9](https://git.ddupan.top/panxiao81/ayatori/pulls/9) 合并 main,
合并版本为 `347a667`;不表示三资源链路已实现或部署。见 [同步记录](../verification.md#ayatori-database-设计修订同步)。
## 计划中的使用方式
1. 平台管理员通过 `PostgreSQLInstance` 注册已有 PostgreSQL 实例及管理连接。
2. 下游以 namespaced `PostgreSQLTenant` 声明所需 database、login owner 和扩展。
3. controller 校验所有权与冲突,幂等创建凭据、role、database 和授权等资源。
2. 下游以 namespaced `PostgreSQLTenant` 申请数据库,或显式引用管理员登记的 Database。
3. controller 建立独立 Database 记录与排他绑定,供应或验证资源;未知同名及不确定创建报冲突。
4. 应用凭据以 OpenBao KV 为事实来源,由 ESO 投射为 Kubernetes Secret。
非 Kubernetes 消费者使用提供的 OpenBao API URL,并通过自身授权获取凭据。
5. ESO 投射成功且应用凭据实际登录成功后,Tenant 才能进入 Ready。
@@ -44,9 +148,30 @@ GitOps、Terraform、kubectl 和未来 Backstage 计划共用这套 Kubernetes A
## 职责边界
2026-09-25 维护者确认第一版 PostgreSQL 管理账号使用原生非 superuser 方案,具有
CREATEDB/CREATEROLE,不引入 SECURITY DEFINER 接口。扩展安装按实际权限逐请求验证,
可用列表不等于任意扩展均可安装;基础管理能力不授予导入或接管他人资源的权限。
这项决定沿用原安全文档的非 superuser 原则,并明确了此前未选定的实施方式。
Instance 观测、Secret watch 与删除引用保护已在 CI 通过后,经维护者批准合并
[PR #11](https://git.ddupan.top/panxiao81/ayatori/pulls/11),main 合并提交为
[f4deb98](https://git.ddupan.top/panxiao81/ayatori/commit/f4deb98a7fcf61fb97ce52bbf190beb816d0141a)。
权限矩阵、启用方式和测试边界以该提交的
[模块说明](https://git.ddupan.top/panxiao81/ayatori/src/commit/f4deb98a7fcf61fb97ce52bbf190beb816d0141a/docs/database/README.md)
与安全文档为准;合并不表示部署或完整供应链路已完成。
后续应用凭据存储切片已签名提交为
[f6bb9e4](https://git.ddupan.top/panxiao81/ayatori/commit/f6bb9e4599afca49a9cdc3d40789e11d118db9c5),
由 [PR #12](https://git.ddupan.top/panxiao81/ayatori/pulls/12) 跟踪,尚未合并。
复用 OpenBao 官方 Go SDK 的 KV v2 CAS=0、回读七键与版本,禁止覆盖
或自动认领;明确权限拒绝等待依赖恢复,写入结果不确定则停止并人工处理。本地真实
OpenBao 测试已覆盖并发、软删除、固定前缀权限和响应丢失,尚未接入 manager、Kubernetes
auth、Database 供应或 ESO。源码模块文档与 wiki 已关联,见
[同步记录](../verification.md)。
- operator 管理实例内的租户资源,不运行 PostgreSQL/OpenBao,也不管理 VM、存储、备份或 OpenBao PKI。
- 应用密码写入 OpenBao,不进入 CR、Event 或日志;ESO 负责向 Kubernetes 消费者投射。
- 默认删除策略为 `Retain`,删除声明不会默认删除业务数据;显式 `Delete` 需重新校验所有权。
- Database 默认 Retain;删除 Tenant 保留资源对象与数据,Released 不自动重新分配。
- 资源侧 Delete 需明确授权、finalizer 与实际管理范围检查,导入不隐含删除或改密授权。
- 遇到未知 database/role 等资源报告 Conflict,不能自动接管、覆盖或删除;现有数据库迁移需遵循迁移合同。
- namespace 是 Kubernetes 身份与 RBAC 边界;database/role 名称在一个 PostgreSQL Instance 内仍全局唯一。
@@ -62,5 +187,6 @@ GitOps、Terraform、kubectl 和未来 Backstage 计划共用这套 Kubernetes A
- [部署](https://git.ddupan.top/panxiao81/postgresql-tenant-operator/src/branch/main/docs/deployment.md)与[安全](https://git.ddupan.top/panxiao81/postgresql-tenant-operator/src/branch/main/docs/security.md):依赖和权限。
- [迁移](https://git.ddupan.top/panxiao81/postgresql-tenant-operator/src/branch/main/docs/migration.md)与[运维](https://git.ddupan.top/panxiao81/postgresql-tenant-operator/src/branch/main/docs/operations.md):现有数据库、删除和恢复合同。
具体实现进度回到[项目仓库](https://git.ddupan.top/panxiao81/postgresql-tenant-operator)查询,
后续查询前先向维护者对齐当前工作与 ticket。本页保留设计定位和带日期的阶段摘要。
迁移前的具体实现进度仍回到[项目仓库](https://git.ddupan.top/panxiao81/postgresql-tenant-operator)
查询;迁移后的实现与发布进度转到 Ayatori。后续查询前先向维护者对齐当前工作与 ticket。
本页保留设计定位和带日期的阶段摘要。
+133
View File
@@ -0,0 +1,133 @@
---
title: Proxmox 日常管理入口
lifecycle: active
evidence: documented
last_reviewed: 2026-09-25
last_verified: 2026-09-25
---
# Proxmox
Proxmox 承载 VM/LXC 与相应主机、网络和存储资源。
本页依据 homelab-infra 工作区 `infrastructure/proxmox/README.md`、`README-ha.md`
及已有 DNS 名称整理使用入口;初轮未检查集群成员、VM、HA 或存储现场状态。
2026-09-25 的有限现场验证仅覆盖下文 sandbox 存储恢复与 LB 链路,不代表整套 PVE/HA 验收。
源码 README 尚未跟踪,HA 文档有工作区修改;配置已进一步核对 `auth.yml`、`site.yml`、
`ha.yml` 与对应 role defaults,不将文档中的历史阶段备注当作当前配置。
维护者于 2026-09-16 明确:本组件优先 IaC,以代码为准。Ansible/Terraform 的声明及任务
是配置依据,README 负责解释;代码存在不等于本轮已验证部署结果。
## 打开管理界面
DNS 清单记录 `pve1.ad.ddupan.top`、`pve2.ad.ddupan.top`、`pve3.ad.ddupan.top`。
Proxmox 默认 HTTPS 管理端口是 `8006`,因此可按维护者确认的节点尝试:
```text
https://pve1.ad.ddupan.top:8006/
```
这是节点名与上游默认端口组合出的入口示例,未验证可达性或证书配置。
端口与节点代理行为见 [Proxmox pveproxy 文档](https://github.com/proxmox/pve-docs/blob/master/pveproxy.adoc)。
`pve_auth` role 声明 `ad` realm,通过 LDAPS 连接 `dc1.ad.ddupan.top:636`,启用证书校验;
域用户按此配置选择 `ad` realm,实际可用权限取决于账号同步及 ACL。`auth.yml` 独立管理该配置。
`pve_acme` role 使用 OpenBao 内部 CA 为节点域名签证书,浏览器需具有相应 CA 信任。
这些是代码声明,不是新的登录验证;不能因 Authelia 是 Web SSO 主入口就推断 PVE 已接入 OIDC。
## 第一次定位一台虚拟机
1. 登录后在资源树中找到目标 VM/LXC,核对名称、VMID 和所在节点。
2. 查看 Summary 与任务记录,区分 guest 状态、节点状态和最近操作结果。
3. 查看 Hardware/Resources 与网络、磁盘配置,确认对应的业务服务。
4. 需要 guest 内部诊断时,再按授权使用 Console 或该 guest 的 SSH 入口。
VMID 可能被复用,不能仅凭一个旧 VMID 判断当前对象归属。
控制台可打开也不等于客户机网络、存储和业务健康。
启动、关闭、迁移、克隆及删除都是独立变更,不作为“查看状态”的附带动作。
## 持久配置与短命 VM 的职责
源目录使用 Ansible 管理节点软件、内核、网络、LINSTOR/DRBD 与 watchdog 等主机配置。
VM 和集群对象的具体管理工具以对应目录为准,不把迁移到 Terraform 的设想写成全部完成。
UI 中临时改动需回写对应受管来源,避免后续自动化覆盖。
动态 CI VM 的使用接口见 [Gitea Dynamic Runner](gitea-dynamic-runner.md),
其生命周期由 runner controller 负责,不能逐台登记进长期 Terraform state。
每个动态 Pod/VM 应独立取得 SPIFFE 身份;workflow 决定登录与请求 token。
源码 README 的 SDN-backed identity 和 AppRole bootstrap 段落属于早期设计记录,
不作为当前统一身份原则或最新 runner 实现的依据。
## 网络、HA 与存储边界
现有设计记录中的 VLAN/VNet 分段不能直接证明 guest 的机器身份;
IP、MAC、VMID 的自报值不能代替可信身份验证。
修改 bridge、SDN 或路由 guest 时,先明确承载哪些业务与管理路径,不能只看当前登录是否仍连通。
`README-ha.md` 记录了 VyOS guest 的 HA 和 watchdog 工作。它描述的是故障后重新启动的路径,
不应承诺无中断切换,也不能推断其他 guest 全部启用 HA。
`pve_ha` role 的资源默认值只列 `vm:100`,`ha.yml` 独立于节点基线 `site.yml`,
避免基线维护顺带改变 HA/fencing 行为。watchdog 的实际选择还需结合 inventory 覆盖与任务实现;
本轮不从旧 README 的 softdog 标题推断当前现场状态。
PVE 主机存储、DRBD 副本和 k3s 的 [OpenEBS](openebs.md) 是不同管理层,
不能互相替代容量、冗余或恢复验证。快照和副本也不能自动证明具备独立备份。
故障入口依次为目标任务日志、guest、宿主节点、存储和集群网络;
涉及 quorum、fencing 或 watchdog 的处理先读 `README-ha.md`,不要套用普通单机重启排障。
长期配置入口为 `infrastructure/proxmox/ansible/`,并按实际变更选择对应 playbook。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#proxmox)。
## Sandbox LB 与根文件系统恢复
Sandbox 的 VyOS 入口为 PostgreSQL `10.60.0.1:5432`、K3s API
`10.60.0.13:6443`、OpenSandbox `10.60.0.13:8080`。数据库只转发到
sandbox1 `10.60.0.11:5432`;K3s 转发到两个节点的 `6443`;OpenSandbox
转发到两个节点的 `30080`。OpenSandbox `/health` 返回 200 不代表 K3s 控制面可用。
配置依据为源码 `infrastructure/sandbox-cluster/README.md`、
`infrastructure/proxmox/ansible/roles/vyos_router/` 及本轮 VyOS 现场检查;
OpenSandbox 的 LB 条目在现场存在,不能推断旧 Ansible 模板已经管理该条目。
排障先检查 HAProxy 监听和每个 backend 的状态,再直连后端。若后端拒绝连接,
检查 PostgreSQL、K3s 与根文件系统,而不是仅重启 LB。
`findmnt -no SOURCE,FSTYPE,OPTIONS /` 即使显示 `rw`,同时出现
`emergency_ro` 也不能视为正常可写。
DRBD 对端失联导致 quorum 丢失时,`on-no-quorum=io-error` 会向文件系统返回
I/O 错误;ext4 可能中止 journal 并进入只读。DRBD 后来恢复 UpToDate/quorum
并不会自动解除文件系统的故障状态。检查宿主日志时用 `journalctl --utc`,
不要直接把宿主本地时间与 guest 的 UTC 时间比较。
在已获停机恢复授权后,按以下顺序处理:
1. 用 `pct config <VMID>`、`pvesm path <rootfs-volume>` 和 `drbdsetup status <resource> --verbose`
核对容器、卷和副本关系。确认链路稳定、quorum 正常、数据副本 UpToDate,且没有其他节点挂载该卷。
2. 正常关闭故障容器,确认 stopped、卷未挂载且无遗留占用。禁止在运行中的根盘执行 fsck。
3. 执行 `pct fsck <VMID> --device rootfs --force 1`。本机 PVE 使用 `fsck -a -l -f`;
底层返回 1 表示已修复,PVE 仍可能把它显示为命令失败。必须核对完整输出,不能把其他错误码当成功。
4. 对同一已停机、未挂载卷执行 `e2fsck -fn <verified-device>`;返回 0 后再启动容器。
若自动安全修复未通过,暂停并评估数据恢复,不盲目加 `-y`、清空 WAL 或重建数据库。
5. 等待 PostgreSQL 完成 crash recovery;验证主库 `pg_is_in_recovery()=false`、
standby 保持 recovery、`pg_stat_replication` 为 streaming/sync,检查 replay lag。
不把普通 TCP check 当成数据库可写性证明,也不自动提升 standby。
6. 检查两个 K3s 服务、两个直连 API 和 VIP 的 `/readyz`、节点与 Pod Ready。
数据库已恢复而某个 K3s 长期停在 activating 时,核对日志与进程;必要时只重启该 K3s 服务。
7. 从 VyOS 再核对每个 backend 为 UP,并验证 OpenSandbox `/health`。
2026-09-25 现场验证范围:sandbox1 根盘离线修复和只读复检通过,重新挂载不再有
`emergency_ro`;数据库恢复同步复制,采样 replay lag 为 0;两个 API 与 VIP 的
`/readyz` 均为 ok,两个节点及全部 Pod Ready。故障证据为目标 DRBD 对端 PingAck
超时、quorum 丢失及紧随其后的 ext4 写入错误;对端连接超时的上游原因尚未确定。
本轮未修改 VyOS LB、DRBD quorum 策略或集群网络。此处保存恢复方法及有限验证边界,
不代表已经消除存储网络复发风险。
本次进一步复盘将触发线索收敛为:新 PG HDD 数据卷在 17:12 开始的初始同步发生重叠,
随后多个既有 DRBD 资源失去 quorum;15:30–15:32 的 etcd rootfs 迁移与后来的新数据卷创建
应分开记录。资源争用的具体瓶颈尚未实证。容器 `serial: 1` 和 etcd health 不等于 DRBD
同步完成;新卷维护需在创建前建立同步预算,并在允许下一卷前等待所有必要副本同步。
目前 PG 创建流程虽已在创建后加限速,仍存在初始未限速窗口,尚未补齐同步完成屏障。
事故报告由 wiki 统一维护:[2026-09-25 DRBD quorum 抖动与 sandbox 控制面中断](../incidents/2026-09-25-drbd-quorum-sandbox.md)。
其中保存统一 UTC 时间线、跨资源影响边界、相关操作会话和后续验收条件;本页保留可复用恢复方法。
+49
View File
@@ -0,0 +1,49 @@
---
title: ps3netsrv 使用指南
lifecycle: unknown
evidence: configuration
last_reviewed: 2026-09-16
last_verified: null
---
# ps3netsrv
为 PS3 客户端通过网络读取游戏内容提供服务。
维护者于 2026-09-16 表示没有需补充的动态事项;本页依据工作区
`apps/ps3netsrv/docker-compose.yml` 整理。该文件有未提交修改,以此处注明的工作区为来源。
本轮没有查询容器、磁盘内容或客户端状态。
## 入口与内容目录
| 项目 | 配置记录 |
|---|---|
| 镜像 | `shawly/ps3netsrv:latest` |
| TCP 端口 | 宿主 `38008` → 容器 `38008` |
| 宿主内容目录 | `/mnt/pool/games/ps3` |
| 容器内目录 | `/games`,当前映射为读写 |
所读 Compose 没有指定客户端应使用的宿主 IP 或域名,接入时由维护者提供实际地址。
这不是浏览器 HTTP 服务,也不能将路径挂载成功等同于客户端已发现内容。
## 第一次从 PS3 浏览内容
1. 确认目标内容已放入宿主映射目录,且容器配置的用户具有读取权限。
2. 按客户端要求组织子目录,例如 ISO 内容位于 `PS3ISO/`,目录形式内容位于 `GAMES/`。
3. 在 webMAN MOD 的网络内容设置中填入服务器地址和端口 `38008`,启用对应网络内容扫描。
4. 刷新内容列表,选择一个条目挂载并读取,确认整个客户端路径。
目录结构见 [容器项目说明](https://github.com/shawly/docker-ps3netsrv),客户端操作见
[webMAN MOD PS3 NET Server](https://github.com/aldostools/webMAN-MOD/wiki/~-PS3-NET-Server)。
本轮未执行以上步骤;具体客户端版本的菜单名称可能不同。
## 排障与维护边界
- 无法连接:核对实际宿主地址、TCP 端口和客户端到宿主的网络。
- 列表为空:核对宿主目录、子目录结构、文件权限与客户端扫描设置。
- 发现内容但读取失败:核对文件可读性及客户端格式支持,再看服务日志。
Compose 的 `USER_ID` / `GROUP_ID` 控制容器读文件时的身份;调整前核对宿主所有权,
不要为排障递归修改整个存储池的权限。挂载目录属于内容数据,重建容器不会替代数据备份。
依赖为 Docker、宿主存储、网络和相容客户端;本页不修改容器或数据目录。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#ps3netsrv)。
+93
View File
@@ -0,0 +1,93 @@
---
title: Samba AD 日常使用入口
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# Samba Active Directory
Samba AD 提供人的目录身份、Kerberos、LDAP、域 DNS 和组策略;
[Authelia](authelia.md) 在此之上提供 Web 登录,[SPIFFE](spire.md) 负责 workload 身份。
AD 组成员资格与每个服务最终授予的权限仍需分别配置。
本页根据 homelab-infra 工作区 `infrastructure/samba-ad/README.md` 整理。
已核对 Ansible 的域变量、`join-windows.yml`、`join-member.yml` 与 member role 任务。
这些来源含未提交修改;没有查询域成员、用户或现场配置。
DNS 的已确认口径见 [LAN DNS](lan-dns.md),不重新盘点主机。
维护者于 2026-09-16 明确:本组件优先 IaC,以代码为准。Ansible/Terraform 的声明及任务
是配置依据,README 负责解释;代码存在不等于本轮已验证部署结果。
## 域与管理入口
| 项目 | 已有资料中的值 |
|---|---|
| DNS domain | `ad.ddupan.top` |
| Kerberos realm | `AD.DDUPAN.TOP` |
| NetBIOS domain | `DDUPAN` |
| 域控 | `dc1.ad.ddupan.top` / `192.168.10.5` |
| 图形管理 | Windows 管理机上的 RSAT:AD Users & Computers、GPMC、DNS |
管理机地址与登录身份由维护者提供。日常 Web 登录从对应应用进入 Authelia,
无需登录域控,也不向普通应用交付 Domain Administrator 凭据。
## 入域之前与入域路径
入域设备需要准确时间、域控连通性和能找到 AD SRV 记录的 DNS 路径。
不能直接照抄源 README 通用示例中的 `10.10.10.10`、`ad.example.com` 或 `EXAMPLE`。
也不要为入域统一改写所有 LAN 主机 DNS;按该设备的域解析需求配置,保留既有 LAN 设计。
Windows 管理机按 `infrastructure/samba-ad/ansible/` 的 inventory 与 `join-windows.yml`
管理,先核对目标主机、WinRM 与所用账号,再由维护者执行入域流程。
README 的手工命令用于解释角色行为,不是重新建域的日常操作步骤。
Linux 的 `join-member.yml` 面向 Samba member fileserver:它配置 winbind、NSS、SMB 与域解析,
明确不安装 `libpam-winbind`。因此文件服务器入域成功不等于已经启用 Linux 系统域账号登录。
修改前阅读角色对现有 `smb.conf`、共享与 UID/GID 映射的处理,不能将普通客户端套成文件服务器。
## 第一次查看用户与组
在已获管理授权的域控会话中,可使用以下只读命令;`YOUR_GROUP` 替换为目标组:
```bash
sudo samba-tool user list
sudo samba-tool group listmembers YOUR_GROUP
```
也可在 RSAT 的 AD Users & Computers 中查找用户,打开其组成员关系。
命令语义见 [Samba samba-tool 手册](https://www.samba.org/samba/docs/current/man-html/samba-tool.8.html)。
输出含账号信息,按任务范围使用,不把完整人员目录复制进公开 wiki。
本轮没有执行这些命令。
新增用户、组、权限或重置密码会改变目录状态,按现有 Ansible 声明或维护流程实施,
避免 UI 临时改动与下一次配置同步互相覆盖。密码通过受控交互或秘密管理提供,不写进命令示例。
应用权限排障先核对 AD 组,再核对 Authelia 策略与应用内映射。
## 故障与维护边界
入域失败先区分 DNS/SRV、时间、连通性与账号权限;已有成员认证异常再看信任关系及 winbind。
### Laptop 上的 Winbind RPC 子进程堆积
2026-09-14,`laptop` 的 `winbind.service` 下曾堆积 1677 个 `rpcd_lsad`。现场日志同时显示
SAMR/LSARPC pipe 断连,以及 AppArmor `samba-rpcd` profile 拒绝
`/run/samba/ncalrpc/np/samr` 和 `lsarpc` 的写访问。仅重启 winbind 会暂时释放内存,
但拒绝仍会触发新的 worker,因此不应把重启视为根治。
已在 `/etc/apparmor.d/local/samba-rpcd` 精确允许这两个 pipe 的 `rw` 权限,重载 profile
并重启 winbind。修复后 `wbinfo -t` 及域/BUILTIN 名称查询通过,短期复测没有新增拒绝;
该结论只适用于 laptop 的 Samba member,不应套用到 `dc1`。
复发时先采集 `free -h`、`pgrep -xc rpcd_lsad`、winbind cgroup 内存、内核 AppArmor
拒绝和 Samba 日志,再决定是否重启。不要关闭 AppArmor 或放宽整个目录;出现新路径时
应按审计日志逐项分析。此规则仍应纳入 `samba_member` Ansible role,避免主机重建后丢失。
静态 DNS 声明入口为 `infrastructure/dns/records.yml`,只管理明确列出的 RRset,
不清理 Samba 自动维护的域控制器 locator、Kerberos 等记录。
新服务 DNS 接入见[发布新服务](../guides/publish-service.md)。
域备份、第二域控和恢复方案回到源码 README;有备份命令不代表已建立定时异机备份或演练过恢复。
域控身份数据库与应用数据不同,不能通过重跑建域、清空数据库来排查普通登录失败。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#samba-ad)。
+87
View File
@@ -0,0 +1,87 @@
---
title: SeaweedFS S3 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# SeaweedFS 对象存储
SeaweedFS 为应用提供 S3 兼容对象存储,zot Registry 是它的消费者之一。
普通应用使用自己的 bucket 和 S3 身份;容器镜像通过 [zot](zot.md) 发布与拉取。
本页依据 homelab-infra 工作区 `apps/seaweedfs/README.md` 和 `apps/zot/README.md` 整理,
客户端语法参考 AWS CLI 官方文档。本轮未查询现场或读写对象。
## 连接入口与身份
| 场景 | endpoint |
|---|---|
| LAN 客户端的 HTTPS S3 入口 | `https://s3.ad.ddupan.top` |
| Kubernetes 集群内 Service | `http://seaweedfs-s3.seaweedfs.svc.cluster.local:8333` |
首次接入先明确自己的 bucket、需要的 Read/Write/List 等权限及凭据获取方式。
当前所读配置使用静态 S3 AK/SK,由 OpenBao 管理;SeaweedFS OIDC/STS 尚未接入。
zot 前端的 SPIFFE 登录不代表通用 S3 客户端已经能用 SPIFFE 换取 S3 凭据。
应用使用专属身份,不复用 zot 或 Terraform 的存储凭据。
Kubernetes Secret 是 ESO 生成的消费副本,身份或凭据变更应修改受管来源,不能手工改副本。
## 用 AWS CLI 查看自己的对象
前提:已安装 AWS CLI,并由既有授权流程将本应用的凭据注入当前进程环境
(`AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY`),或配置受保护的专用 CLI profile。
不要把实际 AK/SK 复制到命令示例、仓库或日志中。
将下例 bucket 替换为自己的已授权 bucket,先只读列出少量对象:
```bash
aws --endpoint-url https://s3.ad.ddupan.top s3api list-objects-v2 \
--bucket YOUR_APP_BUCKET --max-items 10 --no-cli-pager
```
预期返回对象信息或空 bucket 的结果。只具有指定 bucket 权限的身份,不必拥有列举所有 bucket 的权限;
因此不以全局 `aws s3 ls` 是否成功作为接入的唯一标准。
`--max-items` 控制返回条数,具体行为见
[AWS CLI list-objects-v2](https://docs.aws.amazon.com/cli/latest/reference/s3api/list-objects-v2.html)。
## 上传和下载一个测试文件
仅在自己的测试 bucket/prefix 以及具备写权限时操作。替换占位符,并使用尚未占用的 key:
```bash
aws --endpoint-url https://s3.ad.ddupan.top s3 cp ./hello.txt \
s3://YOUR_APP_BUCKET/YOUR_UNUSED_TEST_KEY
aws --endpoint-url https://s3.ad.ddupan.top s3 cp \
s3://YOUR_APP_BUCKET/YOUR_UNUSED_TEST_KEY ./hello.downloaded.txt
cmp ./hello.txt ./hello.downloaded.txt
```
本地先准备 `hello.txt`。预期上传与下载成功,`cmp` 无输出且退出码为 0。
这会在目标 bucket 留下测试对象,是否清理由该 bucket 的所有者决定。
语法参考 [AWS CLI cp](https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html)。
上游 S3 客户端文档用于解释命令,不代表 SeaweedFS 实现了全部 AWS S3 功能。
## zot 数据与维护边界
zot 专用数据位于 `zot` bucket 的 `registry/` 前缀,由 Registry 管理 OCI layout。
不要把普通文件直接写入该前缀,也不要用 S3 客户端手工删除镜像内部对象。
zot 的 S3 身份只允许相应 bucket 的 Read/Write/List/Tagging,不能访问 `tfstate`。
其凭据唯一来源为 OpenBao `kv/k8s/zot-s3`,由 ESO 同步给 zot 和 SeaweedFS;
基础 S3 身份配置在 `kv/k8s/seaweedfs-s3`,两份配置的合成及轮换见源码 README。
轮换不仅是改一个值,还需协调服务端重新加载和消费者更新,避免两端配置不一致。
## 遇到问题先看哪里
- 域名或连接失败:确认当前使用的是 LAN endpoint 还是仅集群内可达的 Service。
- 访问被拒绝:核对使用的应用身份、bucket/key 与所需动作权限,不直接扩大为管理员权限。
- 签名或凭据错误:核对凭据来源、同步情况和客户端配置;不要打印 AK/SK 排障。
- Registry 不可用:区分 zot 的 SPIFFE 客户端认证与它到 S3 的后端认证。
部署与配置来源:homelab-infra `apps/seaweedfs/README.md`、`apps/zot/README.md`。
单一存储系统内的数据副本不等于独立备份;zot 源文档尚未记录已建立独立异机/离线备份。
其他应用的数据保留与恢复策略应由各自用途明确,不能从“已接入 S3”推断已经完成备份。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#seaweedfs)。
+82
View File
@@ -0,0 +1,82 @@
---
title: 共享 PostgreSQL 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# 共享 PostgreSQL
集群内的多个服务共用一套 PostgreSQL,避免为每个应用维护独立数据库实例造成资源浪费。
共享实例已经在使用;计划中的 [PostgreSQL Tenant Operator](postgresql-tenant-operator.md)
将负责简化 database、role 和凭据的管理,目前不能把该计划当成已上线的自助申请入口。
共享使用的现状来自维护者于 2026-09-16 的说明。连接入口与部署配置来自 homelab-infra
工作区 `apps/shared-postgresql/`;本轮未连接数据库或查询 Kubernetes。
## 连接入口
| 使用场景 | 来源中记录的地址 |
|---|---|
| 集群内现有应用的兼容入口 | `shared-postgresql.shared-db.svc.cluster.local:5432` |
| CNPG 读写入口 | `shared-postgresql-rw.shared-db.svc.cluster.local:5432` |
| Tailscale 暴露所用的 Kubernetes Service | `shared-postgresql-tailscale`,namespace `shared-db` |
兼容 Service 的配置选择 CNPG primary。应用应使用 Service 地址,不固定到某个 Pod IP。
表中的 `.svc.cluster.local` 是集群内 DNS 地址;不能直接当作集群外客户端的可达地址。
Tailscale Service 配置存在不等于已经确认外部地址和访问权限,集群外接入须由维护者提供实际入口。
## 新应用接入前准备什么
向维护者说明应用名称、所需 database/role、扩展、连接数预期、网络来源及凭据消费方式。
由维护者按现有管理流程建立并授权,再提供连接参数和秘密引用;本页不提供尚未上线的 Tenant CR 示例。
应用使用自己的数据库与账号,不复用其他应用或实例管理员的凭据。
已有应用的秘密来源以各自 README 和配置为准,不能假定所有历史凭据已统一迁移到同一种流程。
使用 [OpenBao](openbao.md) 与 ESO 的应用,应消费受管秘密,不能直接修改 ESO 生成的副本。
连接 TLS 的要求及 CA 材料也应作为接入参数交付,不通过关闭校验解决连接问题。
## 第一次连接:确认目标数据库与身份
在已能访问集群内 Service、已安装 `psql` 的受控终端操作。
将下例占位符替换为已分配的 database 和应用 role;密码通过终端提示输入,不写入命令行或 wiki。
连接参数中的 TLS 配置沿用维护者交付的配置。
```bash
psql -X -W -v ON_ERROR_STOP=1 \
-h shared-postgresql-rw.shared-db.svc.cluster.local -p 5432 \
-U YOUR_APP_ROLE -d YOUR_APP_DATABASE \
-c 'SELECT current_database(), current_user, 1 AS connection_ok;'
```
预期返回自己的数据库名、登录角色及 `connection_ok = 1`。
该示例不修改业务数据,也不证明建表、迁移或其他权限已经满足。
`-X` 避免加载本地 psql 启动脚本,`-W` 请求密码提示,`ON_ERROR_STOP` 使命令遇错退出。
语法见 [PostgreSQL psql 文档](https://www.postgresql.org/docs/current/app-psql.html)。
AI 接续任务时先确认操作范围,再执行现场查询;不能因为存在这段示例就自动登录数据库。
## 共享实例的维护边界
- 应用 schema migration 只面向自己的数据库,按应用升级流程执行;需要额外扩展或权限时先交由维护者处理。
- 连接池、慢查询和批量任务会影响共享资源,新增消费者时应说明负载预期。
- 数据库停用、role 删除和数据清理是独立操作,不能因应用 manifest 删除就推断数据库可一并删除。
- 配置文件记录 `instances: 1`,使用 CNPG 本身不代表已经配置数据库多副本高可用。
存储配置为 OpenEBS 的 `localpv-zfs-ceph`。持久卷存在不等于已有独立备份或完成恢复验收,
本页不对当前备份情况作未经验证的结论。
历史迁移文档中的 dump/restore 与回滚步骤属于迁移场景,不能整段重跑作为日常接入流程。
其中出现的旧服务名也不代表这些服务仍在运行。
## 遇到问题先看哪里
- 域名不解析或连接超时:先确认客户端位于何处、使用的入口及网络访问范围。
- 认证失败:核对 role、database 和应用自己的凭据来源;不要改用 `postgres` 绕过问题。
- 登录成功但操作被拒绝:区分数据库连接、schema、表和扩展权限,向维护者提供失败动作,不发送密码。
- 多个消费者同时异常:转到共享数据库和存储的运维入口,避免在各应用中分别覆盖连接配置。
源码入口为 homelab-infra 的 `apps/shared-postgresql/migration.md`、
`cloudnativepg-cluster.yaml` 和 `shared-postgresql-service.yaml`(后两者位于同一目录)。
服务依赖 Kubernetes、CNPG、集群 DNS 与持久存储;Tailscale 入口另依赖对应网络及授权。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#shared-postgresql)。
+76
View File
@@ -0,0 +1,76 @@
---
title: SMTP relay 应用发信指南
lifecycle: unknown
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# SMTP relay
为集群应用提供统一出站邮件入口:应用通过集群内 SMTP 连接 relay,
relay 再使用 STARTTLS 与 XOAUTH2 向 Microsoft 365 提交邮件。
本页依据 homelab-infra `apps/smtp-relay/README.md` 与 Service/Deployment 配置整理,
本轮没有连接 relay、发送邮件或查询邮箱。
## 应用接入参数
| 参数 | 已记录值 |
|---|---|
| SMTP host | `smtp-relay.smtp-relay.svc.cluster.local` |
| SMTP port | `25` |
| 应用到 relay 的 TLS | 此内部链路按明文 SMTP 配置 |
| 应用到 relay 的认证 | 不提供用户名或密码 |
| From / envelope sender | `[email protected]` |
| relay 的上游 | `smtp.office365.com:587`,STARTTLS + XOAUTH2 |
这里的无认证入口限于既定内部使用路径,不能直接把它暴露为外部发信入口。
其他发件身份需要对应的 Send As 授权,不能只在应用中随意改 From。
应用只需要 relay 参数,不需要读取或持有 Microsoft 365 refresh token。
## 发送一封接入测试邮件
下面在已能访问集群 Service 的应用环境中使用 Python 标准库。
将 `SMTP_TEST_RECIPIENT` 设置为自己控制的收件地址;执行会真实发送邮件,应先得到该次发信授权。
这份示例本轮未执行。
```python
import os
import smtplib
from email.message import EmailMessage
recipient = os.environ["SMTP_TEST_RECIPIENT"]
sender = "[email protected]"
message = EmailMessage()
message["From"] = sender
message["To"] = recipient
message["Subject"] = "Homelab SMTP relay test"
message.set_content("SMTP relay integration test.")
with smtplib.SMTP("smtp-relay.smtp-relay.svc.cluster.local", 25, timeout=30) as smtp:
refused = smtp.send_message(message, from_addr=sender, to_addrs=[recipient])
if refused:
raise SystemExit("收件人被拒绝,请检查 relay 状态")
```
客户端提交成功只表示 relay 接收,不保证最终送达。
维护者随后结合 relay 投递日志与收件箱确认完整链路;也检查垃圾邮件文件夹。
日志中的上游接收结果仍不能替代收件人侧确认。
## 失败时如何区分
- 连接超时或域名失败:检查集群 DNS、Service 与应用网络范围。
- relay 接收但不送达:检查投递队列、上游连接和认证,而不是给应用配置上游密码。
- `535 5.7.3`:源码提示检查 OAuth 身份是否为实际 sender,以及 token 是否需要重新初始化。
- `5.7.60`:检查 From、envelope sender 与 Microsoft 365 的发信授权是否匹配。
消费者接入不能通过重跑完整 Terraform、部署或 OAuth 初始化流程来试错。
refresh token 持久化在 `smtp-relay-tokens` PVC,SASL 层负责更新;
它是可变运行数据,不是可复制进 wiki 的配置。
源码的 device-code 流程使用 public client,维护说明明确 `CLIENT_SECRET` 留空;
不要照抄同一旧 README 中与之不一致的“创建 client secret”注释。
初始化、重新授权、DKIM 与恢复入口为 `apps/smtp-relay/README.md`。
其中 DKIM 等日期属于历史记录,本文不将其升级为新一次验证。
依赖为 Kubernetes/DNS、token PVC、Microsoft 365 邮箱与授权、上游网络及域名邮件配置。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#smtp-relay)。
+12 -3
View File
@@ -2,11 +2,12 @@
title: SPIFFE/SPIRE 使用入口与阶段状态
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_reviewed: 2026-09-21
last_verified: null
sources:
- https://git.ddupan.top/panxiao81/homelab-infra/issues/34
- https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/platform/spire/RUNBOOK.md
- https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1/spiffe-openbao-login
---
# SPIFFE/SPIRE
@@ -55,7 +56,7 @@ SPIFFE/SPIRE 取代了原计划中由 **workload-sts 承担统一 IAM 平台**
维护者指定以 [homelab-infra #34](https://git.ddupan.top/panxiao81/homelab-infra/issues/34)
为主要状态依据。2026-09-16 查阅时 issue 为 open,最后更新时间为
2026-09-14 12:43:54 UTC;本页是该次查阅的阶段摘要,不替代 ticket 的动态进度。
本轮没有访问运行环境,以下完成结论均为 ticket 记录。
基础设施阶段结论来自 ticket;2026-09-21 另对下表中的可复用 Action 做了现场验证。
| 已完成阶段 | 记录依据 |
|---|---|
@@ -63,6 +64,7 @@ SPIFFE/SPIRE 取代了原计划中由 **workload-sts 承担统一 IAM 平台**
| OIDC HTTPS、DNS、TLS、discovery/JWKS 验证;OpenBao JWT backend/role/policy 创建 | [9 月 14 日端到端验收](https://git.ddupan.top/panxiao81/homelab-infra/issues/34#issuecomment-301),对应 #52、#53 |
| 测试 Pod 获得 aud=openbao 的 JWT-SVID,交换为仅含 spire-poc policy、TTL 300 秒的 Bao token;lookup-self/revoke-self 验证完成 | 同上;临时 workload 与 registration entries 已清理,最终 Terraform plan 为 No changes |
| 新 workload 接入、故障排查和恢复说明已合并 | [9 月 14 日文档记录](https://git.ddupan.top/panxiao81/homelab-infra/issues/34#issuecomment-308),对应 #54 |
| `spiffe-openbao-login@v1` 使用本机 Workload API 获取 JWT-SVID、交换短期 token 并在 post 阶段 `revoke-self` | 2026-09-21 现场验证;Action 未向 stdout/stderr 输出 JWT-SVID 或 token |
## 如何使用
@@ -82,6 +84,13 @@ SPIFFE/SPIRE 取代了原计划中由 **workload-sts 承担统一 IAM 平台**
[Dynamic Runner](gitea-dynamic-runner.md) 提供 Pod/VM 执行环境及获取自身 SPIFFE 身份的能力,
不将 OpenBao 或其他服务的业务登录流程内置为 runner 职责。
Gitea workflow 可使用
[`panxiao81/ci-actions/spiffe-openbao-login@v1`](https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1/spiffe-openbao-login)
完成 JWT-SVID 交换与退出吊销。Action 会按 Actions 协议把短期 token 写入
`GITHUB_ENV`/`GITHUB_STATE` 临时文件,因此只允许用于 job 后销毁的一次性 Pod/VM
runner;不能用于共享或持久 runner。runner 仍只提供 Node.js 20、`spire-agent` 和
Workload API socket,role、audience 与调用时机必须由受审查的 workflow 声明。
可直接沿用的配置模板、交换示例和排障步骤见
[权威 RUNBOOK](https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/platform/spire/RUNBOOK.md)
的第 4–8 节。这里不复制第二份操作脚本。接入需要新增身份和授权配置,不是挂载 socket 后
@@ -94,7 +103,7 @@ OIDC issuer 为 `https://spire-oidc.ad.ddupan.top`,其 discovery/JWKS 用于
## 仍在 ticket 中跟踪
截至本次查阅,后续范围包括真实 Gitea CI/AI Agent 的 OpenBao 接入、credential-exec、
截至本次查阅,后续范围包括在真实 Gitea CI/AI Agent 中验收已发布的登录 Action、
SeaweedFS Web Identity/STS、非 Kubernetes 主机与临时 VM 的证明和回收、
Compute/DBaaS 消费身份,以及 HA、备份恢复和多 issuer 约定。
这些是 #34 的开放范围;单个消费者已有其他 PoC,不等于整项已完成。
+64
View File
@@ -0,0 +1,64 @@
---
title: Tailscale 远程访问指南
lifecycle: unknown
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# Tailscale
Tailscale 提供远程访问 homelab 的网络路径。维护者于 2026-09-16 表示没有需补充的动态事项;
本页根据 `apps/tailscale/subnet-routes.sh` 和共享 PostgreSQL Service 配置整理。
未读取含 OAuth 值的安装脚本,也未查询 tailnet、路由批准状态或现场连通性。
## 两种访问路径
| 路径 | 来源记录的用途 |
|---|---|
| laptop 子网路由 | 访问 LAN 与两个 SDN 网段中的原有地址 |
| Kubernetes operator 暴露 Service | 为特定 Service 提供 tailnet 入口,例如共享 PostgreSQL |
子网脚本将 laptop(LAN 地址 `192.168.10.127`)记录为唯一子网路由器,声明以下完整路由集合:
- `192.168.10.0/24`:homelab LAN。
- `10.60.0.0/24`:SDN labnet。
- `10.61.0.0/24`:SDN retronet。
operator 管理的 Service 入口不能直接视为新的通用子网路由器。
子网路由可达也不等于拥有所有目标服务的应用权限。
## 第一次从远程客户端访问
1. 在自己的客户端登录维护者指定的 tailnet,完成该设备所需的批准流程。
2. 确认客户端接受子网路由。Linux 客户端需要时可执行下面的设置;它改变本机路由接受配置。
3. 打开已有权限的 LAN 服务,例如 [Grafana](grafana.md)。域名还须通过适当的 DNS 配置解析。
```bash
sudo tailscale set --accept-routes=true
```
客户端行为见 [Tailscale 子网路由文档](https://tailscale.com/docs/features/subnet-routers)。
服务登录仍按该服务自己的流程进行。
如果访问 operator 暴露的 Service,使用维护者提供的 tailnet 地址;
不要把 Kubernetes `.svc.cluster.local` 名称当成远程客户端已经可解析的名称。
## 路由、DNS 与权限分别检查
“客户端已登录”“路由已广播”“路由已批准”“访问规则允许”和“目标服务可用”是不同条件。
LAN 的 [Blocky / 路由器 DNS 设计](lan-dns.md) 不自动证明远程客户端已获得相同解析配置。
IP 可达而域名失败时,先查看远程客户端 DNS 路径,不直接改 LAN DNS。
脚本记录两个 SDN 网段由 laptop 从 VyOS 通过 OSPF 学习。
即使 Tailscale 仍广播这两个前缀,底层 OSPF 路由缺失也会导致转发失败。
新增路由还需 tailnet 批准及访问规则配合,单看广播配置不足以验收。
`apps/tailscale/subnet-routes.sh` 是维护端脚本,`--advertise-routes` 替换完整集合;
普通客户端接入无需执行它。新增网段时按完整声明审查,避免意外移除既有路由。
现有脚本提供批准信息的查看方法;执行现场检查前仍需按本库规则对齐范围。
依赖为 Tailscale 控制与数据路径、laptop 转发及目标网络;SDN 另依赖 VyOS/OSPF,
operator Service 另依赖 Kubernetes 和 operator。
本页没有记录 tailnet OAuth、设备密钥或凭据内容。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#tailscale)。
+28 -41
View File
@@ -1,58 +1,45 @@
---
title: 旧 VictoriaMetrics Compose 栈
title: 旧 VictoriaMetrics Compose 栈(已清理)
lifecycle: retired
evidence: live-verified
last_reviewed: 2026-09-16
last_verified: 2026-09-16
sources:
- 维护者提供的 Kubernetes 完整可观测性栈替代目标
- 2026-09-16 本机 Docker 容器、卷及文件元数据只读检查
- 2026-09-16 monitoring namespace 的资源状态只读检查
- 维护者于 2026-09-16 明确要求直接删除旧配置和全部旧数据卷
- 2026-09-16 Docker 卷删除前后检查及 Kubernetes monitoring 状态检查
---
# 旧 VictoriaMetrics Compose 栈
# 旧 VictoriaMetrics Compose 栈(已清理)
**旧运行栈已停用,历史数据卷仍保留。数据是否已迁移、是否需要长期保留尚未确认。**
这里的 retired 只描述旧 Compose 运行栈,不代表旧数据已获准删除。
**旧配置与三个 Docker 数据卷已于 2026-09-16 删除,未备份、未迁移旧数据。**
维护者在了解保留数据情况后明确选择直接删除。新 Kubernetes 可观测性栈未做部署修改。
维护者最初的目标是以 Kubernetes 内的完整可观测性栈替代它,以便集成其他服务。
2026-09-16 经维护者授权进行了有限只读检查,没有启动、停止、迁移或删除任何服务或数据。
## 清理范围与结果
## 检查结果
删除前,旧 Compose 栈已经没有容器;再次确认三个旧卷没有任何容器引用后,
按完整卷名逐个删除,并检查卷列表确认它们均不存在:
- `docker ps -a` 按 Compose project `victoriametrics` 筛选,没有容器;
按 VictoriaMetrics、vmagent、vmalert、Grafana、Alertmanager 名称及镜像筛选也没有旧栈容器。
- 三个 Docker 卷仍存在,按卷筛选所有容器,没有发现引用它们的容器。
- Kubernetes `monitoring` 中 VMSingle/main 和 VMAgent/main 状态为 operational;
Grafana、指标、日志、追踪及相关采集组件的 Pod 处于 Running。
- 新栈的 Grafana、VMSingle、VLSingle、VTSingle PVC 均为 Bound。
这些资源状态不等于已经验证新旧数据一致或完成全部端到端采集验收。
| 已删除卷 | 删除前内容 |
|---|---|
| `victoriametrics_vmdata` | 约 131 MiB,包含历史指标数据与索引 |
| `victoriametrics_vmagentdata` | 空目录,占用约 4 KiB |
| `victoriametrics_grafanadata` | 约 45 MiB,包含旧 grafana.db 和插件等 |
| 旧 Docker 卷 | 磁盘占用(du -sh) | 保留内容 |
|---|---|---|
| `victoriametrics_vmdata` | 131 MiB | data、indexdb、metadata、cache 等;data/small 和 data/big 下有 `2026_02`、`2026_03` 目录 |
| `victoriametrics_vmagentdata` | 4 KiB | 本次查看目录为空 |
| `victoriametrics_grafanadata` | 45 MiB | `grafana.db`(1,536,000 字节)及 plugins、dashboards 等目录 |
源码仓库 `apps/victoriametrics/` 下的 13 个受管文件已删除,平台文档和告警规则注释
中的旧路径引用已修正。旧配置可以从 Git 历史找回;不能通过 Git 恢复已删除的数据卷内容。
本次未创建任何数据备份。
元数据统计确认 `data/` 下有 247 个文件,逻辑大小合计 118,467,976 字节;
`indexdb/` 下有 173 个文件,逻辑大小合计 11,864,570 字节。
基础设施清理已通过 [PR #73](https://git.ddupan.top/panxiao81/homelab-infra/pulls/73)
于 2026-09-16 16:05:33 UTC 合并到 main,合并提交为
[`9c64d31`](https://git.ddupan.top/panxiao81/homelab-infra/commit/9c64d31d3dea2ac2663170ca8125f03ac95cf0dd)。
PR 仅包含此次清理;源码工作区原有的其他修改未纳入。
本机卷路径为 `/var/lib/docker/volumes/<卷名>/_data`。
旧 `grafana.db` 文件修改时间为 2026-03-09 08:30:18 UTC。
目录名和文件修改时间仅是文件系统证据,不能据此断言样本的准确时间范围、完整性或可查询性。
## 清理后的检查
## 如何理解当前状态
- Docker 中三个指定卷均不存在,旧配置目录已不存在。
- 新栈 VMSingle/main、VMAgent/main 仍为 operational。
- Grafana、VMSingle、VLSingle、VTSingle 的四个 PVC 均为 Bound。
- `platform/observability/metrics` 的 Kustomize 渲染通过。
旧卷确有保留内容,不能按“只剩 Compose 配置”处理。
本机没有运行中的旧栈容器,本轮也没有可直接查询的旧实例;未为检查数据而启动旧实例。
没有读取 Grafana 数据库内容或凭据,也没有执行历史样本查询。
下一步若需要保留、恢复或迁移历史数据,应先与维护者确定目标,再安排独立工作。
在此之前保留三个卷,不运行 `docker compose down -v` 或将它们纳入未使用卷清理。
旧数据当前没有容器引用,不能因此视为可安全删除。
## 文档与代码归属
- 旧 Compose 配置:homelab-infra `apps/victoriametrics/compose.yaml`。
- 新可观测性栈:homelab-infra `platform/observability/README.md`。
- 本次只同步知识库,未改动源码中的历史配置或执行退役清理。
这些检查确认清理范围及新栈资源状态,不宣称新旧历史数据完成迁移。
现役监控的维护入口为 homelab-infra `platform/observability/README.md`。
+43
View File
@@ -0,0 +1,43 @@
---
title: vlmcsd 服务入口
lifecycle: unknown
evidence: configuration
last_reviewed: 2026-09-16
last_verified: null
---
# vlmcsd
homelab 中的 KMS 兼容服务,配置使用 `mikolatero/vlmcsd` 镜像。
维护者于 2026-09-16 表示没有需补充的动态事项;本页依据
`apps/vlmcsd/compose.yaml` 整理,未检查运行状态或客户端。
## 入口与客户端使用
Compose 将宿主 TCP `1688` 映射到容器 `1688`。实际宿主地址和客户端使用范围未在该文件中记录,
接入时由维护者提供;它是协议服务,不是网页,也没有仓库中已记录的 OIDC 登录步骤。
已有 Windows KMS 客户端需要指定服务器时,在管理员终端中将 `YOUR_KMS_HOST` 替换为已提供的地址:
```powershell
cscript.exe "$env:SystemRoot\System32\slmgr.vbs" /skms YOUR_KMS_HOST:1688
cscript.exe "$env:SystemRoot\System32\slmgr.vbs" /ato
cscript.exe "$env:SystemRoot\System32\slmgr.vbs" /dlv
```
第一步修改该客户端的 KMS 目标,第二步发起激活请求,第三步查看结果;
适用前提是客户端版本与其已有授权配置支持 KMS,不能将端口连通当成激活成功。
命令依据[镜像项目使用说明](https://github.com/mikolatero/docker-vlmcsd),本轮未执行。
已有客户端无需为了接入此服务先卸载产品密钥;本页不复制那类重置步骤。
## 故障与依赖
连接失败先核对宿主地址、TCP `1688` 与网络规则;服务可达但请求失败时,
结合客户端详细状态和服务日志区分协议、版本及客户端配置问题。
具体客户端清单、DNS 自动发现记录和宿主位置未从所读 Compose 得到,不能自行补成现状。
依赖为 Docker 与客户端到宿主的网络。所读 Compose 未声明持久卷;
这只描述此服务配置,不代表客户端状态可以随意清除。
维护配置入口为 homelab-infra `apps/vlmcsd/compose.yaml`。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#vlmcsd)。
+85
View File
@@ -0,0 +1,85 @@
---
title: zot 镜像与制品仓库使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-16
last_verified: null
---
# zot 镜像与制品仓库
zot 保存容器镜像与 OCI 制品,底层数据存放于 [SeaweedFS](seaweedfs.md)。
客户端使用 Registry API,不需要直接访问 S3 bucket。
本页依据 homelab-infra 工作区 `apps/zot/README.md` 的 2026-09-16 记录整理。
源文档记录双入口已上线并验收、由 Flux 管理;本轮未查询现场或执行下面的示例。
## 两个入口
| 入口 | 用途 | 认证 |
|---|---|---|
| `zot.ad.ddupan.top` | 内网拉取镜像或制品 | 匿名只读 |
| `zot-push.ad.ddupan.top` | 鉴权访问及已授权发布 | SPIRE JWT-SVID,audience 为 `zot`;写权限按 SPIFFE ID 和 repository 分配 |
需要到 LAN 的路由与内网 DNS。两个入口对应相同制品数据,例如推送
`zot-push.ad.ddupan.top/team/image:tag` 后,可从
`zot.ad.ddupan.top/team/image:tag` 拉取,无需再复制一份镜像。
## 第一次拉取
安装 crane 后,在可写的工作目录执行源码文档提供的只读示例:
```bash
crane pull zot.ad.ddupan.top/verification/anonymous-spire:smoke image.tar --format oci
```
预期得到本地 `image.tar` OCI archive。该验证制品仅含测试内容,没有可执行入口,
用于验证拉取链路,不要把它当作能运行的业务镜像。
日常部署使用发布方提供的真实镜像路径和 tag/digest;匿名拉取不需要登录推送入口。
## 发布自己的镜像
发布前需要同时具备:
1. 执行环境能通过 Workload API 获取自己的 SPIFFE 身份。
2. workflow 获取 `aud=zot` 的短期 JWT-SVID。
3. zot 已为该 SPIFFE ID 授予目标 repository 所需的 `read/create/update` 权限。
根据所读源文档,当前持久配置没有常驻 publisher 或删除授权,曾用于验收的临时写权限
已经撤回。因此以下是获授权后的使用模板,不能仅登录成功就假定可以推送。
假定 workflow 已将 JWT-SVID 放入当前进程的 `ZOT_JWT`,准备好自己的 `image.tar`,
并将示例目标替换为已授权的 repository/tag,在 Bash 中执行:
```bash
(
set +x
set -euo pipefail
: "${ZOT_JWT:?workflow 必须先取得 aud=zot 的 JWT-SVID}"
export DOCKER_CONFIG="$(mktemp -d)"
trap 'rm -rf -- "$DOCKER_CONFIG"' EXIT
printf '%s' "$ZOT_JWT" | crane auth login zot-push.ad.ddupan.top \
--username zot --password-stdin
crane push image.tar zot-push.ad.ddupan.top/team/image:tag
)
unset ZOT_JWT
```
临时配置目录退出时删除。登录、token 获取和刷新由 workflow 负责,
[Dynamic Runner](gitea-dynamic-runner.md) 提供环境和身份能力,不代办这些业务流程。
这里的 token 交换不会延长原 SVID 的有效期。
## 常见问题与数据边界
- 拉取域名不能推送:它只提供匿名读取,发布应使用推送域名。
- 401:检查 issuer、audience、有效期,以及 workflow 是否实际取得了 JWT-SVID。
- 登录成功但推送被拒绝:检查具体 SPIFFE ID 的 repository policy;身份与写权限分开配置。
- S3 后端报错:检查 zot 到 SeaweedFS 的连接与受管凭据,不能用客户端的 JWT 代替后端 AK/SK。
zot 的持久数据在 SeaweedFS `zot` bucket 的 `registry/` 前缀;zot Pod 的临时目录不是备份。
恢复需要完整 bucket 数据、OpenBao 专用凭据与部署配置。源文档记录独立异机/离线备份尚未建立,
不能将同一 SeaweedFS 的副本视为独立灾备;重装 zot 不得删除该 bucket。
部署、授权变更、凭据轮换及验收细节以 homelab-infra `apps/zot/README.md` 为准。
来源文件的固定版本与工作区差异见[来源追溯](../sources.md#zot)。
+237
View File
@@ -0,0 +1,237 @@
---
title: 使用指南来源追溯
last_reviewed: 2026-09-16
---
# 使用指南来源追溯
这份索引帮助读者打开使用指南所依赖的源码,并区分可复现版本与工作区材料。
2026-09-16 对照的是 homelab-infra 本地已有 `origin/main` 对应的
[提交 `5ba4411`](https://git.ddupan.top/panxiao81/homelab-infra/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5)。
本轮没有 fetch、查询服务或修改原仓库;它不是“此刻远端最新版本”的保证。
只对明确列出的来源文件比较 Git blob 与工作区文件哈希,未复制秘密内容或访问运行凭据。
下表是本次文件来源核对,不追认旧指南编写时的内容完全一致,也不验证部署结果。
| 标记 | 如何使用链接 |
|---|---|
| 内容一致 | 固定版本与本次工作区文件一致,可用来复现该文件内容 |
| 工作区有差异 | 链接只供比较已提交基线,不能证明工作区新增内容已合并 |
| 该提交未收录 | 不编造远端文件链接,仍按指南注明的工作区路径读取 |
共核对 62 个不同文件:内容一致 44,工作区有差异 12,该提交未收录 6。
某文件本地显示 untracked,不代表它一定不存在于别的分支;以这里指定提交的树为比较对象。
查更新资料可从 [homelab-infra](https://git.ddupan.top/panxiao81/homelab-infra) 进入,但不要把旧固定链接当实时状态。
维护者说明、独立项目 README、SPIRE ticket 和历史 PR 仍以各页直接链接为准。
本索引只补 homelab-infra 中近期使用指南的主要来源,不替代每页证据范围。
## gitea
[返回使用指南](services/gitea.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/gitea/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/gitea/README.md) |
| `platform/gitea-runner/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/gitea-runner/README.md) |
## grafana
[返回使用指南](services/grafana.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `platform/observability/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/observability/README.md) |
| `platform/observability/grafana/values.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/observability/grafana/values.yaml) |
## zot
[返回使用指南](services/zot.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/zot/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/zot/README.md) |
## seaweedfs
[返回使用指南](services/seaweedfs.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/seaweedfs/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/seaweedfs/README.md) |
| `apps/zot/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/zot/README.md) |
## openbao
[返回使用指南](services/openbao.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `infrastructure/openbao/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/openbao/README.md) |
## netbox
[返回使用指南](services/netbox.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/netbox/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/netbox/README.md) |
| `apps/netbox/terraform/topology.yml` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/netbox/terraform/topology.yml) |
## shared-postgresql
[返回使用指南](services/shared-postgresql.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/shared-postgresql/migration.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/shared-postgresql/migration.md) |
| `apps/shared-postgresql/cloudnativepg-cluster.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/shared-postgresql/cloudnativepg-cluster.yaml) |
| `apps/shared-postgresql/shared-postgresql-service.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/shared-postgresql/shared-postgresql-service.yaml) |
## litellm-gateway
[返回使用指南](services/litellm-gateway.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/litellm-gateway/docker-compose.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/litellm-gateway/docker-compose.yml) |
| `apps/litellm-gateway/config.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/litellm-gateway/config.yaml) |
## tailscale
[返回使用指南](services/tailscale.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/tailscale/subnet-routes.sh` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/tailscale/subnet-routes.sh) |
## ps3netsrv
[返回使用指南](services/ps3netsrv.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/ps3netsrv/docker-compose.yml` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/ps3netsrv/docker-compose.yml) |
## vlmcsd
[返回使用指南](services/vlmcsd.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/vlmcsd/compose.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/vlmcsd/compose.yaml) |
## external-secrets
[返回使用指南](services/external-secrets.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `platform/external-secrets/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/external-secrets/README.md) |
| `platform/external-secrets/clustersecretstore.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/external-secrets/clustersecretstore.yaml) |
| `platform/external-secrets/externalsecrets.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/external-secrets/externalsecrets.yaml) |
| `platform/external-secrets/kustomization.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/external-secrets/kustomization.yaml) |
## openebs
[返回使用指南](services/openebs.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `platform/openebs/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/openebs/README.md) |
| `platform/openebs/storageclasses.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/openebs/storageclasses.yaml) |
## k3s-dns
[返回使用指南](services/k3s-dns.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `platform/k3s/Corefile.desired` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/k3s/Corefile.desired) |
| `platform/k3s/coredns-custom.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/k3s/coredns-custom.yaml) |
## marker
[返回使用指南](services/marker.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/marker/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/marker/README.md) |
| `apps/marker/Dockerfile` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/marker/Dockerfile) |
| `apps/marker/deployment.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/marker/deployment.yaml) |
| `apps/marker/service.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/marker/service.yaml) |
## openviking
[返回使用指南](services/openviking.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/openviking/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/openviking/README.md) |
| `apps/openviking/docker-compose.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/openviking/docker-compose.yml) |
## smtp-relay
[返回使用指南](services/smtp-relay.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `apps/smtp-relay/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/smtp-relay/README.md) |
| `apps/smtp-relay/service.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/smtp-relay/service.yaml) |
| `apps/smtp-relay/deployment.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/smtp-relay/deployment.yaml) |
## samba-ad
[返回使用指南](services/samba-ad.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `infrastructure/samba-ad/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/samba-ad/README.md) |
| `infrastructure/samba-ad/ansible/join-windows.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/samba-ad/ansible/join-windows.yml) |
| `infrastructure/samba-ad/ansible/join-member.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/samba-ad/ansible/join-member.yml) |
| `infrastructure/samba-ad/ansible/roles/samba_member/tasks/main.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/samba-ad/ansible/roles/samba_member/tasks/main.yml) |
## oci
[返回使用指南](services/oci.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `infrastructure/oci/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/oci/README.md) |
| `infrastructure/oci/ansible/README.md` | 该提交未收录 | — |
| `infrastructure/oci/terraform/providers.tf` | 该提交未收录 | — |
| `infrastructure/oci/terraform/versions.tf` | 该提交未收录 | — |
| `infrastructure/oci/terraform/compute.tf` | 该提交未收录 | — |
| `infrastructure/oci/terraform/amd.tf` | 该提交未收录 | — |
## proxmox
[返回使用指南](services/proxmox.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `infrastructure/proxmox/README.md` | 该提交未收录 | — |
| `infrastructure/proxmox/README-ha.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/proxmox/README-ha.md) |
| `infrastructure/proxmox/ansible/auth.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/proxmox/ansible/auth.yml) |
| `infrastructure/proxmox/ansible/site.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/proxmox/ansible/site.yml) |
| `infrastructure/proxmox/ansible/ha.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/proxmox/ansible/ha.yml) |
## publish-service
[返回使用指南](guides/publish-service.md)
| 源码路径 | 与工作区比较 | 提交链接 |
|---|---|---|
| `platform/cert-manager/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/cert-manager/README.md) |
| `platform/cert-manager/certificate-wildcard-ad.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/cert-manager/certificate-wildcard-ad.yaml) |
| `platform/envoy-gateway/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/envoy-gateway/README.md) |
| `platform/envoy-gateway/gateway.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/platform/envoy-gateway/gateway.yaml) |
| `infrastructure/dns/README.md` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/dns/README.md) |
| `infrastructure/dns/records.yml` | 工作区有差异 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/dns/records.yml) |
| `infrastructure/samba-ad/ansible/provision-dc.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/samba-ad/ansible/provision-dc.yml) |
| `infrastructure/samba-ad/ansible/roles/samba_ad_dc/tasks/dns_records.yml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/infrastructure/samba-ad/ansible/roles/samba_ad_dc/tasks/dns_records.yml) |
| `apps/netbox/securitypolicy.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/netbox/securitypolicy.yaml) |
| `apps/netbox/networkpolicy.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/netbox/networkpolicy.yaml) |
| `apps/authelia/referencegrant-extauth.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/authelia/referencegrant-extauth.yaml) |
| `apps/gitea/httproute.yaml` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/apps/gitea/httproute.yaml) |
| `clusters/homelab/README.md` | 内容一致 | [固定版本](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/5ba441164661bdff24700595e0e6cd7ddb33eec5/clusters/homelab/README.md) |
+69
View File
@@ -0,0 +1,69 @@
import sys
import tempfile
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
from check_docs import check, metadata_errors, split_frontmatter
class DocumentChecks(unittest.TestCase):
def run_check(self, documents):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
for name, text in documents.items():
file = root / name
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text(text)
return check(root, list(documents))
def test_commonmark_links_and_code_examples(self):
errors = self.run_check({
"README.md": "[引用][page]\n\n[page]: guide.md#中文-标题\n\n"
"![附件](asset.svg)\n\n`[假链接](missing.md)`\n\n"
"```md\n[示例](missing.md)\n```\n",
"guide.md": "# 中文 标题\n",
"asset.svg": "<svg/>",
})
self.assertEqual([], errors)
def test_broken_reference_and_heading(self):
errors = self.run_check({"README.md": "[x][r]\n\n[r]: missing.md\n\n[x](#absent)\n"})
self.assertTrue(any("目标不存在" in e for e in errors))
self.assertTrue(any("标题锚点不存在" in e for e in errors))
def test_duplicate_headings_and_html_anchor(self):
self.assertEqual([], self.run_check({"README.md":
'# Same\n# Same\n<a id="custom"></a>\n[x](#same-1) [y](#custom)\n'}))
def test_escaped_paths_tables_and_external_links(self):
self.assertEqual([], self.run_check({
"README.md": '| a | b |\n|---|---|\n| [x](a%20b.md) | [web](https://example.invalid) |\n',
"a b.md": '# Target\n',
}))
def test_outside_repository_rejected(self):
errors = self.run_check({"README.md": "[x](../outside.md)\n"})
self.assertTrue(any("越出仓库" in e for e in errors))
def test_frontmatter_dates_and_evidence(self):
meta, _ = split_frontmatter('---\ntitle: Example\nlifecycle: active\nevidence: live-verified\n'
'last_reviewed: 2026-09-16\nlast_verified: null\n---\n# Title\n')
self.assertTrue(any("live-verified" in e for e in metadata_errors(meta, required=True)))
meta['last_verified'] = '2026-09-17'
self.assertTrue(any("不能晚于" in e for e in metadata_errors(meta, required=True)))
meta['last_verified'] = '2026-02-30'
self.assertTrue(any("YYYY-MM-DD" in e for e in metadata_errors(meta, required=True)))
def test_duplicate_yaml_keys_rejected(self):
errors = self.run_check({"README.md": '---\ntitle: A\ntitle: B\n---\n'})
self.assertTrue(errors)
def test_new_service_requires_metadata_and_index(self):
errors = self.run_check({"services/new.md": "# New\n", "services/index.md": "# Services\n"})
self.assertTrue(any("缺少 frontmatter" in e for e in errors))
self.assertTrue(any("未被 services/index.md" in e for e in errors))
if __name__ == '__main__':
unittest.main()
+84 -21
View File
@@ -1,15 +1,19 @@
# 待核实与文档缺口
# 首轮状态对齐记录(已完成)
审阅日期:2026-09-16;初版依据工作区,后续按维护者说明和指定资料对齐。
旧 VictoriaMetrics Compose 已获授权做有限现场检查,其余项目未因本清单自动查询现场。
下面的检查方法只是候选步骤,执行前先问维护者当前进度及查询范围。
以下路径相对于 homelab-infra。优先修复影响恢复、认证、DNS 和首次使用的问题。
**2026-09-16,维护者确认本轮待核实事项已结束;当前没有开放的状态核实任务。**
结论来自维护者说明、指定的项目文档与 ticket,以及旧监控栈的授权检查和清理。
本轮完成不等于所有服务都经过现场检查,也不等于各开发项目全部完工。
下文保留对齐结果;后续写作与源码文档同步移至[文档完善清单](documentation-backlog.md)。
动态实施进度继续由各项目文档和 ticket 维护,不另开一轮全量状态盘点。
## 已对齐的动态工作
NATS 已作为集群共享服务部署,当前唯一消费者为 Dynamic Runner,见 [NATS](services/nats.md)。
维护者明确 Dynamic Runner 正在积极开发,其启用范围、durable 名称和实现进度以
[项目文档](https://git.ddupan.top/panxiao81/gitea-dynamic-runner)为准。
维护者补充动态 Pod 已上线测试、系统总并发 4,VM 正在工作、系统总并发 1;
纯 self-hosted runner 准备退役。使用入口见 [Gitea / Actions](services/gitea.md)。
不再将旧示例的 durable 名称差异或启用范围列为独立待核实项。
NATS 原生通过 Account 隔离租户,跨 Account 的名称不构成全局冲突;
runner 的队列协调约定仅在其所属 Account 和 stream 范围内讨论。
@@ -28,25 +32,24 @@ SPIFFE/SPIRE 按维护者指定,以 [#34](https://git.ddupan.top/panxiao81/hom
原工作区集群总览的“首次上线待验证”不作为当前阶段判断。
详见 [SPIFFE/SPIRE 使用入口与阶段状态](services/spire.md);源码工作区本轮未修改。
## 待向维护者确认的记录差异
## 旧监控栈清理结果
初轮列出的状态差异已按维护者说明、指定资料或授权检查完成分类;不再保留自动现场核查任务。
[旧 VictoriaMetrics Compose](services/victoriametrics-legacy.md) 已于 2026-09-16 只读检查:
旧栈无容器,三个旧卷仍存在且无容器引用;VM 卷约 131 MiB、Grafana 卷约 45 MiB。
新 Kubernetes 栈的资源状态正常,但没有验证数据迁移或新旧数据一致性。
旧数据暂时保留,是否恢复、迁移或删除需先由维护者决定。
[旧 VictoriaMetrics Compose](services/victoriametrics-legacy.md) 已于 2026-09-16 完成清理:
维护者明确要求直接删除旧配置和全部数据卷,三个无引用 Docker 卷及旧配置均已删除,
未备份或迁移数据。新 Kubernetes 栈的资源状态检查和指标清单渲染通过。
基础设施清理已通过 [PR #73](https://git.ddupan.top/panxiao81/homelab-infra/pulls/73)
合并 main(`9c64d31`);配置交付和数据处置均已完成。
## 优先补充的使用说明
## 已确认的归属与范围
1. Gitea / Actions:登录、创建仓库、选择 runner,以及可信任务限制。
2. Grafana:登录、找到内存与 Swap 看板、查询指标和日志的一个完整例子。
3. zot / SeaweedFS:拉取、发布授权、S3 客户端接入,以及数据备份边界。
4. OpenBao:日常登录、按权限取用秘密、申请权限;与灾难恢复分开说明。
5. NetBox:查看拓扑与 IPAM 的路径,强调目前是评估镜像,改动入口在 Git。
6. codex-proxy、LiteLLM gateway、shared PostgreSQL、Tailscale、ps3netsrv、vlmcsd、k3s:补用途和当前状态;这些目录缺少根 README。
- 维护者于 2026-09-16 指定 Samba AD、OCI、Proxmox 优先 IaC、以代码为准;
后续可直接核对仓库配置,不重复询问同一资料范围。配置声明与现场验证仍分开记录。
## 盘点盲区
- 维护者于 2026-09-16 说明 codex-proxy“应该是退役的”,已从现役应用列表移至归档范围;
未查询运行环境,也没有删除源码或数据。LiteLLM、Tailscale、ps3netsrv、vlmcsd 无需补充动态事项,
已基于仓库配置补使用指南;这不等于新增的现场验收。
- e5renew 和 research-auto 已由维护者明确为 GitHub 上的[外部消费者](services/external-consumers.md),
不属于 homelab 基础设施,不再列为盘点盲区或缺失组件。
@@ -57,7 +60,67 @@ SPIFFE/SPIRE 按维护者指定,以 [#34](https://git.ddupan.top/panxiao81/hom
operator 仍按项目记录标为 API 骨架阶段;本轮未查询运行环境。
- workload-sts 已按维护者提供的信息查阅:仓库已归档,停止开发、不部署 PoC,
作为[早期设计与替代决策的历史来源](architecture/workload-sts-history.md)保留,不列为待接入服务。
- 新增 NATS、zot、microVM 等来源含未提交文件;合并后补可访问的 commit/PR 链接。
- Backstage 仍作为计划入口记录;本轮没有证明已有部署。
- Backstage 为计划中的统一入口,不作为已部署服务记录。
完成核实后,将结果写回对应权威文档,并更新服务总览的证据等级和验证日期。
后续出现新的状态问题时,先向维护者对齐,再按授权范围更新对应服务文档。
## Ayatori Database 设计修订同步
2026-09-24,维护者批准 Instance → Database → Tenant 资源/申请分离,替代原 PostgreSQL
registry 与自动所有权恢复合同。源仓库设计和 wiki 已同步,Ayatori 设计与 registry 撤除
已推送到 `feat/database-registry-inspection`;本记录随 wiki 来源同步提交发布。
registry 撤除通过本地全量测试、lint 及真实 API server/PostgreSQL 集成测试;
新资源 API 与三资源运行链路未完成,不属于部署或现场验证。
源设计:[6db8a49](https://git.ddupan.top/panxiao81/ayatori/commit/6db8a495fb9f8981d336c9e6288253628ab478b6);
代码撤除:[23a2d81](https://git.ddupan.top/panxiao81/ayatori/commit/23a2d81b5041f8589baab1c234136cd2c701bb06);
wiki 权威摘要:[DBaaS 设计](services/postgresql-tenant-operator.md#当前资源模型2026-09-24-已确认)。
来源链接固定到实现提交;相关设计、registry 撤除与 CI 去重修复已随
[PR #9](https://git.ddupan.top/panxiao81/ayatori/pulls/9) 合并为
[347a667](https://git.ddupan.top/panxiao81/ayatori/commit/347a667c0c1737bc4e2703dec5f11358f0425e43)。
最新 head 的 CI #781 已全部通过;无日志启动失败的 test 单项重试后通过。
旧仓库固定基线及受保护工作树未修改。
2026-09-25 的单数据库、单登录 owner 与凭据生命周期边界,以及 Database 集群级作用域、
引用与管理权限边界、资源侧先写的绑定顺序与部分写入重试规则,以及无绑定名单、
删除前策略可改与 Database UID 凭据定位的决定已同步到
[DBaaS 设计](services/postgresql-tenant-operator.md#当前资源模型2026-09-24-已确认)。
依据维护者当日确认;Ayatori 已提交为 `7e9e8e828bfcbdc8d4e2fcb6bc3d13727712a82c`,
源码已通过 [Ayatori PR #10](https://git.ddupan.top/panxiao81/ayatori/pulls/10) 的三项 CI,
并于同日按维护者要求合并为
[55b269c](https://git.ddupan.top/panxiao81/ayatori/commit/55b269ce2eb40f6b44c1afe838389093efdac98e)。
wiki 按维护者要求直接合入 main,原 [wiki PR #3](https://git.ddupan.top/panxiao81/homelab-wiki/pulls/3)
保留为历史讨论入口;后续纯文档变更不另开 PR。
关联源码:[7e9e8e8](https://git.ddupan.top/panxiao81/ayatori/commit/7e9e8e828bfcbdc8d4e2fcb6bc3d13727712a82c)。
这只是第一版 API 范围确认,不表示新资源链路已实现。
上述已合并实现包含三资源 schema 与真实 API server 校验,
本地 `make test` 与远端 CI 均通过。已接入绑定
controller、目标固定、finalizer 保留与生成 RBAC,真实 API server 验证并发、补写及 watch。
尚未实现 finalizer 清理、供应与交付,不宣称完成三资源生命周期或现场验收。
同日确认原生非 superuser + CREATEDB/CREATEROLE 管理方案,已同步至
[DBaaS 职责边界](services/postgresql-tenant-operator.md#职责边界)。Instance 观测链路的实现提交
[bc227bf](https://git.ddupan.top/panxiao81/ayatori/commit/bc227bfdb4b2f5b027fe522b8dcf72db17b84d26) 本地已通过
全量测试、三轮 controller/application race、真实 PostgreSQL/API server 集成测试及普通/integration lint。
[PR #11](https://git.ddupan.top/panxiao81/ayatori/pulls/11) 的三项 CI 均通过,维护者批准后已合并为
[f4deb98](https://git.ddupan.top/panxiao81/ayatori/commit/f4deb98a7fcf61fb97ce52bbf190beb816d0141a);
未部署或进行现场验收。
后续凭据存储切片已签名提交并推送为
[f6bb9e4](https://git.ddupan.top/panxiao81/ayatori/commit/f6bb9e4599afca49a9cdc3d40789e11d118db9c5),
由 [PR #12](https://git.ddupan.top/panxiao81/ayatori/pulls/12) 跟踪 CI 与 review。
全量测试、真实 PostgreSQL/API server/OpenBao 集成测试及两种 lint 本地通过;源码模块文档
和 wiki 已同步实现边界与正式链接。尚未合并或接入供应流程,不把本地验证等同于远端 CI。
## 2026-09-25 sandbox 存储故障复盘的来源边界
维护者报告 VyOS 到 sandbox 的 LB 故障并授权恢复。现场确认 LB 配置未在故障当天更改,
故障来自 DRBD quorum 丢失后 sandbox1 根卷进入只读;已离线修复并恢复数据库、双 API 与 Pod。
后续按维护者给出的 PostgreSQL/Alertmanager 会话核对,发现新 HDD 数据卷初始同步重叠与
多个既有资源故障的时间关联,尚未证明具体网络或磁盘瓶颈。长期恢复方法见
[Proxmox](services/proxmox.md#sandbox-lb-与根文件系统恢复)。
事故报告与恢复手册在 wiki 统一维护,见[完整事故报告](incidents/2026-09-25-drbd-quorum-sandbox.md)。
取证引用的 etcd/shared-postgresql 源码当时尚未提交,固定版本关联待源码合并后补齐;
服务恢复不等于全部整改完成。