98 Commits
Author SHA1 Message Date
panxiao81 68008e54df 记录 IAM 授权管理与注销边界及验收结果
docs / check (push) Successful in 17s
2026-09-28 12:31:40 +00:00
panxiao81 575c98c303 docs: 明确 Ayatori 显式注入及领域边界
docs / check (push) Successful in 13m3s
2026-09-27 19:18:07 +00:00
panxiao81 4a9b584913 记录维护者完成 AD 与 passkey 开发入口验收
docs / check (push) Successful in 21s
2026-09-27 18:59:58 +00:00
panxiao81 f8445a3f06 docs: 同步 Ayatori 凭据准备闭环及恢复边界
docs / check (push) Successful in 10m41s
2026-09-27 18:36:34 +00:00
panxiao81 32e135d029 记录 WebAuthn 开发入口与 PostgreSQL 凭据边界
docs / check (push) Successful in 20s
2026-09-27 18:32:59 +00:00
panxiao81 45c596786b revert: 撤回超出数据库任务范围的 Ayatori 接入记录
docs / check (push) Successful in 16s
2026-09-27 18:02:55 +00:00
panxiao81 877bc672d5 docs: 记录数据库接入声明隔离修正与范围边界
docs / check (push) Successful in 17s
2026-09-27 17:58:39 +00:00
panxiao81 bee2e1d6fa 记录登录入口通过框架配置控制 HTTPS 与启停
docs / check (push) Successful in 18s
2026-09-27 17:56:55 +00:00
panxiao81 2700037f18 docs: 同步 Ayatori 认证与 bootstrap 合并验收
docs / check (push) Successful in 14s
2026-09-27 17:51:14 +00:00
panxiao81 6de3448fb4 统一 IAM 实现与审阅入口至 PR #4
docs / check (push) Successful in 57s
2026-09-27 17:47:02 +00:00
panxiao81 107297c3e6 docs: 确认维护告警合并及 PrometheusRule 转换验收
docs / check (push) Successful in 39s
2026-09-27 17:38:04 +00:00
panxiao81 0916e08c8b 明确 React 仅替换登录界面,认证交由 Spring Security
docs / check (push) Successful in 1m7s
2026-09-27 17:35:37 +00:00
panxiao81 cf21a15bd1 docs: 更正维护监控的 PrometheusRule 与升级约定
docs / check (push) Successful in 32s
2026-09-27 17:30:30 +00:00
panxiao81 91ed4b5cae docs: 记录共享数据维护采集与告警待合并边界
docs / check (push) Successful in 8m14s
2026-09-27 17:08:24 +00:00
panxiao81 38842d3cd8 同步 IAM 认证文档并明确 Wiki 直接更新 main
docs / check (push) Successful in 11s
2026-09-27 16:57:27 +00:00
panxiao81 1f286114ac 记录认证领域分层及用户 bind 仓储连接约定
docs / check (pull_request) Successful in 18s
2026-09-27 16:55:10 +00:00
panxiao81 3a822efed8 补充企业拆机盘、SAS HBA 与跨境采购评估范围
docs / check (push) Successful in 13s
2026-09-27 04:36:54 +00:00
panxiao81 a5a1854bc1 修订混合存储预算并补充日本二手成交依据
docs / check (push) Successful in 19s
2026-09-27 04:32:28 +00:00
panxiao81 264b8f27d0 规划十万日元以内的单机混合存储候选方案
docs / check (push) Successful in 18s
2026-09-27 04:23:04 +00:00
panxiao81 95e4abfe0a 确认 laptop ARC 预算配置已合并纳管
docs / check (push) Successful in 12s
2026-09-27 03:32:53 +00:00
panxiao81 51fdf40dbb 记录 laptop ARC 4 GiB 预算与现场验证
docs / check (push) Successful in 17s
2026-09-27 03:23:01 +00:00
panxiao81 bd9f2df0e7 docs: 明确 Ayatori 公共 infra 与领域适配边界
docs / check (push) Successful in 4m4s
2026-09-25 21:56:27 +00:00
panxiao81 7e4da26f28 记录维护者已通过 AD 第一因素与属性查询验收
docs / check (pull_request) Successful in 34s
2026-09-25 21:17:57 +00:00
panxiao81 fc181ef8f6 关联 AD 实现 PR 并同步所有变更走 PR 的约定
docs / check (pull_request) Successful in 2m20s
2026-09-25 21:09:43 +00:00
panxiao81 da0d9fff01 记录 AD 第一因素接入边界与 JVM 优先验证约定 2026-09-25 21:08:48 +00:00
panxiao81 6f5b813a89 docs: 纠正 controller 认证的 Pod 部署假设
docs / check (push) Successful in 5m40s
2026-09-25 21:04:35 +00:00
panxiao81 d4114caca0 补充 OpenBao 健康与快照告警运维及验收
docs / check (push) Successful in 5m58s
2026-09-25 21:03:00 +00:00
panxiao81 2113eac41f Merge pull request '记录 iam-login 浏览器登录界面的实现边界' (#7) from docs/iam-browser-login into main
docs / check (push) Successful in 14s
Reviewed-on: #7
2026-09-25 20:43:46 +00:00
panxiao81 263a87d931 记录 OpenBao 人工解封、采集上线与快照修复验收
docs / check (push) Successful in 19s
2026-09-25 20:42:33 +00:00
panxiao81 84eff66b00 记录人工解密确认与维护管理会话前置条件
docs / check (push) Successful in 21s
2026-09-25 20:25:29 +00:00
panxiao81 6115c6b24e 记录 OpenBao 维护候选与快照前置阻塞
docs / check (push) Successful in 42s
2026-09-25 20:04:13 +00:00
panxiao81 dcf66d33b6 docs: 记录共享数据库 IaC 合并及 GitOps 接管验证
docs / check (push) Failing after 10m16s
2026-09-25 19:52:12 +00:00
panxiao81 44c967917c 补充 OpenBao 监控维护与 YubiKey 人工解封 runbook
docs / check (push) Failing after 11m38s
2026-09-25 19:50:44 +00:00
panxiao81 fee5bbccb3 记录 iam-login 浏览器交互与前后端交付边界
docs / check (pull_request) Successful in 10m26s
2026-09-25 19:46:00 +00:00
panxiao81 7d397ec436 记录第二批监控范围与 OpenBao 维护窗口前置条件
docs / check (push) Successful in 14m18s
2026-09-25 19:43:25 +00:00
panxiao81 4d18efed37 docs: 同步凭据切片合并与 Kubernetes 认证验证
docs / check (push) Failing after 11m2s
2026-09-25 19:41:30 +00:00
panxiao81 217a56f683 docs: 同步共享 etcd 与 PostgreSQL 部署验收及 IaC 来源
docs / check (push) Successful in 2m14s
2026-09-25 19:36:30 +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
panxiao81 458a3010a0 移除无现存组件的 RustFS 独立页面和索引 2026-09-16 15:46:06 +00:00
panxiao81 2a088e2b60 记录 RustFS 为已退役的 S3 选型测试实现 2026-09-16 15:44:57 +00:00
56 changed files with 4953 additions and 136 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.* .env.*
!.env.example !.env.example
.venv/
__pycache__/
*.pyc
+6 -1
View File
@@ -1,13 +1,16 @@
# 人与 AI 共用的知识库 # 人与 AI 共用的知识库
先读 README.md,按任务从 services/index.md 和 architecture/constraints.md 查找资料, 先读 README.md,按 guides/task-index.md 定位所需服务,再读 services/index.md 和 architecture/constraints.md,
并检查 verification.md 中的相关冲突。不要求把整个仓库一次性放入上下文。 并检查 verification.md 中的相关冲突。不要求把整个仓库一次性放入上下文。
- 原仓库 README 同步已按维护者要求暂缓;当前优先维护 wiki,不将源码文档同步作为其他工作的前置步骤。
- 原仓库来源的固定版本与工作区差异见 sources.md;不能把基线链接当成未提交内容已经合并的证据。
- 正式知识写给人和 AI 共同阅读;本文件只放工作规则,不另存一份服务事实。 - 正式知识写给人和 AI 共同阅读;本文件只放工作规则,不另存一份服务事实。
- 以中文维护正文、commit、PR;配置键、命令和上游专有名称保留原文。 - 以中文维护正文、commit、PR;配置键、命令和上游专有名称保留原文。
- 区分设计、配置、部署记录与现场验证。没有访问现场,不得写“运行正常”。 - 区分设计、配置、部署记录与现场验证。没有访问现场,不得写“运行正常”。
- 查询服务或项目状态前先问维护者:哪些工作正在动态进行、由哪个 ticket 跟踪、哪些现状尚未记录。已有明确授权的范围无需重复询问;不能从一个项目扩大到其他项目或现场查询。 - 查询服务或项目状态前先问维护者:哪些工作正在动态进行、由哪个 ticket 跟踪、哪些现状尚未记录。已有明确授权的范围无需重复询问;不能从一个项目扩大到其他项目或现场查询。
- 维护者指定 ticket 为依据时,先读正文和讨论,区分已完成阶段与开放的后续范围。issue open 不等于尚未部署,README 与 ticket 不同也不能立即认定为运行异常。 - 维护者指定 ticket 为依据时,先读正文和讨论,区分已完成阶段与开放的后续范围。issue open 不等于尚未部署,README 与 ticket 不同也不能立即认定为运行异常。
- Samba AD、OCI、Proxmox 已获维护者明确指定为 IaC 优先:以 Ansible/Terraform 代码为配置依据,README 为解释。此范围内读取仓库配置无需再次询问;现场查询仍按授权范围处理,不能把代码声明当作部署验收。
- 修改前读取对应源码 README/runbook;需要现场核实时先取得维护者对范围的确认。发现差异先记录来源,不能自行把计划升级为事实。 - 修改前读取对应源码 README/runbook;需要现场核实时先取得维护者对范围的确认。发现差异先记录来源,不能自行把计划升级为事实。
- 新增服务同时补用途、入口、登录方式、第一次使用示例、依赖和故障入口。 - 新增服务同时补用途、入口、登录方式、第一次使用示例、依赖和故障入口。
- 改变行为、入口、依赖、状态或恢复方法时,在同一任务更新对应文档与服务索引。 - 改变行为、入口、依赖、状态或恢复方法时,在同一任务更新对应文档与服务索引。
@@ -16,4 +19,6 @@
- 每项当前事实注明来源;last_verified 只在完成所述现场验证后更新,不随文字编辑刷新。 - 每项当前事实注明来源;last_verified 只在完成所述现场验证后更新,不随文字编辑刷新。
- 凭据只记录取得方式和受管位置,不复制实际密码、token、私钥、state 或含敏感值的输出。 - 凭据只记录取得方式和受管位置,不复制实际密码、token、私钥、state 或含敏感值的输出。
- 不复制 apps/tailscale/helm.sh 的内容。迁移旧文档前先审查敏感内容,不能整库直接发布。 - 不复制 apps/tailscale/helm.sh 的内容。迁移旧文档前先审查敏感内容,不能整库直接发布。
- 提交前运行 `python3 scripts/check_docs.py`;修改检查器时运行 `python3 -m unittest discover -s tests -v`。依赖与本地环境见 CONTRIBUTING.md。
- 本 Wiki 完成检查后直接提交并推送 main,无需 PR;代码仓库仍走分支和 PR。
- 遵守 CONTRIBUTING.md;不把临时检查日志和个人 agent memory 当成正式文档。 - 遵守 CONTRIBUTING.md;不把临时检查日志和个人 agent memory 当成正式文档。
+55
View File
@@ -7,6 +7,9 @@
2026-09-16 维护者指定 SPIFFE/SPIRE 基本以 homelab-infra #34 的记录为依据; 2026-09-16 维护者指定 SPIFFE/SPIRE 基本以 homelab-infra #34 的记录为依据;
本轮仅查该 ticket 及其直接引用的 runbook,没有查询现场。其他项目仍需先询问。 本轮仅查该 ticket 及其直接引用的 runbook,没有查询现场。其他项目仍需先询问。
2026-09-16 维护者指定 Samba AD、OCI、Proxmox 优先 IaC、以代码为准。
可直接核对其仓库中的配置与任务,README 与代码不一致时优先解释代码;此授权不等于现场变更或验收。
稳定设计与使用方法放知识库,动态进度链接到 ticket。知识库只保留注明查阅日期的阶段摘要, 稳定设计与使用方法放知识库,动态进度链接到 ticket。知识库只保留注明查阅日期的阶段摘要,
不复制维护第二份实时任务列表。issue open 可能表示后续阶段未完成,不能据此推断基础服务未部署。 不复制维护第二份实时任务列表。issue open 可能表示后续阶段未完成,不能据此推断基础服务未部署。
@@ -49,3 +52,55 @@ accepted 不代表部署完成,implemented 必须附实现和验收依据。
使用普通 Markdown 链接、相对附件路径和文字说明;关键事实直接写入正文。 使用普通 Markdown 链接、相对附件路径和文字说明;关键事实直接写入正文。
可选 Obsidian 编辑,个人布局、缓存、插件和同步配置不提交。对外分享前检查敏感内容。 可选 Obsidian 编辑,个人布局、缓存、插件和同步配置不提交。对外分享前检查敏感内容。
提交前检查相对链接、服务目录覆盖,以及新增内容是否混淆计划和运行事实。 提交前检查相对链接、服务目录覆盖,以及新增内容是否混淆计划和运行事实。
## 一次服务变更应更新哪里
| 变化 | 必须查看的文档 |
|---|---|
| 使用入口、认证、权限、客户端参数 | 对应 `services/` 页面;入口变化同时更新服务总览 |
| 新增或退役组件 | 服务页、`services/index.md`;任务入口变化再改 `guides/task-index.md` |
| 跨服务设计或边界 | `architecture/constraints.md` 及受影响指南 |
| 只有开发进度变化 | 原项目 ticket;wiki 仅在阶段摘要需要变化时更新并注明日期 |
| 取得新的验证结果 | 服务页说明日期与验证范围,据实更新 `last_verified` |
| 工作区来源已合并 | 核对实际内容后更新 `sources.md` 的固定链接及差异标记 |
先修改最接近事实的页面,再同步导航,避免把同一套操作复制到多份文档。
无需每次修改都更新首页、所有服务页或整个来源索引。
原仓库 README 同步按维护者要求暂缓,不阻塞 wiki 的维护。
按维护者 2026-09-27 的明确约定,本 Wiki 的修改完成检查后直接提交并推送 `main`,
无需创建 PR。此规则仅适用于 Wiki;代码仓库仍按各自约定新建分支并提交 PR。
不得跳过文档检查或覆盖其他工作区修改。
## 本地与 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):有什么、有什么用、在哪里、状态依据是什么。 - [按任务查找文档](guides/task-index.md):接入服务、写 CI、查日志、取秘密或接续 AI 任务。
- [SPIFFE/SPIRE](services/spire.md):按 #34 整理的阶段状态、使用与 runbook 入口。 - [服务总览](services/index.md):组件、用途、入口和状态依据。
- [PostgreSQL Tenant Operator](services/postgresql-tenant-operator.md):计划在共享 PostgreSQL 上提供的 DBaaS 中间层。 - [发布新服务](guides/publish-service.md):LAN DNS、证书、HTTPRoute、认证与 GitOps。
- [Gitea Dynamic Runner](services/gitea-dynamic-runner.md):原 microVM runner,现支持 Pod/VM 两种一次性执行环境。 - [架构约束](architecture/constraints.md):修改环境前必须遵守的设计。
- [NATS](services/nats.md):已部署的集群共享消息服务,目前仅 Dynamic Runner 消费。 - [来源追溯](sources.md):固定源码版本,以及与工作区的差异。
- [旧 VictoriaMetrics 栈](services/victoriametrics-legacy.md):运行栈已停用,历史数据卷保留。 - [文档维护规则](CONTRIBUTING.md)、[服务模板](templates/service.md)、[AI 工作入口](AGENTS.md):如何共同维护知识。
- [LAN DNS](services/lan-dns.md):Blocky 主 DNS、路由器上游与备用、Samba AD 域 DNS 的现状。 - [首轮状态对齐记录](verification.md):已完成的澄清与历史处置。
- [Authelia](services/authelia.md):active 的唯一主 OIDC broker 与登录入口。 - [文档完善清单](documentation-backlog.md):已补指南与暂缓事项。
- [待核实与文档缺口](verification.md):互相矛盾的记录、缺少使用说明的服务、下一步核实方法。
- [架构约束](architecture/constraints.md):修改环境前必须遵守的设计及原始依据。 设计历史与范围外项目见[workload-sts](architecture/workload-sts-history.md)、
- [workload-sts 设计历史](architecture/workload-sts-history.md):已归档的早期身份方案及 SPIRE 替代决策。 [旧监控栈](services/victoriametrics-legacy.md)及[外部消费者](services/external-consumers.md)。
- [文档维护规则](CONTRIBUTING.md):人和 AI 如何共同维护知识。
- [服务文档模板](templates/service.md):新服务必须同时提供使用说明。
- [AI 工作入口](AGENTS.md):新上下文按任务查找资料。
## 当前证据边界 ## 当前证据边界
@@ -25,11 +22,13 @@
`ebe0ec154dab557598075b5cf6d3629c3c23fe2a`。该工作区包含未提交修改和未跟踪文件。 `ebe0ec154dab557598075b5cf6d3629c3c23fe2a`。该工作区包含未提交修改和未跟踪文件。
后续按维护者提供的线索补读了 SPIFFE/SPIRE #34 与 runbook、workload-sts 归档决策、 后续按维护者提供的线索补读了 SPIFFE/SPIRE #34 与 runbook、workload-sts 归档决策、
PostgreSQL Tenant Operator 的 README 与架构文档,以及 Gitea Dynamic Runner README。 PostgreSQL Tenant Operator 的 README 与架构文档,以及 Gitea Dynamic Runner README。
具体来源和查阅范围见各页;其余条目仍以初轮工作区证据为限。 具体来源和查阅范围见各页;后续使用指南已按对应源码和上游接口文档逐项补充。
未补充的状态仍以初轮证据为限;来源文件与已提交版本的比较见[来源追溯](sources.md)。
LAN DNS 已按维护者于 2026-09-16 提供的现状更新,未查询现场。 LAN DNS 已按维护者于 2026-09-16 提供的现状更新,未查询现场。
Authelia 同日由维护者明确为 active、唯一的主 OIDC broker,已同步到服务总览。 Authelia 同日由维护者明确为 active、唯一的主 OIDC broker,已同步到服务总览。
后续状态查询先向维护者确认动态工作与资料来源,授权范围内不重复询问。 后续状态查询先向维护者确认动态工作与资料来源,授权范围内不重复询问。
初轮没有查询运行环境;后续仅对旧 VictoriaMetrics 栈做了维护者明确授权的有限只读检查, 初轮没有查询运行环境;后续对旧 VictoriaMetrics 栈做了维护者明确授权的有限只读检查,
随后按明确要求删除旧配置和数据卷,
检查范围和结果见对应页面。“文档记录已部署”不等于今天已验证健康。 检查范围和结果见对应页面。“文档记录已部署”不等于今天已验证健康。
本库中的入口地址来自原有记录,也尚未逐一验证可达性。 本库中的入口地址来自原有记录,也尚未逐一验证可达性。
+89
View File
@@ -0,0 +1,89 @@
---
title: Ayatori 控制面边界
last_reviewed: 2026-09-25
---
# 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 已部署或达到生产可用状态。
## Controller 公共基础设施边界
2026-09-25 维护者确认:OpenBao 认证、客户端及 Kubernetes 读写访问是整个 controller 的
infra 能力,不属于第一个使用它们的 Database 领域。启动入口统一装配和注入;公共层不反向
依赖产品领域,也不为复用而增加全局注册中心或统一包装所有后端的 reader/writer。
优先使用官方 SDK 和 manager 已提供的接口;不同身份与权限范围仍须显式隔离。
领域维护业务值对象与规则,application 按消费方需要定义 repository 接口,adapter 负责
对象映射与后端访问。例如 Database 七键凭据、位置约束及冲突恢复不是通用 KV 规则,
也不应因接入 Bao 而把这些业务规则归入 adapter。此次修订纠正原实现把 Bao 认证放在
Database adapter 的归属,认证方式与部署位置约定不变。源码拆分由
[PR #13](https://git.ddupan.top/panxiao81/ayatori/pulls/13) 跟踪,2026-09-27 经维护者批准合并;
实现与详细约定见
[6b2808c 的总体架构](https://git.ddupan.top/panxiao81/ayatori/src/commit/6b2808ce91b03215f466746a15d0c3d7442bb9d4/docs/architecture/overview.md#进程内依赖边界)。
2026-09-27 维护者进一步确认采用 Wire 风格的显式构造器注入:当前规模由 bootstrap
集中手写装配,不引入运行时 IoC 容器或代码生成依赖。controller 接收装配完的用例,
不在 Reconcile 或注册过程中创建 adapter/use case。application 保留 I/O 编排、消费方
接口及并发快照;凭据值对象、准备资格和恢复规则归领域,Kubernetes Conditions 映射归
adapter。此约定用于纠正业务规则混入 application 及装配分散的问题,不要求把所有接口
和临时数据结构搬进领域。实现见待审阅的
[PR #15](https://git.ddupan.top/panxiao81/ayatori/pulls/15),具体边界与测试见
[7834cab 的总体架构](https://git.ddupan.top/panxiao81/ayatori/src/commit/7834cab/docs/architecture/overview.md#进程内依赖边界);
不改变现有 API 或凭据协议,尚未部署。
## 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 策略。
+24 -3
View File
@@ -1,15 +1,25 @@
# 架构约束索引 # 架构约束索引
审阅日期:2026-09-16。以下是现有仓库明确记录的约束摘要,不是本轮新增的架构决策。 审阅日期:2026-09-25。以下是现有仓库明确记录的约束摘要;Ayatori 条目来自其独立项目的
来源路径相对于 homelab-infra;修改时必须读原文和对应代码,冲突进入[核实清单](../verification.md)。 已接受设计,其余来源路径相对于 homelab-infra。修改时必须读原文和对应代码,新出现的差异
先向维护者确认;[首轮状态对齐](../verification.md)已完成。
| 约束 | 原因与边界 | 来源 | | 约束 | 原因与边界 | 来源 |
|---|---|---| |---|---|---|
| Ayatori 公共 infra 与领域 repository 分离 | 连接、认证和官方读写客户端统一装配;领域保留对象映射和业务语义,不引入万能仓储 | [Controller 公共基础设施边界](ayatori-control-plane.md#controller-公共基础设施边界) |
| 新增监控配置优先使用 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 明确、各服务使用指南 |
| 新建 etcd 按全 homelab 共享基础设施设计,PostgreSQL 为首个消费者 | 替代 PostgreSQL 专属 DCS 定位,避免每个服务重复部署;三成员及消费者 RBAC 隔离已部署,不迁移现有 k3s datastore | [共享 etcd](../services/shared-etcd.md),维护者于 2026-09-25 明确 |
| 服务独立部署,Terraform root/state 按服务隔离 | 避免认证和变更影响范围绑在一起 | `AGENTS.md`、`CLAUDE.md` | | 服务独立部署,Terraform root/state 按服务隔离 | 避免认证和变更影响范围绑在一起 | `AGENTS.md`、`CLAUDE.md` |
| OpenBao 恢复不能依赖 k3s 或读取自己内部的恢复凭据 | 先恢复信任根,再恢复消费者 | `infrastructure/openbao/README.md`、`CLAUDE.md` | | OpenBao 恢复不能依赖 k3s 或读取自己内部的恢复凭据 | 先恢复信任根,再恢复消费者 | `infrastructure/openbao/README.md`、`CLAUDE.md` |
| Terraform 管 API 配置,Ansible 管主机及不能安全纳管的密钥材料 | 不可读回秘密和根密钥不能靠反复重建实现收敛 | `infrastructure/openbao/README.md` | | Terraform 管 API 配置,Ansible 管主机及不能安全纳管的密钥材料 | 不可读回秘密和根密钥不能靠反复重建实现收敛 | `infrastructure/openbao/README.md` |
| LAN HTTP 入口为 Envoy Gateway;新增服务核对 parentRefs、DNS 和认证 | 不直接套用 archive 中的 Gateway 示例 | `platform/envoy-gateway/README.md`、`AGENTS.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 补充 | | SPIFFE 提供跨基础设施的统一机器身份入口,替代 workload-sts 统一 IAM 平台方案 | 服务信任 SPIFFE 身份、签发自己的 token 并维护自身权限;非 Kubernetes 身份不依赖 Kubernetes ServiceAccount,优先复用服务现有接入机制 | [核心设计与取舍](../services/spire.md#核心设计与取舍),维护者于 2026-09-16 补充 |
| 已由 Flux 接管的资源通过 Git 修改;brownfield 不全局开启 prune | 防止漂移回滚与误删;未接管资源不能假定受 Flux 管理 | `clusters/homelab/README.md` | | 已由 Flux 接管的资源通过 Git 修改;brownfield 不全局开启 prune | 防止漂移回滚与误删;未接管资源不能假定受 Flux 管理 | `clusters/homelab/README.md` |
| DNS 各视图保留权威边界;只管理明确声明的 RRset | 不清理 Samba 自动维护的域记录;LAN 现状按维护者说明对齐,旧源码文档待同步 | `infrastructure/dns/README.md`、[LAN DNS](../services/lan-dns.md) | | DNS 各视图保留权威边界;只管理明确声明的 RRset | 不清理 Samba 自动维护的域记录;LAN 现状按维护者说明对齐,旧源码文档待同步 | `infrastructure/dns/README.md`、[LAN DNS](../services/lan-dns.md) |
@@ -23,3 +33,14 @@
通用变更约束:先做适用的 plan/check/diff,再操作现场;不将凭据和 Terraform state 通用变更约束:先做适用的 plan/check/diff,再操作现场;不将凭据和 Terraform state
写入知识库;不更新 homelab-infra 的冻结 `CHANGELOG.md`。 写入知识库;不更新 homelab-infra 的冻结 `CHANGELOG.md`。
## 待评估草案
[十万日元以内混合存储草案](hybrid-storage-draft.md)(2026-09-27,draft)评估单机
Ceph SSD/HDD 分池、千兆起步与二手 PC。预算与方向来自维护者讨论,尚未形成已验证的
采购清单,未部署或替代现有存储;备份与恢复优先于跨主机高可用。
[独立 IAM 与 agent 身份草案](independent-iam-draft.md)(2026-09-25,draft)提出以 Hydra
解耦认证与签发,通过 OIDC 接入人类、machine 和 agent,并作为 Ayatori 的独立外部依赖。
完整方案仍为草案。2026-09-25 已按维护者要求先实施人类登录 PoC,上表显式记录其有限
变更;SPIFFE、agent 动态授权、组模型及 DNS 迁移未随之实施。
+149
View File
@@ -0,0 +1,149 @@
---
title: 十万日元以内混合存储草案
last_reviewed: 2026-09-27
---
# 十万日元以内混合存储草案
状态:**draft**。依据维护者 2026-09-27 的讨论:第一版即评估 SSD/HDD 混合存储,
整机预算目标不超过 **100,000 日元**,优先日本二手 PC、低流量、千兆内网。
接受单存储机故障时停机,关注独立备份与可恢复性,不以跨主机高可用为前提。
本页未代表采购决定、已验证兼容的物料清单或部署记录;本轮未查询现场容量。
## 已有环境与接入边界
现有文档记录 [OpenEBS](../services/openebs.md) 提供本地 ZFS PVC,
[SeaweedFS](../services/seaweedfs.md) 提供 S3,[zot](../services/zot.md) 使用其对象存储。
StorageClass 名称中的 ceph 不代表现场已有独立 Ceph 集群。
本草案不自动迁移这些服务,也不把现有数据视为可以删除重建。
目标覆盖 VM、裸机/普通容器和 Kubernetes。Ceph 为候选统一后端:RBD 提供块存储,
CephFS 提供文件系统,RGW 提供 S3;CSI 只是 Kubernetes 接入方式。
OCI 镜像继续通过 registry 管理,不能将 S3 endpoint 当作 OCI registry。
未来评估 zot 后端迁移时需核对 S3 兼容性、对象迁移与回滚。
## 数据放置候选
| 介质/池 | 用途 | 候选策略 |
|---|---|---|
| SSD 元数据池 | CephFS 元数据、RBD 元数据、RGW 索引等 | 三副本,规模按实际对象数估计 |
| SSD 数据池 | 数据库、运行中的 VM 磁盘、其他活跃数据 | 评估 EC 2+1;按同步写延迟决定是否对部分数据使用副本池 |
| HDD 数据池 | 下载、做种、ISO、构建出的 VM 镜像、OCI blob、温冷数据 | 评估 EC 2+1,接受较低随机 I/O 性能 |
| 独立备份目的地 | 不可重建的数据、数据库原生备份与日志、恢复材料 | 必须离开本存储机;地点与成本尚未确定 |
CRUSH 规则按设备类别约束 SSD/HDD,故障域候选为 `osd`,每个 OSD 对应独立物理盘。
两个介质池分别使用 EC 2+1 时,至少需要 **3 SSD + 3 HDD**,不是三块混合介质凑出两池。
这是显式放置,不是自动冷热分层。做种/拉取并发仍需实测 HDD 延迟,不能假定全部是顺序 I/O。
假设 3×512 GB SSD 与 3×4 TB HDD:仅按 EC 数据计算,名义容量分别约 1.024 TB 和 8 TB。
这不是可承诺业务容量:SSD 还承载副本元数据,两组均需扣除系统开销与空闲余量。
三盘 EC 2+1 坏一盘后没有第三个同类 OSD 可恢复完整分片数,需换盘或增盘。
`min_size` 决定降级后的 I/O 边界;不能为了继续写入而默认降低它。
两个校验分片以上的布局需要更多同类盘,另行比较成本。
EC 的 k/m 不随扩盘改变,变更编码需新池及迁移。
## 硬件与预算门槛
按日本 junk/个人二手交易重新选品,基础机以 **5,000–10,000 日元为寻找目标**,
优先 CPU、主板、电源和机箱完整且可进入 BIOS 的整机;不再按保修商用整机价格估算。
这是等待合适货源的目标,不代表当前有满足六盘条件的现货。
整机自带内存应与裸机加内存比较总价,不能预设“补至 32 GB 只需 7,000 日元”。
CPU 先比较八代桌面 i5 和旧 Xeon E3 塔式机,不预留大量混跑计算业务的预算。
内存同时比较 16 GB 起步试验与 32 GB 整机方案,不把 32 GB 定为购买前提。
六 OSD 加 MON/MGR、MDS/RGW 的 16 GB 方案需要收紧各进程内存预算并验证恢复负载,
尚未证明能满足本环境;32 GB 也不是无需调优的保证。
系统盘独立,目标总连接数为六块数据盘加系统盘;系统盘可用原机 M.2,仍须核对端口共享。
选底座时先核实三个 3.5 英寸 HDD 的安装、三个 SSD 的固定、全部端口和电源线,
再比较 SATA 扩展卡/HBA、盘架、运费后的总价。单看“塔式”或 CPU 代数不能确定兼容。
DDR4 UDIMM、ECC UDIMM、RDIMM 和 SO-DIMM 必须按具体主板区分,不能用便宜的异种内存凑价。
### 2026-09-27 二手市场查阅记录
以下为查阅页面的标价或成交记录。网页可能使用缓存;“显示库存”不保证此刻仍可购买,
也不保证有三块相同条件的磁盘。已结束的交易仅用于设定寻找目标。
| 样本与来源 | 日元 | 页面状态与限制 |
|---|---:|---|
| [TX1310 M3,E3-1225 v6、8 GB、120 GB SSD](https://jmty.jp/shizuoka/sale-pcp/article-1r5eh5) | 5,000 | 8 月发布,已结束受理;静冈富士市自取,卖方称正常工作但按 junk 出售 |
| [OptiPlex 3070,i5-9500、32 GB、无盘](https://jp.mercari.com/item/m67679775226) | 17,000 | 已售,含运费;BIOS 确认,半高扩展槽的小机箱,不是六盘兼容推荐 |
| [Samsung DDR4-2666,8 GB×4](https://paypayfleamarket.yahoo.co.jp/item/z663609362) | 16,000 | 8 月 17 日已售,含运费;需要四个兼容 DIMM 插槽 |
| [じゃんぱら 桌面 DDR4-2666,16 GB 单条](https://www.janpara.co.jp/sale/search/detail/?ITMCODE=162546) | 9,980 | 页面列出库存;两条 19,960,不能推断为所有 DDR4 的最低价 |
| [Intel D3-S4610 480 GB×3,拍卖编号 v1238959510](https://auctions.yahoo.co.jp/jp/auction/v1238959510) | 18,150 | 结束交易列表显示 8 月 2 日成交,27 次竞价;原详情无法重新读取,运费及健康记录待核,不能作为现货 |
| [Ultrastar DC HC310 4 TB](https://paypayfleamarket.yahoo.co.jp/item/z638495592) | 11,800 | 已售,作为同容量二手 HDD 的价格样本 |
| [WD40EZAX 4 TB](https://store.shopping.yahoo.co.jp/excellar/1050028495.html) | 14,900 | 页面显示余量少;卖方标注 CMR、9,000–10,000 小时,东京免运,未确认三块库存 |
TX1310 M3 比大量办公 SFF 更值得筛选,但不是无需改装的六盘机。
[富士通日本规格书](https://jp.fujitsu.com/platform/server/primergy/catalog/close/pr201902/tx1310m3_catalog.pdf)
列出四个 3.5 英寸 SATA 盘位、一个 5 英寸半高位、四个 DIMM 插槽、四端口 SATA 控制器,
以及全高 PCIe x16/x4 插槽。六块数据盘加系统盘仍需核实扩展卡、SSD 盘架和供电;
旧服务器的内存规格应按完整型号与官方配置表确认。
### 有条件的预算,而非现货采购单
用主机 **10,000**、另购 32 GB 内存 **19,960**、上述三 SSD 成交价 **18,150**、
三块 HDD 按 **14,900×3** 计算,小计已经 **92,810 日元**,尚未包括缺失系统盘、
扩展卡、盘架和额外运费。SSD 是历史成交价,HDD 数量未确认,因此这不是可下单总价。
若找到类似 **17,000 日元含 32 GB 的整机**,同样磁盘价格下小计为 **79,850 日元**,
才有约两万日元处理扩展与运输;但上述 OptiPlex 机箱不适合直接照搬此组合。
下一轮应优先找盘位合适且带足内存的塔式整机,以及型号和健康数据明确的企业 SSD 批次,
而不是锁定最便宜的小机箱再不断追加改装费用。
结论是十万目标有继续寻找二手组合的依据,**尚未找到兼容性、库存和含运费总价全部落实的组合**。
原先 24,000 日元买齐三块 4 TB HDD、7,000 日元补至 32 GB 的额度撤回,不能继续当作预算事实。
预算暂不含新购独立备份设备;若没有可用目的地,需纳入最终总价或分阶段投入。
## 企业拆机盘、HBA 与跨境采购
维护者补充的筛选方向:优先比较日本及中国国内二手企业级 SSD/HDD,主机也纳入跨境比价;
不限定消费级磁盘,不因主板 SATA 口不足直接淘汰基础机,可增加 SAS HBA。
跨境方案按商品、境内运输、国际运输、实际税费与退换成本计算到手价,不能仅换算挂牌价。
国内公开搜索本轮未获得可核实的当前完整报价,不将旧交易或行情转载写成现货价格。
企业 SSD 优先核对 PLP、剩余耐久、完整型号与固件,以及同步写表现。
[Ceph 硬件建议](https://docs.ceph.com/en/latest/start/hardware-recommendations/)
强调企业 SSD 的掉电保护与持续性能;企业级不等于二手个体已健康,也不必一律购买高 DWPD 型号。
SATA 与 SAS HDD 均参与比价,按相同容量、检测程度和退换条件比较。
2026-09-27 搜索索引提供一个新的价格线索:
[HGST HUS726040ALS210 / EMC HUS72604CLAR4000,4 TB SAS](https://store.shopping.yahoo.co.jp/misaonet/hitachihgsthus726040als2104tbsasemchus72604clar4000.html)
标价 **5,258 日元**。详情页未成功读取,库存、运输、扇区格式与健康数据均未核实,
不能据此确认可用,也不能当作已验证三盘报价。该样本足以支持继续查 SAS 企业盘,
原先 14,900 日元的 SATA 样本不是二手 4 TB 的价格下限。
HBA 候选可从 LSI 9207-8i / SAS2308 同类卡比较:
[官方规格](https://docs.broadcom.com/doc/12352057)列出 PCIe 3.0 x8、八个 SAS/SATA 端口、
两个 SFF-8087 接口及 9.8 W 功耗;
[官方固件说明](https://www.broadcom.com/support/knowledgebase/1211161500727/lsi-sas-9207---9217-firmware)
说明 9207 出厂 IT 固件允许单盘直通。OEM 卡仍须逐型号确认固件、接口与兼容性。
HBA 的选型费用包括对应 SAS/SATA 线束、供电、挡板和散热,不能只算卡价。
[官方用户指南](https://docs.broadcom.com/doc/12353331)规定最低风速 200 LFM,
普通塔式机需要检查卡周围风道,而非只确认机箱有风扇。
[SAS 控制器可以接 SATA 盘,SATA 控制器不能接 SAS 盘](https://www.seagate.com/gb/en/support/kb/connecting-sata-drive-to-sas-controller-006170en/)。
实际采购核实磁盘端连接器与线束;存储阵列拆机盘另查逻辑扇区格式、锁定状态和 OEM 固件,
不能默认所有盘都可直接接入或重新格式化。Ceph 候选保持每块物理盘独立暴露给 OSD。
下一轮优先比较日本本地底座搭配国内小件/磁盘,与整机跨境两种到手成本;
盘位、HBA 插槽、供电和散热仍需对具体机器核实。当前没有采购或部署动作。
## 下一步与实施门槛
1. 确定 SSD 活跃数据和 HDD 温冷数据各自所需的可用容量、增长余量;当前尚未提供。
2. 筛在售的二手基础机与磁盘,逐项核实盘位、供电、接口、内存和含运费总价。
3. 用选定版本验证六 OSD 的内存、同步随机写、镜像分发、做种并发和坏盘重建影响。
4. 演练系统盘重装、MON 状态与凭据恢复、数据库原生备份还原;不将 OSD 尚存等同于可直接导入。
5. 通过后单独制定消费者迁移与回滚步骤;本草案不授权购置、部署或移动数据。
若六盘及基础机无法压到预算内,优先调整容量或采购阶段,明确记录取舍;
不通过未说明的单副本、混合介质分片或降低 `min_size` 凑预算。
## 技术依据
- [Ceph CRUSH 设备类别](https://docs.ceph.com/en/latest/rados/operations/crush-map/)
- [Ceph EC、元数据池与编码边界](https://docs.ceph.com/en/latest/rados/operations/erasure-code/)
- [Ceph 内存与硬件建议](https://docs.ceph.com/en/latest/start/hardware-recommendations/)
上游 latest 文档可能对应开发版本;真正部署前需按所选稳定版本重新核对支持范围。
+283
View File
@@ -0,0 +1,283 @@
---
title: 独立 IAM 草案:人类、机器与 AI Agent 的统一应用接入
status: draft
last_reviewed: 2026-09-27
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,不意味着下游会自动执行或撤销相应权限。
具体组名、角色模型及同步方式尚未确定。
### 客户端注册与管理边界
Hydra 是 OAuth2 客户端注册表,提供客户端 CRUD Admin API 与动态注册能力;注册本身无需
扩展 iam-login 或修改 Hydra 服务器配置文件。当前第一方 client allowlist 仅用于 PoC 授权。
后续应用接入应确定统一的授权策略来源,避免长期同步两份客户端配置;应用所有权、审批、
回调变更权限及密钥管理可能形成独立 IAM 管理功能,其界面与实现尚未选型。
本轮不把客户端管理后台纳入登录服务,不开放公共动态注册。
## 人类后端、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、持久化及监控,实测资源成本;不能把编译成功等同完整验收。
日常迭代以 JVM 测试为准,不再要求每轮 Native 编译;Native 留在阶段性验收时集中验证,
新增路径未经过原生测试时须明确记录。
首轮保持 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 密码因素与直接所属组查询在重构前已通过维护者浏览器验收;此前 Spring Data LDAP 版本
已通过 JVM 与浏览器回归;后续 Spring Security + WebAuthn 开发路径已获维护者实际验收确认(见下文)。
密码成功仅建立第一因素;WebAuthn 开发链路可继续完成第二因素;新增 Hydra 接入已完成隔离授权码验证,尚未替换现役入口。
界面方案的早期验证见 [iam-login PR #3](https://git.ddupan.top/panxiao81/iam-login/pulls/3);
AD 接入与 Spring Security 重构统一见 [iam-login PR #4](https://git.ddupan.top/panxiao81/iam-login/pulls/4),使用方式见
[iam-login AD 接入文档](https://git.ddupan.top/panxiao81/iam-login/src/branch/main/docs/ad-login.md)。
按维护者 2026-09-27 明确的边界,React 只替换 Spring Security 默认登录前端。
认证、因素状态、SecurityContext、会话轮换与退出由 Spring Security 管理,不再维护
自建 `LoginTransaction` 状态机。HTTPS 跳转使用 Spring Security 配置;未启用 AD 时
通过条件装配移除登录页面与密码处理链,由兜底安全链拒绝访问,不增加自定义 Filter。
密码通过可以保存仅含密码因素的认证结果,但不能
据此接受 Hydra challenge;尚未实现的应用入口仍拒绝访问。
代码按 DDD 组织 `authentication` 限界上下文:领域层持有 `User`、`UserRepository`,
应用层编排目录密码验证和用户查询,AD 基础设施使用 Spring Data LDAP 实现用户仓储,
Security Provider 将结果接入框架,Web 层只渲染页面。仓储复用本次用户 bind 的连接,
查询完成即关闭,不增加独立读取账号,也不把密码或连接保存在浏览器会话中。
后续机器 API 独立设计。
WebAuthn 采用 Spring Security 官方 JDBC 仓储与 PostgreSQL,开发先使用本地容器和持久卷;
生产共享 PostgreSQL 在部署阶段接入。首次注册要求近期 AD 密码,已有凭据后的注册还需
已有 WebAuthn 因素;注册本身不算第二因素通过。凭据删除、自助恢复与已有凭据迁移暂未开放。
认证器验证、因素合并与会话轮换复用框架,应用扩展只约束目录主体、凭据归属与 challenge
时效/单次消费。实现与验证范围见 [iam-login PR #6](https://git.ddupan.top/panxiao81/iam-login/pulls/6);
2026-09-27 已通过 JVM 与虚拟认证器浏览器验证;维护者随后反馈已完成开发入口验收、
看起来能够工作,据此确认真实人类 AD + passkey 路径。Native、重启恢复与生产 Hydra 新链路仍待验收。
### 目录与 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 的通用示例域名/地址待清理。
上述项目仅保留记录,本轮不修改原仓库文档。
+47
View File
@@ -0,0 +1,47 @@
---
title: laptop ARC 内存预算
last_reviewed: 2026-09-27
---
# laptop ARC 内存预算
laptop 同时运行 Kubernetes、数据库和 libvirt VM。维护者于 2026-09-27 明确批准
先将 ZFS ARC 上限设为 **4 GiB**,为应用和虚拟机保留突发余量。保留自动 ARC 下限。
## 当前配置与验证
2026-09-27 已在线应用 `zfs_arc_max=4294967296`,持久文件为
`/etc/modprobe.d/homelab-zfs-arc.conf`,并更新所有已安装内核的 initramfs。
没有重启主机、卸载 ZFS 或重启业务。现场 `arcstats` 的 `c`、`c_max` 均为
4294967296,`c_min` 保持 1038999680;随后 ARC 实际使用量约 3.75 GiB,
内存 PSI 的 10/60/300 秒窗口均为 0。这个即时结果不等于已经验证下一次更新负载。
配置源码和回滚操作见
[PR #165](https://git.ddupan.top/panxiao81/homelab-infra/pulls/165) 的
[Ansible play](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/06943d4c6583f1b62fea6176b56f237da54a12e7/infrastructure/host-memory/laptop-arc.yml) 与
[操作说明](https://git.ddupan.top/panxiao81/homelab-infra/src/commit/06943d4c6583f1b62fea6176b56f237da54a12e7/infrastructure/host-memory/README.md)。
现场已部署,PR 已于 2026-09-27 合并至 main;合并提交为
[06943d4](https://git.ddupan.top/panxiao81/homelab-infra/commit/06943d4c6583f1b62fea6176b56f237da54a12e7)。
## 为什么设置预算
2026-09-26 17:13–17:21 UTC,Gitea RunnerService 请求超过内网 Envoy 的 15 秒超时。
集中日志确认其中一次 Declare 请求在 Gitea 内耗时约 45.5 秒。
同期宿主机发生内存回收、换页与 I/O 压力,ARC 从约 3.8 GiB 增至 5.8 GiB,
当时自动上限约 15.5 GiB。数据库、DNS 与控制面都有延迟迹象。
进程指标 `vm:winadmin` 写入由约 0.04 MiB/s 升至约 5.8–7.5 MiB/s,
与虚拟磁盘 `zd128` 对应。Windows 任务日志确认 Edge 自动更新在
17:10:59 开始、17:20:55 结束,期间有安装/AppX 活动。多层证据支持它是重要触发负载,
但没有 Windows 进程级 I/O 历史,不能宣称已证明唯一原因。
排查优先使用已有 process-exporter:QEMU 按 VM 名分组,支持 PSS、SwapPss 和 I/O。
进程 I/O 计数可能包含退出子进程的记账,containerd-shim 突跳不能直接解释为实时盘吞吐。
宿主机物理盘、zvol、进程指标需相互验证,不能相加。
## 后续观察
从 [Grafana](../services/grafana.md) 的 Homelab 内存与 Swap 面板查看 ARC、PSI 与换页,
对照 winadmin 下次自动更新及数据库延迟。必要时再调整缓存预算或 VM I/O 策略。
当前未改变 runner fail-fast、Windows 自动更新、swap 或 VM I/O 上限。
ARC 上限不是 ZFS 全部内存的硬上限;已有 swap 占用不会因为降低 ARC 自动清零。
+49
View File
@@ -0,0 +1,49 @@
---
title: 证书、秘密同步与 GitOps 监控
last_reviewed: 2026-09-25
---
# 证书、秘密同步与 GitOps 监控
采集与规则由 observability Flux Kustomization 管理,以 ServiceMonitor、PodMonitor 和
PrometheusRule 声明;VM Operator 转换后交给 vmagent/vmalert。
通知和静默入口见 [Grafana](../services/grafana.md#从告警进入-grafana)。
## 采集与阈值
| 对象 | 采集 | 告警 |
|---|---|---|
| cert-manager controller | ServiceMonitor,:9402,job=cert-manager | Certificate Ready=True 的值为 0 持续 15m;到期不足 7 天且至少 1 天 warning 15m;不足 1 天(含已过期)critical 5m |
| ESO 三个组件 | PodMonitor,:8080,以各组件名称为 job | ExternalSecret Ready=True 值为 0 持续 10m;ClusterSecretStore 同条件 5m critical |
| Flux 四个 controller | PodMonitor,:8080,以 controller 名称为 job | 八个已接入 controller job 各自 down 或整个 job 消失 5m warning |
| Flux 六类对象 | KSM 自定义资源状态 gotk_resource_info | 非暂停对象未 Ready 持续 15m;根 Kustomization 状态指标消失 5m |
controller 存活规则共 8 条,状态与证书规则共 7 条。证书 warning 和 critical 范围互斥。
采集使用 honorLabels,证书和 Secret 的 namespace/name 是被观测对象,不能覆盖为 exporter 命名空间。
目前只采集 cert-manager controller;webhook/cainjector 继续依赖通用 workload 健康规则。
Flux 自定义指标覆盖 Kustomization、HelmRelease、GitRepository、HelmRepository、HelmChart、
OCIRepository。KSM 只增加这些资源与 CRD 发现所需的 list/watch,保留 Kubernetes collectors。
resource_namespace 保存对象命名空间。suspended=true 排除;默认省略 suspend 仍参与判断。
OCI 类型 HelmRepository 正常没有 Ready 条件,repository_type=oci 排除;OCIRepository 本身仍检测。
不以旧 gotk_reconcile_condition 指标编写规则,也不通过告警自动解除暂停或修改配置。
## 排障
- 证书:先查 Certificate conditions,再沿 CertificateRequest、Issuer、Order、Challenge 找原因。
本规则只覆盖 cert-manager 管理的证书,不证明实际 HTTPS 入口已经加载新证书。
- Secret 同步:查 ExternalSecret/ClusterSecretStore conditions 与 ESO 日志,核对 provider 网络、身份和授权;
不输出 Secret 内容。旧的成功副本可能仍可用,但不能据此认为后续轮换可靠。
- Flux:按 customresource_kind、resource_namespace、name 定位对象,查 conditions 与依赖。
15m 用于容忍正常升级。主动维护使用暂停或有期限的静默,禁止永久屏蔽失败。
- 指标缺失:依次看原生监控 CR、转换对象、targets、即时查询和 KSM 的 RBAC/配置日志。
up==0 不能发现已移除目标,因此各预期 job 另用 absent 检测;同 job 单副本以外的拓扑缺失仍有盲点。
实现:[PR #160](https://git.ddupan.top/panxiao81/homelab-infra/pulls/160)、
[OCI 例外 #161](https://git.ddupan.top/panxiao81/homelab-infra/pulls/161)。
上游依据:[Flux 自定义指标](https://fluxcd.io/flux/monitoring/custom-metrics/)。
19 个规则语义测试覆盖暂停、缺省 suspend、OCI 例外、证书级别切换及 ESO 状态零值等。
2026-09-25 现场已确认这 8 个 controller target up,4 个证书到期样本、12 个 Ready Secret 状态样本,
KSM 已输出 Flux 对象状态。未人为使生产证书过期或中断 Secret 同步;通知链路沿用此前端到端验收。
最终 Flux 应用版本为 `655ca567baa58767fcb6a0fd45c78c1044c2b95f`,KSM HelmRelease Ready。
+140
View File
@@ -0,0 +1,140 @@
---
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)。
下面的规模、矩阵和盲点保留初轮盘点基线,不能再当作第一批实施后的现状。
第二批已补 [证书、ESO 与 Flux](monitoring-controllers.md) 的 15 条规则,
以及 [CNPG、NATS 与 SeaweedFS](monitoring-data-services.md) 的 14 条规则和 12 个新采集目标。
OpenBao 已完成受鉴权 telemetry、ServiceMonitor 与采集不可用规则,维护者人工解封后验收通过;
并修复快照续期、生成维护前快照及 VM 外副本;随后增加内部健康和独立 node_exporter
快照失败/新鲜度/指标缺失告警,详见 [维护 runbook](openbao-monitoring-maintenance.md)。
备份独立验收、NATS consumer 维度、外部探测和集群外心跳仍待补齐。
## 证据和范围
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、数据库迁移与身份平台;本次盘点不授权自动修改这些项目。
+48
View File
@@ -0,0 +1,48 @@
---
title: CNPG、NATS 与 SeaweedFS 监控
last_reviewed: 2026-09-25
---
# CNPG、NATS 与 SeaweedFS 监控
本批仅增加指标采集与 14 条 PrometheusRule 告警,数据库范围按维护者要求限于 CNPG。
共享 Patroni PostgreSQL 与 etcd 的变更由对应任务管理。
## 采集与规则
| 服务 | 采集与范围 | 告警 |
|---|---|---|
| CNPG shared-db/shared-postgresql | PodMonitor 抓取已有实例 :9187,job=cnpg | exporter/目标不可用 5m critical;PostgreSQL down 2m critical;SQL 采集错误 5m;连接使用率 >80% 10m;非 idle 事务超过 300s 持续 5m |
| NATS | 沿用 job=nats/nats | JetStream 服务端文件或内存容量 >80% 10m;10m 内慢消费者计数增加并持续 5m |
| SeaweedFS | ServiceMonitor 仅选择 master/filer/volume 三个服务的 :9327 | 各组件采集不可用 5m critical;volume 可用磁盘 <10% 10m;因磁盘不足限制写入 5m critical;5m 内写失败增加持续 2m |
CNPG 使用内置 exporter,不新增数据库账号、不改数据库实例配置、不执行业务写入。
连接数按 Pod 汇总数据库与用户,再除以同实例 max_connections;长事务排除普通 idle 连接。
当前单实例没有复制冗余,不添加必然无法满足的副本告警。本批没有建立或验证备份流程。
NATS 本批是服务端容量,不能代替 Account、stream 限额与 consumer pending/redelivery 监控。
当前 exporter 未输出这些 consumer 维度,后续需明确 exporter 开关与业务阈值再补。
慢消费者使用增量,历史累计值不持续触发。
SeaweedFS 排除 filer-client 的重复发现,组件分别使用 seaweedfs-master/filer/volume job。
只把 isDiskSpaceLow 视为这条只读故障,避免满卷轮转或主动只读造成误报。
这些指标不证明 S3 请求端到端成功,也不证明副本和异机备份可恢复。
## 使用与故障定位
在 [Grafana Explore](https://grafana.ad.ddupan.top/explore) 选择 VictoriaMetrics,可查询:
```promql
cnpg_collector_up{job="cnpg"}
```
预期 CNPG 实例值为 1。告警中的 pod/namespace 对应数据库实例;先看 CNPG Cluster conditions、
Pod 日志及 PVC,再查连接池和事务。禁止仅为消除告警盲目提高连接上限或终止业务事务。
NATS 先查服务端配额、保留策略和消费者处理能力;不同 Account 的队列必须分别解释。
SeaweedFS 先查 volume 文件系统/ZFS 与日志,不能直接删除底层卷文件。
通知和临时静默见 [Grafana](../services/grafana.md#从告警进入-grafana)。
实现:[PR #160](https://git.ddupan.top/panxiao81/homelab-infra/pulls/160)。
2026-09-25 现场确认新增 CNPG 与 SeaweedFS 共 4 个 target up,CNPG collector_up=1,
SeaweedFS 容量指标有当前样本;NATS 沿用已验证采集。新增规则无评估错误。
测试覆盖连接数聚合、磁盘指标 type 标签匹配及慢消费者历史值;未制造生产数据库/磁盘故障。
+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 不在本批修复范围。
+264
View File
@@ -0,0 +1,264 @@
---
title: OpenBao 监控接入维护 runbook
last_reviewed: 2026-09-25
---
# OpenBao 监控接入维护 runbook
用于本次 OpenBao 自身指标接入中央监控。2026-09-25 维护者要求现在开始准备维护,
先完成顺序和 runbook;本文同时保留执行顺序与最终验收,实际完成范围见下方“本次执行状态”。
建议从明确宣布开始计时预留 30 分钟,实际起止记录 UTC,并注明维护者当地时区。
维护者确认使用人工解封:解封材料保存在 Bao VM,经 GPG 加密,解密私钥由 YubiKey 持有。
文件确切位置、封装格式以及是否另有残留明文未核实;agent 不搜索或读取这些材料。
解密、PIN/触摸确认和提交 unseal share 由维护者在自己的终端完成。
## 本次执行状态(2026-09-25)
维护者已确认 YubiKey 解密可用并明确同意进入重启/人工解封交接。
20:34:42 UTC 应用已校验 telemetry 配置并重启,随后维护者完成 unseal。
现场确认 initialized=true、sealed=false、health=200、受鉴权 Prometheus metrics=200,
cluster_id 与维护前一致,匿名 metrics 仍为 403。
停机前已更换失效的快照 token,修正每日续期命令为现场支持的 `bao token renew`(不带 -self)。
新快照 `openbao-20260925-203149.snap` 为 183334 bytes,VM 外副本保存在管理工作站
`/home/panxiao81/.local/state/openbao-maintenance/`,权限 0600,SHA-256 一致。
这是配置维护前的备份核验,不等于完成异机灾难恢复演练。
快照 service Result=success、timer active;文件只在写入成功后更名,失败不清理旧快照。
metrics policy/role 已按候选源配置应用:实际 vmagent-main SA 登录与 token 续期成功,
无权读取业务 Secret,测试 token 已撤销。随后已将 `vault_policy.metrics` 与
`vault_kubernetes_auth_backend_role.metrics` 导入现有 SeaweedFS S3 主远端 state,
仅针对这两项的 plan 均为 no-op;这不代表整个 Terraform 配置已经全量 zero-diff。
重启后 ClusterSecretStore 和 12 个 ExternalSecret Ready;monitoring/alertmanager-telegram
已定向刷新,refreshTime 更新为 20:39:33 UTC,状态 SecretSynced。
[PR #162](https://git.ddupan.top/panxiao81/homelab-infra/pulls/162) 已合并,Flux 应用
`834f65494195ba5e139e1fc6ee0221fd705b9656`,vmagent 新 Pod 3/3 Ready。
Bao Agent 日志确认自动登录成功、token 写入内存卷及首次自动续期成功;up{job="openbao"}=1,
已观察连续三次 up=1,当前指标可查询,单次抓取约 636 个样本,OpenBaoMetricsUnavailable 规则已加载,无评估错误。
本次未设置维护静默,无需清理 silence;没有撤销维护者自己的登录会话。
真实长周期重新登录、快照未来定时运行和独立灾难恢复演练不包含在本次验收内。
以下保留操作顺序和回滚方法;其中“待执行”描述须结合本节判断,不能重复重启。
## 内部健康和快照日常监控
2026-09-25 后续部署未重启 Bao(启动时间仍为 20:34:43 UTC)。真实快照任务
Result=success、退出码 0,新快照 194598 bytes;VM 指标报告 success=1、textfile scrape error=0。
Flux 已应用 `7137426e8f5c99ca1514c508501e07c2066dd769`;API 和 VM exporter 两类 target 均为 up,
快照结果与成功时间已进入 VictoriaMetrics。21:02:27 UTC 六条 OpenBao 规则均 inactive,
部署初期缺数据 pending 已解除;全栈 108 条规则无评估错误。Ansible 部署后 check mode 零变更。
本次通过 28 个告警语义场景及 4 个快照脚本测试,未通过制造真实故障验证 Telegram。
[PR #163](https://git.ddupan.top/panxiao81/homelab-infra/pulls/163) 补齐内部健康、健康 gauge 缺失、
快照失败、快照超时/无成功记录和快照采集失联五条规则;原有受鉴权采集不可用规则保留。
仍由 ServiceMonitor 和 PrometheusRule 声明。内部 active 判定面向当前单节点,扩容为多节点前需修改。
VM 使用 Ubuntu node_exporter,监听 `192.168.10.8:9100`;没有公共入口,当前 UFW 未启用,
LAN 地址绑定不是逐来源 ACL。采集标签为 `job=node-exporter,node=bao1`,复用主机内存和文件系统规则。
textfile 目录 `/var/lib/prometheus/node-exporter/` 只由 root 写入,指标不带 token 或快照内容。
独立 exporter 在 Bao sealed 或快照 token 失效时仍能报告快照结果。
每日任务失败会记录 result=0,保留旧的最后成功时间;只有完整快照原子更名后才更新成功时间并清理旧文件。
失败持续 5 分钟为 warning,距最后成功超过 36 小时或没有成功指标持续 15 分钟为 critical;
exporter 失联、textfile 解析错误、结果指标缺失持续 5 分钟为 warning。
本地快照成功不等于已复制到独立故障域,更不等于恢复演练通过。
部署和回滚使用独立的 `ansible/monitor-openbao.yml`,只处理 exporter、快照脚本和 timer;
不改 Bao 服务配置,不轮换 token,不需要再次人工解封。首次部署必须执行一次真实快照建立基线。
参数、验证命令与回滚边界见
[源码监控运维说明](https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/infrastructure/openbao/MONITORING.md)。
## 目标、分工与影响
- 执行者:准备配置与采集声明、检查、备份核对、部署、观测和配置回滚。
- 维护者:确认 GPG 文件与 YubiKey 可用、人工解封;整个重启及回滚期间保持在线。
- 本次只涉及 telemetry、最小权限采集身份与必要采集/告警,不升级 Bao、不改 seal 类型、
不重新初始化、不轮换解封密钥,也不恢复 Raft 数据。
- 停机或 sealed 期间,秘密读取、动态凭据签发/续租、PKI/ACME 和 Bao 登录不可用。
已投射的 Kubernetes Secret 不会因 Bao sealed 自动消失,但 ESO 刷新会失败;
不能保证所有依赖应用都无影响,窗口内避免启动依赖新凭据的部署和轮换。
- Telegram 使用现有挂载 token,预计仍可发通知;维护前核对,不能把“预计”当作保证。
## 顺序与交接点
| 顺序 | 负责方 | 操作和通过条件 |
|---|---|---|
| 1,停机前 | 执行者 | 核对版本、运行配置来源、seal 状态和受鉴权 metrics;判断是否真的需要重启 |
| 2,停机前 | 执行者 | 准备并审查 IaC 差异、采集身份及续期方式、监控 CR 与回滚配置;离线校验通过 |
| 3,停机前 | 维护者 | 在自己的终端确认 YubiKey 解密路径可用、所需 share 数量可满足,回复“人工解封已就绪” |
| 4,停机前 | 执行者 | 确认独立 VM 登录/控制台、快照与配置备份、依赖基线;所有恢复材料不依赖运行中的 Bao |
| 5,T+0 | 双方 | 明确宣布窗口开始,记录时间;只对预期告警设置 30 分钟到期的精确静默 |
| 6,T+0~5m | 执行者 | 应用已审查配置;若确需重启,只重启一次,确认进程启动及 sealed 状态后立即交接 |
| 7,T+5~10m | 维护者 | YubiKey 解密并人工 unseal,直到 initialized=true、sealed=false;不向 agent 发送 key |
| 8,T+10~20m | 执行者 | 验证 Bao 和依赖恢复,再上线/验证受鉴权采集、规则及凭据自动续期/重新登录 |
| 9,T+20~30m | 双方 | 满足验收则结束窗口;否则停止扩大变更,按下述回滚/故障分支处理 |
时间段是预算,不是自动执行信号。维护者没有完成解封准备时,不执行重启。
若受鉴权检查表明现有 telemetry 已满足需求,直接完成无需停机的采集接入,不为走流程重启。
## 1. 停机前检查
从能够验证 TLS 的客户端检查,无需登录或解封材料:
```bash
export BAO_ADDR=https://bao.ad.ddupan.top:8200
bao status -format=json
```
记录 initialized、sealed、seal 类型、threshold、版本和节点身份,不从旧初始化示例推断 threshold=1。
`bao status` 在 sealed 时通常返回退出码 2;不能把这个预期状态当作进程崩溃。
若已经异常 sealed 或 initialized=false,停止本次常规维护,先定位现有故障,绝不执行 init。
在 VM 上确认服务状态、实际二进制和配置路径,不输出配置中的秘密:
```bash
sudo systemctl is-active openbao
sudo systemctl show openbao -p MainPID -p ExecMainStatus
/usr/local/bin/bao version
```
仓库默认配置路径 `/etc/openbao/config.hcl`、数据路径 `/opt/openbao/data`;执行前核对现场。
保持一条已建立的 VM 管理会话,并确认断开后仍能通过独立控制台或既有维护身份恢复访问。
不要依赖 Bao 在停机期间签发新的 SSH 凭据。
受鉴权请求 `/v1/sys/metrics?format=prometheus`,只记录 HTTP 状态、格式和必要指标名。
此前匿名请求返回 403,只证明访问受限;模板未显式写 telemetry 也不等于运行时禁用了它。
鉴权材料只通过受控内存/文件引用传递,不放命令行、Git 或日志。
## 2. 配置与采集准备
如确需显式配置,候选最小变更为:
```hcl
telemetry {
prometheus_retention_time = "5m"
disable_hostname = true
}
```
采集间隔规划为 30 秒。以上是待审查片段,需按现场版本校验;已有 telemetry 配置应合并,
不要重复添加。保留 TLS、Raft、seal、认证与现有 listener 设置。
指标标签和前缀以实际返回为准,不能预先假设所有指标都以 bao_ 开头。
采集身份限定 `sys/metrics` GET 所需 read 能力,先验证权限和实际请求;不要复用 root token,
也不开放匿名 metrics。明确身份取得、自动续期/重新登录与重启恢复方式后,才认为采集准备完成。
优先复用现有机器身份机制;若需 agent/proxy,应在窗口前写好最小配置并验证访问边界,
不在停机后临时决定长期 token 或新增服务架构。
监控声明优先 ServiceMonitor/PodMonitor/PrometheusRule;外部 VM 的发现方式应与最终采集架构匹配。
HTTPS 使用正确域名/CA,不关闭校验;metrics path 为 `/v1/sys/metrics`,`format=prometheus`
放 query params,不能把问号串在 path 里。sealed 期间 metrics 不可用,因此还需独立 health/目标缺失检测,
不能仅靠 Bao 内部指标证明 sealed 状态可被发现。
配置见 [PR #162](https://git.ddupan.top/panxiao81/homelab-infra/pulls/162),已合并部署,状态以本次执行记录为准。
使用绑定 monitoring/vmagent-main 的 Kubernetes auth metrics role,由 Bao Agent sidecar 自动登录/续期,
token 仅存 Pod 内存卷供 vmagent 只读消费。采集用 ServiceMonitor + 外部 Service/Endpoints;
现有 converter 的 Endpoints 发现保留,EndpointSlice 迁移另行处理。
role 权限、认证/首次续期与受鉴权 metrics 已验收;未来维护仍须重新核对现场,不只依靠历史记录。
使用现场版本支持的配置校验方式,先检查对应命令 help;禁止启动第二个 server 验证同一 Raft 数据目录。
现有 Ansible 写配置会通知 restart,不能把正式 apply 当作无停机预演。
## 3. 回滚材料与维护静默
- 以 root-only 权限备份实际配置,记录原权限/属主和 checksum;备份留在独立可访问的管理位置。
不把完整配置贴到聊天或 wiki。
- 使用已有快照流程核对最近成功快照;必要时在停机前生成一次并检查退出状态、文件大小、校验和和副本可访问性。
现有来源为 `openbao-snapshot.service` / timer 与 `/usr/local/bin/bao-snapshot.sh`,先核对现场存在再运行。
不打印 snapshot token;快照文件存在不等于恢复演练成功。
- 记录 ESO ClusterSecretStore 与 ExternalSecret 当前状态、refreshTime,以及代表性认证/PKI 流程的基线。
- 在 Grafana 选择外部 Alertmanager,仅对 `ClusterSecretStoreNotReady{name="openbao"}` 及已确认受影响的
ExternalSecret 精确设置限时静默,记录 silence ID。不要静默全部 critical、Telegram 发送故障或无关服务。
## 4. 重启与人工解封
仅在前置条件全部满足且窗口已明确开始后,由执行者在 VM 执行:
```bash
sudo systemctl restart openbao
sudo systemctl is-active openbao
```
随后检查 `bao status`。服务 active 而 sealed=true 是人工解封流程的预期交接点,
此时停止自动操作,告诉维护者“Bao 已启动,等待人工 unseal”。
维护者在自己掌控、无录屏/日志采集的终端按既有 GPG 流程解密所需 share,随后使用隐藏输入提示:
```bash
export BAO_ADDR=https://bao.ad.ddupan.top:8200
bao operator unseal
bao status
```
按现场 threshold 提交足够的不同 share。不要使用 `xargs bao operator unseal`、命令替换或明文参数,
也不要把解密结果交给 agent。仓库旧初始化示例中的 xargs 方式不用于本次维护。
加密文件可能是 GPG 文件、base64 包装 share 或初始化 JSON;由维护者按真实格式处理,本文不猜文件路径或格式。
完成后只回报 sealed=false 与非敏感状态;清理自己产生的临时解密副本/剪贴板,不删除原始加密备份。
## 5. 验收与结束
必须逐项记录结果,不以 systemd active 代替可用性:
1. initialized=true、sealed=false,节点/集群身份未变化,TLS 校验正常;预期 active 节点健康接口成功。
2. 既有机器身份登录正常;代表性秘密消费/PKI 流程按既有权限验证,结果不输出秘密。
3. ClusterSecretStore/openbao Ready;窗口前健康的 ExternalSecret 恢复 Ready,并观察一次新的实际刷新。
需要加速时选择一个受影响对象触发 reconcile,不把所有 ESO 对象批量强制刷新。
4. 受鉴权 metrics 返回有效 Prometheus 数据,匿名请求仍被拒绝;中央 target 连续至少三次 up,关键指标有当前样本。
5. 采集身份续期/重新登录机制验证通过;规则已加载且无评估错误,目标消失/鉴权失败有可识别告警。
6. 若做临时告警演练,标注维护测试并记录 firing/resolved;没有做真实故障演练时明确注明。
7. 取消本次 silence,记录窗口实际结束时间、配置 commit/PR、验证与未完成项,更新来源文档。
## 6. 停止与回滚分支
- 新配置校验失败:不应用、不重启,修正候选配置。
- 重启后进程无法启动:检查有限范围日志,恢复原配置及权限,再启动服务;维护者仍需准备 unseal。
- 进程已启动但 YubiKey/解密/份额不可用:停止反复重启,维护者处理解封流程。
恢复旧配置不会自动解封;若接近窗口截止则按故障处置,不能宣布回滚已恢复。
- Bao 已恢复,仅采集鉴权/指标失败:优先撤回新增采集配置/身份变更,保持核心服务可用;
不为修监控反复重启 Bao。记录监控尚未完成,安排后续修复。
- 必须恢复原服务配置时:恢复备份、重启、再次人工解封,并重复核心与依赖验收。
- 本次配置回滚不包含 Raft snapshot restore、清空数据目录、init、rekey 或 seal migration。
## 来源与证据边界
维护者 2026-09-25 确认 VM 保存 GPG 加密解封材料,YubiKey 解密且需人工 unseal。
本轮已进行只读预检及候选文件准备;没有读取解封材料、替换运行配置、设置静默或执行重启。
### 2026-09-25 停机前预检
- Bao API 与 VM 二进制均为 2.6.1,Shamir threshold/shares 为 1/1,initialized=true、sealed=false。
- 管理入口为 `ssh [email protected]`,sudo 可用。按维护者明确要求,将管理工作站
panxiao81 的 authorized_keys 中两条受信任公钥追加到 VM 的 ansible 用户,保留原公钥,
修改前已在该账号 `.ssh/` 备份 authorized_keys;此次是现场授权变更,尚未纳入 cloud-init/IaC。
- 运行配置未显式设置 telemetry。原配置与候选文件分别保存为 VM root-only 目录
`/etc/openbao/maintenance-monitoring-20260925/config.before.hcl`、`config.candidate.hcl`。
候选文件通过现场 `bao operator validate-config -config=...`;原运行配置未变。
若后续其他任务改动运行配置,必须重新比较后再使用,不能覆盖新改动。
- 快照服务 9 月 23–25 日日志均为 403,9 月 25 日退出码 2;默认 `/var/backups/openbao`
未发现 .snap。尚未证明存在其他有效副本,此项阻止进入重启。
- 源码快照使用 periodic token,但没有续期步骤。候选补丁增加每日续期、显式 rotate 开关、
私有 partial 文件及成功后原子更名;403 的精确原因仍需检查 token 状态,不能直接断言已过期。
- 当前本地 Bao 管理员会话不可用;受鉴权 metrics、Terraform plan/apply、快照身份恢复待完成。
- 候选通过 Kustomize、规则检查、server dry-run、Terraform fmt;Agent 只在关闭的本机端口验证
解析/启动,未做真实登录。快照模拟测试验证续期失败与写失败不删旧备份,成功才清理保留数量。
源码:[OpenBao 部署与恢复入口](https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/infrastructure/openbao/README.md),
配置模板与 restart handler 位于同目录 `ansible/roles/openbao/`。
命令依据:[人工 unseal](https://openbao.org/docs/2.6.x/commands/operator/unseal/)、
[telemetry 配置](https://openbao.org/docs/2.6.x/configuration/telemetry/)。
### 人工解封准备确认
维护者已在插有 YubiKey 的 working PC 成功验证解密。VM 的 `/home/ansible/unseal.txt`
包含带 `Unseal Key 1:` 前缀的 base64 GPG 密文;正文不保存其内容。
实际解封由维护者在 working PC 解密后通过 HTTPS 提交,不能将密文直接当作 unseal key。
这次验证未执行解封或重启。
随后只读确认:快照 token 的 lookup-self 也返回 403,VM root 没有可用的 Bao CLI 会话。
需要维护者先登录管理会话,恢复快照身份并完成受鉴权预检后才能进入停机。
若在 VM 使用 OIDC CLI 登录,应从 working PC 建立
`ssh -t -L 8250:127.0.0.1:8250 [email protected]`,再在 VM 的 root shell 设置
`BAO_ADDR=https://bao.ad.ddupan.top:8200` 并运行 `bao login -method=oidc -no-print role=admin`。
登录网址在 working PC 浏览器打开,账号需符合现有 vault-admins 组约束;不把 token 发给 agent。
+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)。
+65
View File
@@ -0,0 +1,65 @@
---
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 同步目前按维护者要求暂缓,不将其列为每次任务的前置条件。
- [证书、秘密同步与 GitOps 监控](monitoring-controllers.md):证书临期、ESO 同步与 Flux Ready 排障。
- [CNPG、NATS 与 SeaweedFS 监控](monitoring-data-services.md):数据库连接、消息容量与存储故障。
- [OpenBao 监控接入维护](openbao-monitoring-maintenance.md):窗口准备、YubiKey 人工解封交接与回滚。
+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 title: Authelia
lifecycle: active lifecycle: active
evidence: documented evidence: documented
last_reviewed: 2026-09-16 last_reviewed: 2026-09-25
last_verified: null last_verified: null
sources: sources:
- 维护者于 2026-09-16 确认当前状态 - 维护者于 2026-09-16 确认当前状态
@@ -10,8 +10,10 @@ sources:
# Authelia # Authelia
**Authelia 已作为 homelab 唯一的主 OIDC broker 工作,当前状态为 active。** **Authelia 继续作为 homelab 的主 OIDC 入口与人类认证后端工作,状态为 active。**
此状态由维护者于 2026-09-16 明确,本轮未查询运行环境。 基础状态由维护者于 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 title: Gitea Dynamic Runner
lifecycle: experimental lifecycle: experimental
evidence: documented evidence: documented
last_reviewed: 2026-09-16 last_reviewed: 2026-09-21
last_verified: null last_verified: null
sources: sources:
- https://git.ddupan.top/panxiao81/gitea-dynamic-runner/src/branch/main/README.md - 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 # Gitea Dynamic Runner
@@ -17,9 +19,23 @@ microVM;每个环境只执行一个 job,结束后销毁环境及本地状态
更名由维护者提供;以下组件与接口说明依据 2026-09-16 查阅的项目 README。 更名由维护者提供;以下组件与接口说明依据 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 如何选择执行环境 ## workflow 如何选择执行环境
README 定义两种稳定接口,在 workflow 的 job 中选择: 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 后关机并清理 | | `vm` | 动态 Cloud Hypervisor microVM | 每个任务创建独立 COW disk、seed 和 TAP,guest runner 执行一个 job 后关机并清理 |
两种接口不能仅凭“环境一次性”就认定具有相同的隔离边界。 两种接口不能仅凭“环境一次性”就认定具有相同的隔离边界。
接入前需要结合项目设计约束和实际部署确认任务的信任范围。 接入前需要结合项目设计约束和实际部署确认任务的信任范围。
旧 homelab-infra 文档中的 `kind-microvm` 是早期记录,不作为本项目当前 workflow 接口。 旧 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 路径为: 当前 README 描述的 bootstrap 路径为:
@@ -80,6 +106,16 @@ workflow 决定如何消费身份:登录哪个服务、请求哪个 audience
不属于 runner 内置的业务流程。向其他服务请求 token 也遵循同一边界; 不属于 runner 内置的业务流程。向其他服务请求 token 也遵循同一边界;
runner 不应替 workflow 选择下游 role/policy,或统一代理其业务凭据交换。 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 能否取得各自身份和是否保持隔离; 因此,身份相关的环境验收应关注 Pod/VM 能否取得各自身份和是否保持隔离;
具体服务的登录与 token 使用由对应 workflow 验收。 具体服务的登录与 token 使用由对应 workflow 验收。
本段记录设计职责,不表示获取身份的能力已经在所有 backend 完成实现或现场验证。 本段记录设计职责,不表示获取身份的能力已经在所有 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 指向的完整设计约束,本轮未逐篇复核。 - [设计原则](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 指向的长期调度路线与迁移边界,本轮未逐篇复核。 - [Runner 协议路线](https://git.ddupan.top/panxiao81/gitea-dynamic-runner/src/branch/main/docs/runner-protocol-roadmap.md):README 指向的长期调度路线与迁移边界,本轮未逐篇复核。
- [SPIFFE/SPIRE](spire.md):统一机器身份的设计定位与阶段依据。 - [SPIFFE/SPIRE](spire.md):统一机器身份的设计定位与阶段依据。
- [`ci-actions@v1`](https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1):workflow 可复用的 SPIFFE/OpenBao 登录与 Nexus 配置 Action。
实际启用范围、workflow 验收、排障及消息队列约定在项目文档中维护。 实际启用范围、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)。
+173
View File
@@ -0,0 +1,173 @@
---
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)。
宿主机 ARC 的 4 GiB 预算、应用方式及验证边界见[ARC 内存预算](../guides/laptop-arc-budget.md)。
+161
View File
@@ -0,0 +1,161 @@
---
title: Hydra 与 OIDC 上游适配器
lifecycle: experimental
evidence: live-verified
last_reviewed: 2026-09-27
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 入口,不删除用户或原有认证配置。
### 独立登录服务的 AD 接入
`iam-login` 的人类界面沿用内联上下文与原生表单,新增 AD 第一因素验收入口;
以用户身份 LDAPS bind,读取 objectGUID 和直接 `memberOf`,组名保持原样。
当前不展开嵌套组或主组,不能视为已完成与 Authelia 的有效组集合等价验证。
密码成功仅代表第一因素通过;Gitea 仍使用上面已验收的 Go/Authelia 路径。
按 2026-09-27 明确的实现边界,React 只替换 Spring Security 默认 UI,密码 POST、
因素状态和认证会话交由框架管理。待 MFA 页面要求近期密码因素,尚未实现的应用入口拒绝访问。监控 Basic 认证与人类登录会话隔离。
本轮开发验证通过 JVM 测试,并从 JVM 通过 CA/域名验证读取真实 AD RootDSE。
2026-09-25 维护者已在 HTTPS 开发入口完成真实密码验证,成功进入待 MFA 页面,
并反馈目录标识、邮箱及六个直接所属组的查询结果。此人类验收只覆盖 AD 第一因素与
属性读取,不包括 MFA 或 Hydra 登录。新增路径尚未跑 Native;日常迭代不要求每轮原生编译。开发入口使用受限 Tailscale HTTPS,属于临时验收实例,不是生产入口。
AD 接入与 Spring Security 重构统一见 [iam-login PR #4](https://git.ddupan.top/panxiao81/iam-login/pulls/4);
2026-09-27 通过 18 项 JVM 测试和 1 项浏览器回归,后续真实人类验证反馈见下方 WebAuthn 开发验证。
配置、边界与使用方式见
[iam-login AD 接入文档](https://git.ddupan.top/panxiao81/iam-login/src/branch/main/docs/ad-login.md)。
### WebAuthn 开发验证
2026-09-27 的 [iam-login PR #6](https://git.ddupan.top/panxiao81/iam-login/pulls/6) 将第二因素接入
Spring Security 官方 WebAuthn 流程,并以官方 JDBC 仓储和本地 PostgreSQL 持久卷保存凭据。
该实现仍在开发 PR,生产 Go/Authelia 链路未切换。
开发入口仍为 `https://laptop.tail7e769.ts.net:18082/signin`,限 Tailscale 可达。
先验证 AD 密码,首次使用注册 passkey,再实际验证 passkey;注册成功本身不通过 MFA。
已有凭据后的新增注册要求现有 MFA;本轮 UI 不开放凭据管理、删除或自助恢复。
当前真实 AD 开发实例的 `/signin/complete` 显示双因素结果,尚未配置 Hydra 授权接入;
新增 Login/Consent 的代码与隔离验证见下文。
2026-09-28 维护者明确首轮自用边界:AD 用户、密码和组继续使用 RSAT/命令行管理;
丢失全部 MFA 时由管理员核实身份后人工操作目标主体的数据库凭据恢复。
不开发目录管理、自动恢复或完整 self-service UI,也不将其作为核心人类链路验收前提。
22 项 JVM 测试与 Chromium 虚拟认证器流程通过,覆盖再次登录、注册限制、会话轮换、
challenge 过期/消费、断言重放及跨主体凭据拒绝。真实开发 HTTPS 页面的证书与表单回归
已检查。维护者随后在该开发入口完成验收,反馈“我验收完了,看样子能工作”;
据此记录 AD + passkey 人类浏览器路径已获维护者确认。此反馈不构成 Native、数据库
重启恢复或 Hydra/Gitea 新链路验收,也未限定认证器型号与跨设备兼容范围。
数据库开发操作、数据卷保留与失败边界见
[WebAuthn 文档(开发分支)](https://git.ddupan.top/panxiao81/iam-login/src/branch/feat/webauthn-mfa/docs/webauthn.md)。
### 独立登录服务的 Hydra 接入
双因素后的 Login/Consent、客户端管理与统一注销已提交至
[同一 iam-login PR #6](https://git.ddupan.top/panxiao81/iam-login/pulls/6),源码版本为
[62b6e9d](https://git.ddupan.top/panxiao81/iam-login/commit/62b6e9d),尚未合并或切换生产入口。
2026-09-28 已通过 36 项 JVM 测试与隔离 Hydra v26.2.0 的浏览器授权码及注销流程:
模拟 AD → WebAuthn → 原生表单确认 → Hydra code → 客户端兑换并验签 ID token。
验证覆盖 issuer、audience、nonce、显式配置的旧 subject、直接组 claims 与授权码重放拒绝;
独立 MFA 路径此前也通过浏览器回归。本轮另验证客户端 CRUD、Hydra 重启后的 PostgreSQL
持久化、更新保留密钥、管理权限/CSRF 拒绝、再次授权确认、注销通知签名与 sid 关联,以及
Spring 本地会话失效。这些是测试夹具结果,不是生产 Gitea 验收。
生产主体按 AD authority + objectGUID 显式绑定现役 Hydra sub,未绑定账号拒绝授权;
不靠邮箱、用户名或自动新建账号迁移。生产映射值尚未取得并核实,现役入口未切换,
AD/WebAuthn/Hydra 的 Native 完整链路也仍待验收。配置与迁移条件见
[Login/Consent 文档(开发分支)](https://git.ddupan.top/panxiao81/iam-login/src/branch/feat/webauthn-mfa/docs/hydra-login.md)。
Hydra 持有客户端注册表并提供 CRUD Admin API;新增客户端不依赖修改服务器配置文件。
管理能力由 iam-login 的 `clients` 领域模块包装:Spring session、有效 MFA 与显式直接管理组
控制访问,写操作保留 CSRF;不公开 Hydra admin 或任意代理。本地实现中的客户端与密钥只存
Hydra PostgreSQL,启用标记写入 client metadata 并在授权时重新读取。旧配置 allowlist
只作无标记客户端的过渡兼容,不是第二份注册表。暂不建设完整自助管理 UI。
统一注销计划沿用 Hydra 登记的 front/back-channel 协议;登录服务通过 Spring 清除当前
本地会话。Hydra 必须保留登录会话以关联注销;仅凭 issuer 的 remembered-login 标记不能
绕过本地 MFA。下游不支持注销协议、通知失败或 issuer 会话已过期时,不能声称所有应用均
已退出;不等同撤销全部 token 或其他设备会话。
正式入口目标是替换现役 `auth.ddupan.top`,Hydra public 与 iam-login UI/API 按路径共用
origin,仍保持独立部署。不能把整个 `/oauth2/**` 都路由给 Hydra,也不发布 admin 路径。
上线前需审查 issuer 与现有账号关联、cookie/TLS 转发、WebAuthn RP ID 与凭据重新注册、
回退路由;这是部署计划,现有 Go/Authelia 生产链路未改变。
+37 -31
View File
@@ -1,49 +1,51 @@
# 服务总览 # 服务总览
审阅日期:2026-09-16。以下覆盖源码工作区 apps/、platform/、infrastructure/ 的一级组件,以及集群入口。 审阅日期:2026-09-18。以下覆盖源码工作区 apps/、platform/、infrastructure/ 的一级组件,以及集群入口。
**除旧 VictoriaMetrics Compose 已获授权做有限现场检查外,其余条目未在本轮现场验证。** **除旧 VictoriaMetrics Compose 已获授权检查并清理外,其余条目未在本轮现场验证。**
状态栏区分维护者说明、文档、ticket、配置与现场证据,不提供持续的实时健康判断。 状态栏区分维护者说明、文档、ticket、配置与现场证据,不提供持续的实时健康判断。
SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护者说明更新, SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护者说明更新,
独立项目按指定 README 收录。其余条目仍为初轮工作区盘点,查询前先向维护者对齐。 独立项目按指定 README 收录。其余条目仍为初轮工作区盘点,查询前先向维护者对齐。
来源路径相对于 [homelab-infra](https://git.ddupan.top/panxiao81/homelab-infra);包含未提交内容,见首页证据边界。 来源路径相对于 [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 阶段说明 | | [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` | 无需逐台确认主机;旧源码说明待同步 | | [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](gitea.md) | 代码托管与 Actions | `git.ddupan.top` | 记录已部署 | `apps/gitea/README.md` | 已有登录、最小 CI 与 runner 选择指南 |
| gitea | 代码托管与 Actions | `git.ddupan.top` | 记录已部署 | `apps/gitea/README.md` | 补首次使用与 runner 选择 |
| http-echo | Flux 部署与漂移修复 canary | `集群内` | 记录已验证 | `apps/http-echo/README.md` | 已有验证步骤 | | http-echo | Flux 部署与漂移修复 canary | `集群内` | 记录已验证 | `apps/http-echo/README.md` | 已有验证步骤 |
| litellm-gateway | 模型 API 网关,实际消费者待确认 | `待核实` | 仅发现配置 | `apps/litellm-gateway/docker-compose.yml` | 缺 README 与接入说明 | | [litellm-gateway](litellm-gateway.md) | 模型 API 网关,实际消费者未记录 | `宿主 TCP 4000;地址未记录` | 仅发现配置 | `apps/litellm-gateway/docker-compose.yml` | 已有参数、请求示例与依赖说明 |
| marker | GPU 文档转换 API | `集群内端口 8001` | 配置与部署指南;上线待核实 | `apps/marker/README.md` | 缺 API 使用例子 | | [marker](marker.md) | GPU 文档转换 API | `集群内端口 8001` | 配置与部署指南;未附上线记录 | `apps/marker/README.md` | 已有转换示例;部署镜像仍为占位符 |
| netboot | PXE 与系统安装 | `192.168.10.127` | 有部署及使用记录 | `apps/netboot/README.md` | 已有客户端启动说明 | | netboot | PXE 与系统安装 | `192.168.10.127` | 有部署及使用记录 | `apps/netboot/README.md` | 已有客户端启动说明 |
| netbox | 网络资产与地址管理评估 | `netbox.ad.ddupan.top` | 记录已部署;评估用途 | `apps/netbox/README.md` | 补面向浏览者的使用路径 | | [netbox](netbox.md) | 网络资产与地址管理评估 | `netbox.ad.ddupan.top` | 记录已部署;评估用途 | `apps/netbox/README.md` | 已有浏览与 Git 修改入口指南 |
| openviking | 上下文检索服务 | `记录端口 1933 / 8020` | 配置与部署指南;上线待核实 | `apps/openviking/README.md` | 缺导入、查询的完整例子 | | [nexus](nexus.md) | CI 包代理与统一制品仓库 POC | `nexus.ad.ddupan.top` | 2026-09-20 已现场验证 Ansible、Go、OCI 与 BuildKit cache | `apps/nexus/README.md` | 补 publisher account、外部 PostgreSQL 与备份恢复测试 |
| ps3netsrv | PS3 网络内容服务 | `待核实` | Docker 运维文档记录运行 | `apps/ps3netsrv/docker-compose.yml` | 缺客户端使用与挂载说明 | | [openviking](openviking.md) | 上下文检索服务 | `记录端口 1933 / 8020` | 配置与部署指南;未附上线记录 | `apps/openviking/README.md` | 已有导入、任务查询、检索与原文读取指南 |
| seaweedfs | S3 对象存储 | `s3.ad.ddupan.top` | zot 文档记录已使用 | `apps/seaweedfs/README.md` | 补客户端接入、备份与恢复 | | [ps3netsrv](ps3netsrv.md) | PS3 网络内容服务 | `宿主 TCP 38008;地址未记录` | Docker 运维文档记录运行 | `apps/ps3netsrv/docker-compose.yml` | 已有客户端与内容目录指南 |
| shared-postgresql | 共享 PostgreSQL / CNPG | `shared-db namespace` | 历史迁移记录已完成 | `apps/shared-postgresql/migration.md` | 缺服务首页、租户接入说明 | | [seaweedfs](seaweedfs.md) | S3 对象存储 | `s3.ad.ddupan.top` | zot 文档记录已使用 | `apps/seaweedfs/README.md` | 已有客户端读写指南与备份边界说明 |
| smtp-relay | 应用经 Microsoft 365 发信 | `smtp-relay.smtp-relay.svc.cluster.local:25` | 有配置与测试指南;上线待核实 | `apps/smtp-relay/README.md` | 核实发信链路与消费者 | | [shared-etcd](shared-etcd.md) | homelab 共享协调与选主存储 | 三个 mTLS endpoints,见服务页 | 三成员已部署并现场验证,experimental | `infrastructure/etcd/README.md` | 原生指标与规则已接入;自动续签已启用;维护指标与告警已接入并验证 |
| tailscale | 远程网络与子网路由 | `Tailscale 网络` | 有配置;本轮未读敏感安装脚本 | `apps/tailscale/subnet-routes.sh` | 缺 README、路由与客户端说明 | | [shared-postgresql](shared-postgresql.md) | CNPG 与新 k3s 外共享 PG | 旧 `shared-db`;新 `pg-prod` / `pg-dev.ad.ddupan.top` | 新生产主从与开发实例上线,旧应用未迁移 | `infrastructure/shared-postgresql/README.md`、旧 migration.md | 切换/备份恢复已验证;Ayatori 独立控制面仅备齐声明 |
| victoriametrics | 旧 Compose 监控栈 | `待核实` | 文档称被平台栈替代;残留待查 | `apps/victoriametrics/compose.yaml` | 明确退役或现存职责 | | [smtp-relay](smtp-relay.md) | 应用经 Microsoft 365 发信 | `smtp-relay.smtp-relay.svc.cluster.local:25` | 有配置与测试指南;未附上线记录 | `apps/smtp-relay/README.md` | 已有应用参数、测试邮件与投递边界指南 |
| vlmcsd | KMS 兼容服务,使用范围待确认 | `待核实` | 仅发现配置 | `apps/vlmcsd/compose.yaml` | 缺 README 与状态说明 | | [tailscale](tailscale.md) | 远程网络与子网路由 | `Tailscale 网络` | 有配置;本轮未读敏感安装脚本 | `apps/tailscale/subnet-routes.sh` | 已有远程访问与路由边界指南 |
| zot | OCI 镜像与制品仓库 | `zot.ad.ddupan.top / zot-push.ad.ddupan.top` | 文档记录 9 月 16 日验收 | `apps/zot/README.md` | 已有拉取示例;长期 CI 发布仍待接入 | | [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` | 已有签发和验证说明 | | [cert-manager](../guides/publish-service.md) | 签发与续期 TLS 证书 | `ClusterIssuer API` | 记录已接管 Flux | `platform/cert-manager/README.md` | 已有新服务证书复用与接入指南 |
| envoy-gateway | LAN HTTP 入口与认证集成 | `192.168.10.127:443` | 记录已接管 Flux | `platform/envoy-gateway/README.md` | 已有服务接入说明 | | [envoy-gateway](../guides/publish-service.md) | LAN HTTP 入口与认证集成 | `192.168.10.127:443` | 记录已接管 Flux | `platform/envoy-gateway/README.md` | 已有 DNS、路由、认证与发布路径指南 |
| external-secrets | OpenBao 到 Kubernetes 的秘密投射 | `Kubernetes API` | Helm 记录已接管;对象范围需区分 | `platform/external-secrets/README.md` | 补新增秘密引用的使用流程 | | [external-secrets](external-secrets.md) | OpenBao 到 Kubernetes 的秘密投射 | `Kubernetes API` | Helm 记录已接管;对象范围需区分 | `platform/external-secrets/README.md` | 已有字段投射示例与 ownership 边界 |
| gitea-runner | 可信 Gitea Actions 任务执行 | `Gitea Actions` | 记录已接管 Flux | `platform/gitea-runner/README.md` | 补 workflow label 与使用限制 | | gitea-runner | 旧常驻 Gitea Actions runner | 纯 `self-hosted` | 维护者说明准备退役,尚未标为已退役 | `platform/gitea-runner/README.md`、维护者说明 | 新 workflow 改用 [动态 Pod/VM](gitea-dynamic-runner.md) 的明确 labels |
| k3s | 集群 CoreDNS 定制 | `集群内 DNS` | 仅发现 DNS 配置 | `platform/k3s/Corefile.desired` | 缺组件 README | | [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 消息队列约定以独立项目文档为准 | | [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` | 补看板和查询使用指南 | | [observability / Grafana](grafana.md) | 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 使用边界 | | [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 为准 | | [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 +54,14 @@ SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护
|---|---|---|---|---|---| |---|---|---|---|---|---|
| cloudflared | 公网 Tunnel 与 DNS | `Cloudflare 边缘配置` | 有现有资源接管记录 | `infrastructure/cloudflared/terraform/README.md` | 明确配置权威位置与服务发布流程 | | cloudflared | 公网 Tunnel 与 DNS | `Cloudflare 边缘配置` | 有现有资源接管记录 | `infrastructure/cloudflared/terraform/README.md` | 明确配置权威位置与服务发布流程 |
| [dns](lan-dns.md) | 跨视图 DNS 声明 | `records.yml` | LAN 角色已按维护者说明对齐;声明接管范围未重查 | `infrastructure/dns/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-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 的职责 | | 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`、独立项目文档 | 具体启用范围和实现进度以独立项目文档为准 | | 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` | 补跨站点使用入口 | | [oci](oci.md) | 云主机、网络与站点互联 | `OCI ap-osaka-1` | 有恢复、接管与网络实施记录 | `infrastructure/oci/README.md` | 已有登录、站点网络与维护入口 |
| openbao | 秘密管理与内部 CA | `bao.ad.ddupan.top` | 有部署与接管记录 | `infrastructure/openbao/README.md` | 补日常使用和恢复入口 | | [openbao](openbao.md) | 秘密管理与内部 CA | `bao.ad.ddupan.top` | 人工解封、中央采集与本地快照已验收 | `infrastructure/openbao/README.md` | 内部健康和快照新鲜度有告警;异地恢复演练待完成 |
| proxmox | PVE、虚拟化与主机基础设施 | `PVE 管理入口` | 已有基础设施;README 混有设计设想 | `infrastructure/proxmox/README.md` | 分离当前环境与 workload identity 设想 | | [proxmox](proxmox.md) | PVE、虚拟化与主机基础设施 | `PVE 管理入口` | 已有基础设施 | `infrastructure/proxmox/ansible/` 与 `README-ha.md` | 已有管理入口;sandbox LB/根盘恢复流程见服务页;身份与 runner 设计见独立项目 |
| samba-ad | AD 身份、域 DNS 与域成员管理 | `dc1 / 192.168.10.5` | 有部署记录;维护者说明 DNS 部分已完成 | `infrastructure/samba-ad/README.md`、[LAN DNS](lan-dns.md) | 补入域和日常管理入口 | | [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 +71,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 基础设施;仅保留归属入口。 - [e5renew、research-auto](external-consumers.md):GitHub 上的外部消费者,不属于 homelab 基础设施;仅保留归属入口。
- [Gitea Dynamic Runner](gitea-dynamic-runner.md):正在积极开发的动态 Pod/VM runner,原名 gitea-microvm-runner;具体启用范围、调度和队列约定以项目文档为准。 - [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 替代。 - [workload-sts](../architecture/workload-sts-history.md):已归档的早期机器身份方案;停止开发、不部署 PoC,由 SPIFFE/SPIRE 替代。
- Backstage:规划中的服务目录与文档入口;本轮未发现独立部署目录。 - Backstage:规划中的服务目录与文档入口;本轮未发现独立部署目录。
- Keycloak、Casdoor:`archive/` 下有明确退役记录,替代入口为 Authelia。 - Keycloak、Casdoor:`archive/` 下有明确退役记录,替代入口为 Authelia。
@@ -79,4 +85,4 @@ SPIFFE/SPIRE 已按维护者授权补读 #34;LAN DNS 与 Authelia 已按维护
- `docs/superpowers/`:已退役工作流,记录已完成的 CNPG/ZFS 迁移。 - `docs/superpowers/`:已退役工作流,记录已完成的 CNPG/ZFS 迁移。
- `docs/cicd.md`、`docs/homelab-gitops-redesign.md`:部分实施设计,不代表所有阶段都上线。 - `docs/cicd.md`、`docs/homelab-gitops-redesign.md`:部分实施设计,不代表所有阶段都上线。
- `docs/gitea-upgrade-plan.md`:包含已完成升级记录,现状以服务 README 和现场为准。 - `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 为路由器。 主机通过 DHCP 自动获取 DNS 配置:主 DNS 为 Blocky,副 DNS 为路由器。
当前知识库以此作为 LAN 客户端配置口径,无需另行进行主机覆盖盘点。 当前知识库以此作为 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,保留部署与操作细节的原有归属: 以下路径相对于 homelab-infra,保留部署与操作细节的原有归属:
- `apps/blocky/README.md`:Blocky 部署、分流和检查方法。 - `apps/blocky/README.md`:Blocky 部署、分流和检查方法。
- `infrastructure/samba-ad/README.md`:域 DNS 与 Samba 配置。 - `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/samba-ad/router-dns-nec-ix.md`:路由器 DNS 记录。
- `infrastructure/dns/README.md`、`records.yml`:跨视图 DNS 声明与所有权。 - `infrastructure/dns/README.md`、`records.yml`:跨视图 DNS 声明与所有权。
本次只更新知识库;原工作区中“Blocky 未成为正式 resolver”的旧描述尚待同步。
路由器自身的更上游和 AD/DN42 条件转发明细未在本次补充,也不因此自动产生核查任务。 路由器自身的更上游和 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)。
+9 -1
View File
@@ -2,7 +2,7 @@
title: NATS title: NATS
lifecycle: active lifecycle: active
evidence: documented evidence: documented
last_reviewed: 2026-09-16 last_reviewed: 2026-09-25
last_verified: null last_verified: null
sources: sources:
- 维护者于 2026-09-16 提供的部署与消费者说明 - 维护者于 2026-09-16 提供的部署与消费者说明
@@ -40,3 +40,11 @@ Dynamic Runner 的 stream、subject、durable 名称、worker 配置和具体启
知识库只保留[Dynamic Runner 的用途与职责边界](gitea-dynamic-runner.md)。 知识库只保留[Dynamic Runner 的用途与职责边界](gitea-dynamic-runner.md)。
涉及 runner 的实际配置和实现进度时,先按项目文档接续工作;需要扩大查询范围时再向维护者确认。 涉及 runner 的实际配置和实现进度时,先按项目文档接续工作;需要扩大查询范围时再向维护者确认。
## 指标与告警
2026-09-25 已现场确认既有 :7777 prom-exporter 经 PodMonitor → VMPodScrape 接入中央采集,
job 为 `nats/nats`,target up 且 nats_* 指标有当前样本。已有采集不可用/整个 job 消失告警;
已增加 JetStream 服务端容量与慢消费者规则;consumer 积压仍待后续。
范围和阈值见 [数据服务监控](../guides/monitoring-data-services.md)。
转换器故障处理与验证依据见 [基础监控运维](../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)。
+109
View File
@@ -0,0 +1,109 @@
---
title: OpenBao 使用指南
lifecycle: active
evidence: live-verified
last_reviewed: 2026-09-25
last_verified: 2026-09-25
---
# OpenBao
OpenBao 提供秘密管理与内部 CA,部署在 Kubernetes 之外的独立主机上。
日常使用是以自己的身份登录,按已有 policy 读取秘密或申请短期凭据。
本页依据 homelab-infra 工作区 `infrastructure/openbao/README.md` 整理,
CLI 语法参考下列官方文档。登录和取密指南仍以文档为据;2026-09-25 已现场验证
服务解封、中央指标、ESO 秘密刷新及本地快照监控,范围见本文末节。
## 人的登录入口
前提是客户端能解析并访问内部域名,已安装 `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)。
## 监控接入与维护窗口
2026-09-25 已启用受鉴权 Prometheus telemetry,ServiceMonitor 通过现有 vmagent 采集,
job 为 `openbao`。同 Pod 的 Bao Agent 使用 Kubernetes SA 登录 metrics role,自动续期,
token 仅保存于内存卷;指标身份不能读取业务秘密,匿名 metrics 仍被拒绝。
已有目标 down/消失持续 3 分钟的 critical 告警,通知沿用 Telegram。
内部健康规则另检查当前单节点的 active、unsealed、Raft autopilot node healthy,
并单独告警健康 gauge 缺失。以后改为多节点时必须调整 active 判定;尚未覆盖全部 Raft 或 PKI 风险。
维护中已修复快照 token 失效及脚本缺少续期的问题,生成新快照并核对 VM 外副本。
快照 timer 已启用;独立的 VM node_exporter 通过 textfile 上报最近结果、完成时间和最后成功时间,
不依赖 Bao 解封或 API token。快照失败持续 5 分钟为 warning,超过 36 小时无成功快照
或无成功记录持续 15 分钟为 critical;采集失联/损坏也有专用告警。
标准主机指标复用现有主机规则。异地副本与恢复演练仍需独立验收。
维护者用 working PC 的 YubiKey 解密 VM 上保存的加密 unseal share,重启后人工解封。
本次服务配置变更、采集上线与恢复验收已完成,详细操作与证据见
[OpenBao 监控接入维护 runbook](../guides/openbao-monitoring-maintenance.md)。
后续重启仍需同样的人在场解封流程;不能因本次恢复成功假定已经自动解封。
+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)。
+178 -10
View File
@@ -2,7 +2,7 @@
title: PostgreSQL Tenant Operator(计划中的 DBaaS) title: PostgreSQL Tenant Operator(计划中的 DBaaS)
lifecycle: planned lifecycle: planned
evidence: documented evidence: documented
last_reviewed: 2026-09-16 last_reviewed: 2026-09-27
last_verified: null last_verified: null
sources: sources:
- https://git.ddupan.top/panxiao81/postgresql-tenant-operator - https://git.ddupan.top/panxiao81/postgresql-tenant-operator
@@ -21,20 +21,124 @@ homelab 资源有限,为每个应用维护一套数据库会浪费资源。绝
计划自行实现这个中间层,让下游通过统一接口申请可消费的数据库,降低共享实例的管理成本。 计划自行实现这个中间层,让下游通过统一接口申请可消费的数据库,降低共享实例的管理成本。
这段现状和设计动机由维护者于 2026-09-16 提供;本轮没有查询数据库或集群。 这段现状和设计动机由维护者于 2026-09-16 提供;本轮没有查询数据库或集群。
现有实例的日常接入见[共享 PostgreSQL 使用指南](shared-postgresql.md)。
现有实例的源码入口为 homelab-infra 的 `apps/shared-postgresql/`。 现有实例的源码入口为 homelab-infra 的 `apps/shared-postgresql/`。
## 当前进度 ## 当前进度
2026-09-16 查阅[项目 README](https://git.ddupan.top/panxiao81/postgresql-tenant-operator/src/branch/main/README.md) 维护者于 2026-09-20 提供的阶段状态如下:
与架构文档时,项目记录为 **API 骨架阶段,尚未对 PostgreSQL 或 OpenBao 执行写操作**。
已批准的设计合同不等于已经实现的功能,本文不表示 DBaaS 已上线。 - 已合并 Instance 的 Endpoint、凭据引用、身份/版本、定义与观测目标等值对象;
项目首页还注明 `config/samples` 保留旧 API 骨架,不能将其直接当作最终使用接口。 - 已合并扩展支持能力模型,以及 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 实例及管理连接。 1. 平台管理员通过 `PostgreSQLInstance` 注册已有 PostgreSQL 实例及管理连接。
2. 下游以 namespaced `PostgreSQLTenant` 声明所需 database、login owner 和扩展。 2. 下游以 namespaced `PostgreSQLTenant` 申请数据库,或显式引用管理员登记的 Database。
3. controller 校验所有权与冲突,幂等创建凭据、role、database 和授权等资源。 3. controller 建立独立 Database 记录与排他绑定,供应或验证资源;未知同名及不确定创建报冲突。
4. 应用凭据以 OpenBao KV 为事实来源,由 ESO 投射为 Kubernetes Secret。 4. 应用凭据以 OpenBao KV 为事实来源,由 ESO 投射为 Kubernetes Secret。
非 Kubernetes 消费者使用提供的 OpenBao API URL,并通过自身授权获取凭据。 非 Kubernetes 消费者使用提供的 OpenBao API URL,并通过自身授权获取凭据。
5. ESO 投射成功且应用凭据实际登录成功后,Tenant 才能进入 Ready。 5. ESO 投射成功且应用凭据实际登录成功后,Tenant 才能进入 Ready。
@@ -44,9 +148,72 @@ 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)
与安全文档为准;合并不表示部署或完整供应链路已完成。
应用凭据存储切片及测试准备修复已通过三项 CI,并经维护者批准合并
[PR #12](https://git.ddupan.top/panxiao81/ayatori/pulls/12),合并提交为
[22ab72e](https://git.ddupan.top/panxiao81/ayatori/commit/22ab72ec60dd5a0bf852e4563e107597dd56e81f)。
复用 OpenBao 官方 Go SDK 的 KV v2 CAS=0、回读七键与版本,禁止覆盖
或自动认领;明确权限拒绝等待依赖恢复,写入结果不确定则停止并人工处理。本地真实
OpenBao 测试已覆盖并发、软删除、固定前缀权限和响应丢失,尚未接入 manager、
Database 供应或 ESO。源码模块文档与 wiki 已关联,见
[同步记录](../verification.md)。
Kubernetes 认证会话、公共 infra 与 bootstrap 装配拆分已于 2026-09-27 经维护者批准合并
[PR #13](https://git.ddupan.top/panxiao81/ayatori/pulls/13),合并提交
[6b2808c](https://git.ddupan.top/panxiao81/ayatori/commit/6b2808ce91b03215f466746a15d0c3d7442bb9d4)。
维护者指出并纠正了首版的 Pod 文件假设:controller 可以是 systemd service;Kubernetes auth
仍是正确路径,但应复用 manager 的标准 kubeconfig/in-cluster 配置,通过 RBAC 授权的指定
ServiceAccount TokenRequest 申请短期 JWT。集群内外共用同一客户端路径,不另建机器身份。
重新登录重新申请 JWT,申请失败不回退投射文件或静态 token;官方 SDK 负责 Bao 登录与
LifetimeWatcher,续期失败及停止时清空本地 token。kubeconfig 的签发、更新与撤销属于部署管理。
manager 已增加显式 HTTPS/CA、auth role、目标 SA/audience 配置、Runnable 与 readiness,
默认停用;controller 不自动创建身份或授予权限。真实受限 kubeconfig 启动 manager 的测试
验证 TokenRequest、续期、跨 namespace/其他 SA 拒绝、RBAC 撤回恢复与 Bao audience 校验,
三轮 race、本地全量测试和两种 lint 通过。生产 auth 配置与 Database 供应尚未接入,不代表已部署。
认证客户端与生命周期按维护者确认的
[公共 infra 边界](../architecture/ayatori-control-plane.md#controller-公共基础设施边界)整理,
Database 保留凭据 repository/adapter 语义;装配由独立 bootstrap 包负责,Run 只编排启动与清理。
合并不表示供应链路已完成;合并时 CI 的状态边界见[同步记录](../verification.md)。
具体使用边界见该提交的
[认证会话说明](https://git.ddupan.top/panxiao81/ayatori/src/commit/6b2808ce91b03215f466746a15d0c3d7442bb9d4/docs/database/README.md#openbao-kubernetes-认证会话)。
2026-09-27 维护者确认最小凭据记录合同:Database `status.credentialRef` 在首次外部写入前
固定 mount/path,`status.credentialVersion` 只在创建并回读成功后保存版本;记录不可自动
更改或清空,Conditions 独立表示当前可用性。已有值但无确认记录、已确认凭据消失或最新
版本漂移均按 Conflict 人工处理,不认领、不生成替代密码,也不随部署参数搬迁。
按维护者要求,字段切片已扩展为一个完整的凭据准备行为,见
[凭据准备闭环](https://git.ddupan.top/panxiao81/ayatori/src/commit/35ada6d7eb58245c5214632282178b145489d0dc/docs/database/README.md#凭据准备闭环),
已随 [PR #14](https://git.ddupan.top/panxiao81/ayatori/pulls/14) 在 CI 三项检查通过后合并
(合并提交 `72ce3ed`),未部署。
显式设置 `--database-credential-mount` 后启用:校验双向绑定和 Instance,固定位置,
创建并回读,保存确认版本。用例在 application,Kubernetes repository 负责状态写入,
controller 只驱动 watch/重查;Bao client 与认证生命周期仍由公共 infra 统一装配。
创建开始却没有成功确认时,重入转 Conflict,即使进程可能尚未实际发请求也保守停止;
明确的权限拒绝可等待恢复。无关 Conditions 刷新不改变目标,相关绑定、generation、删除
或 Ready 变化则停止旧操作。旧 CRD 裁剪新字段时拒绝继续外部写入,升级须先安装新 CRD。
真实 API server、隔离 Bao 与实际 manager 已覆盖重启、并发、依赖恢复、状态保存失败及
删除边界;完整集成回归通过,但这不是现场验证。只有 CredentialsReady 可以为 True,
PostgreSQL 创建、ESO 交付和删除回收尚未接入,Database/Tenant 不能据此宣告 Ready。
凭据准备的分层进一步按维护者确认的
[显式装配与领域边界](../architecture/ayatori-control-plane.md#controller-公共基础设施边界)
重构,见待审阅的 [PR #15](https://git.ddupan.top/panxiao81/ayatori/pulls/15)。
该重构不扩展供应范围或修改凭据协议;本地完整集成回归已通过,尚未合并或部署。
- operator 管理实例内的租户资源,不运行 PostgreSQL/OpenBao,也不管理 VM、存储、备份或 OpenBao PKI。 - operator 管理实例内的租户资源,不运行 PostgreSQL/OpenBao,也不管理 VM、存储、备份或 OpenBao PKI。
- 应用密码写入 OpenBao,不进入 CR、Event 或日志;ESO 负责向 Kubernetes 消费者投射。 - 应用密码写入 OpenBao,不进入 CR、Event 或日志;ESO 负责向 Kubernetes 消费者投射。
- 默认删除策略为 `Retain`,删除声明不会默认删除业务数据;显式 `Delete` 需重新校验所有权。 - Database 默认 Retain;删除 Tenant 保留资源对象与数据,Released 不自动重新分配。
- 资源侧 Delete 需明确授权、finalizer 与实际管理范围检查,导入不隐含删除或改密授权。
- 遇到未知 database/role 等资源报告 Conflict,不能自动接管、覆盖或删除;现有数据库迁移需遵循迁移合同。 - 遇到未知 database/role 等资源报告 Conflict,不能自动接管、覆盖或删除;现有数据库迁移需遵循迁移合同。
- namespace 是 Kubernetes 身份与 RBAC 边界;database/role 名称在一个 PostgreSQL Instance 内仍全局唯一。 - namespace 是 Kubernetes 身份与 RBAC 边界;database/role 名称在一个 PostgreSQL Instance 内仍全局唯一。
@@ -62,5 +229,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/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/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)查询, 迁移前的具体实现进度仍回到[项目仓库](https://git.ddupan.top/panxiao81/postgresql-tenant-operator)
后续查询前先向维护者对齐当前工作与 ticket。本页保留设计定位和带日期的阶段摘要。 查询;迁移后的实现与发布进度转到 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)。
+92
View File
@@ -0,0 +1,92 @@
---
title: SeaweedFS S3 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-25
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)。
## 中央监控
2026-09-25 已接入 master、filer、volume 指标与容量/写入故障规则;
使用方式与验证边界见 [数据服务监控](../guides/monitoring-data-services.md)。
+72
View File
@@ -0,0 +1,72 @@
---
title: Homelab 共享 etcd
lifecycle: experimental
evidence: live-verified
last_reviewed: 2026-09-27
last_verified: 2026-09-25
---
# Homelab 共享 etcd
为 homelab 服务提供共享的配置、协调与选主存储。维护者已接受共享定位;首个消费者是
k3s 外 PostgreSQL 的 Patroni。三成员基础服务已部署,现有监控已接入,自动续签已启用;现有 k3s datastore 未迁移。
## 入口与第一次接入
部署拓扑为 laptop 原生 systemd、pve1/pve2 各一个无特权 LXC(150/151)。地址为
192.168.10.127、10.60.0.20、10.60.0.21,客户端端口 2379,三端点健康检查已通过。两个 LXC 的 rootfs 位于 `pve-rg` SSD DRBD 池。
实际接入前由管理流程交付三个 TLS endpoints、中央 CA、独立客户端证书和 Bao 秘密引用。
使用分配身份在自己的 prefix 内 put/get/delete 验证,并确认跨 prefix 被拒绝;不要使用管理员证书接应用。
证书由 OpenBao 中央 CA 签发,成员间 peer CN 受限。管理员原生 etcdctl 使用 CN=root 证书;
Patroni etcd3 gateway 使用无 CN 的 mTLS 证书加独立账号密码,不能复用管理员证书。
密码首次随机生成并存入 Bao,重复部署复用,缺失、读取失败或漂移均不静默重置。
首个消费者秘密路径为 `kv/infra/etcd/consumers/patroni-pg-prod`,授权 prefix 为
`/homelab/patroni/pg-prod/`;账号和随机密码已创建,真实 gateway 登录已验证;Patroni 已部署并通过自动切换验证。
## 依赖、维护与恢复
依赖主机网络、磁盘、systemd;证书签发及配置收敛依赖 Bao。运行使用本地证书,不要求 Bao 在线。
共享 etcd 的创建、维护和快照与数据库生命周期分离;删除 PostgreSQL 不删除 etcd。
全集群快照恢复必须协调所有消费者,不能作为单个业务的回滚。
源码实现提供每日每成员本地快照、独立认证初始化、消费者收敛和逐成员更新入口。
三个成员的原生指标已接入现有 VictoriaMetrics,不增加 exporter;内网 2381 listener 不提供 KV API。
六条规则覆盖成员采集、采集可见成员不足、无 leader、容量、fsync 和选举,现场三目标 up=1、规则 health=ok。
Alertmanager 已接入 [Telegram 通知](grafana.md#telegram-告警接入),warning/critical 可向外通知;备份/证书/续签检查的主机采集已于 2026-09-27 部署,
新增规则已随 PR #166 合并并由 Flux 接管,见[维护告警](shared-postgresql.md#维护告警2026-09-27)。
自动续签已启用:维护者恢复 OIDC 管理会话后,独立 cert auth、受限 policy 与每日 timer 已部署。
登录使用 laptop 现有 peer 证书,按 DNS SAN 限制身份;无 CN gateway 证书不能用于 Bao cert
登录(identity alias 为空),不会改动 etcd gateway 的无 CN 要求。首次实际续签流程三成员均
`changed=0`、service Result=success;程序固定副本由 root 管理,短期 token 用后撤销。
运行仍只依赖本地证书;续签和恢复步骤见源码 README。
业务负载下的存储延迟与完整灾难恢复演练仍待完成。
故障时先查 `homelab-etcd` systemd 日志和三端点健康;成员替换不能通过删除数据目录、重跑初始化处理。
详细操作与验收边界见 homelab-infra `infrastructure/etcd/README.md`。
存储故障处理:单成员 `NoLeader` 与频繁选举告警可能来自底层 I/O,不能直接认定整个集群失去 quorum。
2026-09-25 CT150 的 DRBD 根卷短暂丢失 quorum,ext4 journal 写入失败后进入 `emergency_ro`;
另外两成员仍健康。保存快照后停止 CT150,以 PVE 离线 fsck 修复、复查干净再启动,三成员健康及
Raft term/index 一致已重新验证,两容器根卷与新增 mp0 均可写。不要在挂载中的卷上 fsck 或直接强制 remount。
本项目两块新 HDD 数据卷后台同步上限已通过 IaC 限制为各 10 MiB/s;限速后短期未再见 PingAck 超时,
但唯一根因和长期稳定性未确证。没有更改全局 DRBD quorum/协议。对应入口为
`infrastructure/shared-postgresql/ansible/limit-resync.yml`,重复执行无变更;详细恢复过程见上述 runbook。
频繁选举规则包含 15 分钟历史窗口,故障恢复后需结合当前健康及计数判断。
## 证据与阶段边界
2026-09-25 维护者指定 laptop + 两台 PVE 各一个新 LXC,并明确复用 Bao 中央 CA;旧 Vault 迁移后置。
现场部署已应用独立 Bao PKI roles/policies,创建 LXC 150/151 并启用三成员 mTLS、认证及消费者 RBAC。
PVE 两个 LXC 已直接迁移底层 rootfs 到 `pve-rg`;逐成员停机迁卷、启动后检查 quorum,未重建容器或数据库。
2026-09-25 现场核实两个 rootfs 的目标存储与运行状态,三个 endpoint 均成功提交健康探测。
当前 PVE LXC `move-volume` 要求容器停止;操作入口为源码 `ansible/move-storage.yml`。
本地临时三节点 etcd 3.7.2 测试通过:mTLS、认证和消费者幂等、prefix 隔离、gateway 登录/写入、
密码缺失/漂移失败关闭、快照离线恢复与停止一成员后的写入。假 Bao 测试不证明真实 PKI/policy 正确;
测试进程 RSS 约 37–40 MiB 不是生产容量承诺。Terraform validate 与 Ansible lint 通过。
证书签发、秘密创建、gateway 登录和机器身份续签均已在真实服务验证。
来源为维护者指令、只读前置核查及 homelab-infra `infrastructure/etcd/`;
文档已直接发布 main([文档 acd4b55](https://git.ddupan.top/panxiao81/homelab-infra/commit/acd4b55)),实现见 [IaC PR #159](https://git.ddupan.top/panxiao81/homelab-infra/pulls/159),已合并。与数据库的关系见[共享 PostgreSQL](shared-postgresql.md#共享-etcd-设计边界)。
+167
View File
@@ -0,0 +1,167 @@
---
title: 共享 PostgreSQL 使用指南
lifecycle: active
evidence: documented
last_reviewed: 2026-09-27
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)。
## 共享 etcd 设计边界
2026-09-25 维护者确定:为计划中的 k3s 外 PostgreSQL 引入的 etcd,应作为全 homelab
共享基础设施建设,PostgreSQL 是首个消费者。该共享定位已实现并完成首期部署验收;既有应用尚未迁移,
不改变本页现有 CNPG 入口。原研究将 etcd 列入数据库部署角色,新边界将其生命周期独立,
以便多个服务共用,减少重复部署与维护。
首期三成员已跨 laptop 与两台 PVE 部署,可与其他服务物理共置;
独立 IaC 管成员、认证、维护和快照,消费者只取得自己的账号与 key prefix 权限。
数据库卸载不能删除共享 etcd,全集群快照恢复也不能用作单个数据库的回滚。
现有 k3s 内部 datastore 不包含在本次迁移范围;其他消费者按实际需要接入。
维护者同时确定 etcd mTLS 证书由 OpenBao 中央 CA 签发,复用现有信任根,不引入
Pigsty 自建 CA。签发角色、peer 身份限制及消费者认证已部署;自动续签身份和 timer 已启用;
证书本地保存,正常启动不要求实时访问 Bao,Bao 本身不依赖此共享 etcd。
Patroni 的 etcd3 gateway 路径不支持证书 CN 对应的 RBAC 登录;维护者确定其独立随机密码
存入 Bao,由 Ansible 执行时读取,重复部署复用,轮换显式执行。该 secret 已在共享 etcd 部署阶段创建并验证 gateway 登录;Patroni 已部署。
PVE 改为裸机目前仅为后续倾向,没有迁移决定。
来源为本轮维护者设计指令及 homelab-infra
`infrastructure/shared-postgresql/RESEARCH.md`;文档来源为 [文档 acd4b55](https://git.ddupan.top/panxiao81/homelab-infra/commit/acd4b55),实现由 [IaC PR #159](https://git.ddupan.top/panxiao81/homelab-infra/pulls/159) 跟踪。
本节记录数据库设计边界;共享 etcd 的现场部署与验证见独立服务页,本页 CNPG 的 `last_verified` 不因此更新。
共享 etcd 的首轮 IaC、隔离验证与部署前置条件见[共享 etcd](shared-etcd.md)。
### k3s 外实例的实现与验收边界(2026-09-25)
新 PostgreSQL 18.6 生产主从与独立开发实例已上线,现有 CNPG 应用数据尚未迁移。
生产稳定入口 `pg-prod.ad.ddupan.top:5432` 指向 VyOS `192.168.10.2` 上独立 HAProxy;
正常 primary 为 laptop SSD ZFS,PVE LXC150 为 standby。开发入口为
`pg-dev.ad.ddupan.top:5433`,同机独立用户/数据集。客户端要求中央 CA 与 verify-full TLS。
LXC151 的专属 HDD 卷存放 pgBackRest 仓库,真实 SSH/WAL 归档、首个 full 和每日 timer 已验收;
保留 3 个 full、本地连续 WAL,尚无异地备份,开发实例当前不备份。
真实备份已恢复到临时目录的隔离实例,SQL 可写与管理角色属性验证通过,未覆盖生产 PGDATA。
低负载停止 laptop 主库服务后,完整通过的一次演练约 9.2 秒恢复经稳定入口写入;旧主重新作为
replica 加入、计划回切 laptop 后复制与探针清理全部通过。这不是 SLA,也不覆盖冻结/网络分区等全部故障。
Bao PKI 与专用 `homelab-postgresql` SPIFFE 身份已通过 OIDC 管理会话首次创建;之后受限身份
完成签发、KV 读取与独立管理凭据交付。原始实例秘密不交给 Ayatori,控制面只读
`kv/infra/postgresql/ayatori/{prod,dev}` 中的 username/password。
生产与开发管理账号实际 TLS 登录和非 superuser CREATEDB/CREATEROLE 属性已验证。
配置、备份传输、代理与凭据重跑 `changed=0`;PG 每日续签已启用,实际 systemd 运行成功,
证书窗口检查与 SQL 验收无变更。只在续签后重载证书,不重启实例;尚未强制演练临期轮换。
数据库日常运行独立于 k3s;机器身份续签依赖现有 SPIRE 与 Bao,不等于运行时依赖。
生产 Patroni 原生指标已接入现有监控,两目标 up=1、五条 HA 规则 health=ok 且 inactive。
SQL 级 exporter 仍后置;开发实例、备份年龄与证书的维护监控进度见下节。存储事故与持续观察边界见
[共享 etcd](shared-etcd.md#依赖维护与恢复),不以短期验收证明底层长期稳定。
维护者明确 Ayatori 沿用独立控制面规划:本轮只准备 Instance、ExternalSecret、公开 CA、
Kustomize 与专用 ESO 只读 policy,没有向现有 k3s 安装 controller/CRD 或应用这些声明。
独立控制面还需创建实际 SecretStore/认证绑定并验收 Instance Ready;完整 Database/Tenant
供应能力以 Ayatori 自身实施为准。不能把现有 SQL 验证当作 Ayatori 已接管。
源码为 homelab-infra `infrastructure/shared-postgresql/README.md` 与
`ayatori/README.md`;部署、切换、恢复、续签及凭据引用的具体入口在那里维护,文档已发布 main;IaC 见 [IaC PR #159](https://git.ddupan.top/panxiao81/homelab-infra/pulls/159),已合并;2026-09-25 核实 Flux observability 已应用 `f6d12d6`,四个监控对象均已进入 inventory。
Terraform backend 已复用 `kv/k8s/seaweedfs-s3` 中受限 AK/SK;此前阻塞是 Bao 管理权限,已由
维护者重新 OIDC 登录解决,不是 S3 凭据缺失。旧 Ansible Vault 迁移仍后置。
### 维护告警(2026-09-27)
三台现有主机已部署只读采集与 textfile exporter,每分钟检查 etcd 成功快照、PG 仓库成功 full、
磁盘证书链、laptop 上两个续签任务,以及 dev 本地 peer 身份的只读 SQL。无需新增数据库密码或
Bao token,数据库和 etcd 未重启。实际检查均成功;vmagent Pod 可访问三个内网 `:9109/metrics`。
[IaC PR #166](https://git.ddupan.top/panxiao81/homelab-infra/pulls/166) 已合并,新增抓取和八条告警
**已启用**。2026-09-27 现场确认 Flux observability Ready、应用版本 `589c34e`,
PrometheusRule 与 VMStaticScrape 均在 inventory;转换后的 VMRule 为 operational,
三个目标 up=1,八条规则 health=ok、inactive。告警以 PrometheusRule 声明,由现有 converter 转换;exporter 升级只改版本,
下载包与官方校验和列表随同一版本变量变化。规则覆盖采集不可用/过期/单项失败、备份超过 36 小时、证书不足 10 天 warning / 3 天
critical、续签检查超过 36 小时或失败,以及 dev SQL 连续异常 3 分钟。已有运行及选主告警保持启用。
故障时先查 `homelab-data-collect.service/timer` 和 `homelab-data-exporter.service`。
备份异常再查原 snapshot/backup unit;续签异常查 laptop 的两个 renew unit 和 Bao/SPIRE 连通性;
dev 异常查数据库 unit、磁盘及 socket。不要通过修改备份文件时间、删除证书或重建实例消除告警。
备份年龄不证明可恢复或 WAL 连续;dev 只读检查不验证外部 DNS/TLS;磁盘证书有效不证明运行进程已
重载。部署入口与详细排障见 [维护监控 runbook](https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/infrastructure/shared-data-monitoring/README.md)。
文档来源 [26a8ffe](https://git.ddupan.top/panxiao81/homelab-infra/commit/26a8ffe),IaC 版本
[0d633cf](https://git.ddupan.top/panxiao81/homelab-infra/commit/0d633cf)。6 项采集测试、12 个新增告警场景、
既有规则回归、Ansible lint 和 Kustomize 渲染通过;三主机重复部署 `changed=0`。
+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 使用入口与阶段状态 title: SPIFFE/SPIRE 使用入口与阶段状态
lifecycle: active lifecycle: active
evidence: documented evidence: documented
last_reviewed: 2026-09-16 last_reviewed: 2026-09-21
last_verified: null last_verified: null
sources: sources:
- https://git.ddupan.top/panxiao81/homelab-infra/issues/34 - 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/homelab-infra/src/branch/main/platform/spire/RUNBOOK.md
- https://git.ddupan.top/panxiao81/ci-actions/src/tag/v1/spiffe-openbao-login
--- ---
# SPIFFE/SPIRE # SPIFFE/SPIRE
@@ -55,7 +56,7 @@ SPIFFE/SPIRE 取代了原计划中由 **workload-sts 承担统一 IAM 平台**
维护者指定以 [homelab-infra #34](https://git.ddupan.top/panxiao81/homelab-infra/issues/34) 维护者指定以 [homelab-infra #34](https://git.ddupan.top/panxiao81/homelab-infra/issues/34)
为主要状态依据。2026-09-16 查阅时 issue 为 open,最后更新时间为 为主要状态依据。2026-09-16 查阅时 issue 为 open,最后更新时间为
2026-09-14 12:43:54 UTC;本页是该次查阅的阶段摘要,不替代 ticket 的动态进度。 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 | | 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 | | 测试 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 | | 新 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 身份的能力, [Dynamic Runner](gitea-dynamic-runner.md) 提供 Pod/VM 执行环境及获取自身 SPIFFE 身份的能力,
不将 OpenBao 或其他服务的业务登录流程内置为 runner 职责。 不将 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) [权威 RUNBOOK](https://git.ddupan.top/panxiao81/homelab-infra/src/branch/main/platform/spire/RUNBOOK.md)
的第 4–8 节。这里不复制第二份操作脚本。接入需要新增身份和授权配置,不是挂载 socket 后 的第 4–8 节。这里不复制第二份操作脚本。接入需要新增身份和授权配置,不是挂载 socket 后
@@ -94,7 +103,7 @@ OIDC issuer 为 `https://spire-oidc.ad.ddupan.top`,其 discovery/JWKS 用于
## 仍在 ticket 中跟踪 ## 仍在 ticket 中跟踪
截至本次查阅,后续范围包括真实 Gitea CI/AI Agent 的 OpenBao 接入、credential-exec、 截至本次查阅,后续范围包括在真实 Gitea CI/AI Agent 中验收已发布的登录 Action、
SeaweedFS Web Identity/STS、非 Kubernetes 主机与临时 VM 的证明和回收、 SeaweedFS Web Identity/STS、非 Kubernetes 主机与临时 VM 的证明和回收、
Compute/DBaaS 消费身份,以及 HA、备份恢复和多 issuer 约定。 Compute/DBaaS 消费身份,以及 HA、备份恢复和多 issuer 约定。
这些是 #34 的开放范围;单个消费者已有其他 PoC,不等于整项已完成。 这些是 #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 lifecycle: retired
evidence: live-verified evidence: live-verified
last_reviewed: 2026-09-16 last_reviewed: 2026-09-16
last_verified: 2026-09-16 last_verified: 2026-09-16
sources: sources:
- 维护者提供的 Kubernetes 完整可观测性栈替代目标 - 维护者于 2026-09-16 明确要求直接删除旧配置和全部旧数据卷
- 2026-09-16 本机 Docker 容器、卷及文件元数据只读检查 - 2026-09-16 Docker 卷删除前后检查及 Kubernetes monitoring 状态检查
- 2026-09-16 monitoring namespace 的资源状态只读检查
--- ---
# 旧 VictoriaMetrics Compose 栈 # 旧 VictoriaMetrics Compose 栈(已清理)
**旧运行栈已停用,历史数据卷仍保留。数据是否已迁移、是否需要长期保留尚未确认。** **旧配置与三个 Docker 数据卷已于 2026-09-16 删除,未备份、未迁移旧数据。**
这里的 retired 只描述旧 Compose 运行栈,不代表旧数据已获准删除。 维护者在了解保留数据情况后明确选择直接删除。新 Kubernetes 可观测性栈未做部署修改。
维护者最初的目标是以 Kubernetes 内的完整可观测性栈替代它,以便集成其他服务。 ## 清理范围与结果
2026-09-16 经维护者授权进行了有限只读检查,没有启动、停止、迁移或删除任何服务或数据。
## 检查结果 删除前,旧 Compose 栈已经没有容器;再次确认三个旧卷没有任何容器引用后,
按完整卷名逐个删除,并检查卷列表确认它们均不存在:
- `docker ps -a` 按 Compose project `victoriametrics` 筛选,没有容器; | 已删除卷 | 删除前内容 |
按 VictoriaMetrics、vmagent、vmalert、Grafana、Alertmanager 名称及镜像筛选也没有旧栈容器。 |---|---|
- 三个 Docker 卷仍存在,按卷筛选所有容器,没有发现引用它们的容器。 | `victoriametrics_vmdata` | 约 131 MiB,包含历史指标数据与索引 |
- Kubernetes `monitoring` 中 VMSingle/main 和 VMAgent/main 状态为 operational; | `victoriametrics_vmagentdata` | 空目录,占用约 4 KiB |
Grafana、指标、日志、追踪及相关采集组件的 Pod 处于 Running。 | `victoriametrics_grafanadata` | 约 45 MiB,包含旧 grafana.db 和插件等 |
- 新栈的 Grafana、VMSingle、VLSingle、VTSingle PVC 均为 Bound。
这些资源状态不等于已经验证新旧数据一致或完成全部端到端采集验收。
| 旧 Docker 卷 | 磁盘占用(du -sh) | 保留内容 | 源码仓库 `apps/victoriametrics/` 下的 13 个受管文件已删除,平台文档和告警规则注释
|---|---|---| 中的旧路径引用已修正。旧配置可以从 Git 历史找回;不能通过 Git 恢复已删除的数据卷内容。
| `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 等目录 |
元数据统计确认 `data/` 下有 247 个文件,逻辑大小合计 118,467,976 字节; 基础设施清理已通过 [PR #73](https://git.ddupan.top/panxiao81/homelab-infra/pulls/73)
`indexdb/` 下有 173 个文件,逻辑大小合计 11,864,570 字节。 于 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 配置”处理。 这些检查确认清理范围及新栈资源状态,不宣称新旧历史数据完成迁移。
本机没有运行中的旧栈容器,本轮也没有可直接查询的旧实例;未为检查数据而启动旧实例。 现役监控的维护入口为 homelab-infra `platform/observability/README.md`。
没有读取 Grafana 数据库内容或凭据,也没有执行历史样本查询。
下一步若需要保留、恢复或迁移历史数据,应先与维护者确定目标,再安排独立工作。
在此之前保留三个卷,不运行 `docker compose down -v` 或将它们纳入未使用卷清理。
旧数据当前没有容器引用,不能因此视为可安全删除。
## 文档与代码归属
- 旧 Compose 配置:homelab-infra `apps/victoriametrics/compose.yaml`。
- 新可观测性栈: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()
+145 -22
View File
@@ -1,15 +1,19 @@
# 待核实与文档缺口 # 首轮状态对齐记录(已完成)
审阅日期:2026-09-16;初版依据工作区,后续按维护者说明和指定资料对齐。 **2026-09-16,维护者确认本轮待核实事项已结束;当前没有开放的状态核实任务。**
旧 VictoriaMetrics Compose 已获授权做有限现场检查,其余项目未因本清单自动查询现场。
下面的检查方法只是候选步骤,执行前先问维护者当前进度及查询范围。 结论来自维护者说明、指定的项目文档与 ticket,以及旧监控栈的授权检查和清理。
以下路径相对于 homelab-infra。优先修复影响恢复、认证、DNS 和首次使用的问题。 本轮完成不等于所有服务都经过现场检查,也不等于各开发项目全部完工。
下文保留对齐结果;后续写作与源码文档同步移至[文档完善清单](documentation-backlog.md)。
动态实施进度继续由各项目文档和 ticket 维护,不另开一轮全量状态盘点。
## 已对齐的动态工作 ## 已对齐的动态工作
NATS 已作为集群共享服务部署,当前唯一消费者为 Dynamic Runner,见 [NATS](services/nats.md)。 NATS 已作为集群共享服务部署,当前唯一消费者为 Dynamic Runner,见 [NATS](services/nats.md)。
维护者明确 Dynamic Runner 正在积极开发,其启用范围、durable 名称和实现进度以 维护者明确 Dynamic Runner 正在积极开发,其启用范围、durable 名称和实现进度以
[项目文档](https://git.ddupan.top/panxiao81/gitea-dynamic-runner)为准。 [项目文档](https://git.ddupan.top/panxiao81/gitea-dynamic-runner)为准。
维护者补充动态 Pod 已上线测试、系统总并发 4,VM 正在工作、系统总并发 1;
纯 self-hosted runner 准备退役。使用入口见 [Gitea / Actions](services/gitea.md)。
不再将旧示例的 durable 名称差异或启用范围列为独立待核实项。 不再将旧示例的 durable 名称差异或启用范围列为独立待核实项。
NATS 原生通过 Account 隔离租户,跨 Account 的名称不构成全局冲突; NATS 原生通过 Account 隔离租户,跨 Account 的名称不构成全局冲突;
runner 的队列协调约定仅在其所属 Account 和 stream 范围内讨论。 runner 的队列协调约定仅在其所属 Account 和 stream 范围内讨论。
@@ -28,27 +32,25 @@ SPIFFE/SPIRE 按维护者指定,以 [#34](https://git.ddupan.top/panxiao81/hom
原工作区集群总览的“首次上线待验证”不作为当前阶段判断。 原工作区集群总览的“首次上线待验证”不作为当前阶段判断。
详见 [SPIFFE/SPIRE 使用入口与阶段状态](services/spire.md);源码工作区本轮未修改。 详见 [SPIFFE/SPIRE 使用入口与阶段状态](services/spire.md);源码工作区本轮未修改。
## 待向维护者确认的记录差异 ## 旧监控栈清理结果
初轮列出的状态差异已按维护者说明、指定资料或授权检查完成分类;不再保留自动现场核查任务。 初轮列出的状态差异已按维护者说明、指定资料或授权检查完成分类;不再保留自动现场核查任务。
[旧 VictoriaMetrics Compose](services/victoriametrics-legacy.md) 已于 2026-09-16 只读检查: [旧 VictoriaMetrics Compose](services/victoriametrics-legacy.md) 已于 2026-09-16 完成清理:
旧栈无容器,三个旧卷仍存在且无容器引用;VM 卷约 131 MiB、Grafana 卷约 45 MiB。 维护者明确要求直接删除旧配置和全部数据卷,三个无引用 Docker 卷及旧配置均已删除,
新 Kubernetes 栈的资源状态正常,但没有验证数据迁移或新旧数据一致性。 未备份或迁移数据。新 Kubernetes 栈的资源状态检查和指标清单渲染通过。
旧数据暂时保留,是否恢复、迁移或删除需先由维护者决定。 基础设施清理已通过 [PR #73](https://git.ddupan.top/panxiao81/homelab-infra/pulls/73)
合并 main(`9c64d31`);配置交付和数据处置均已完成。
## 优先补充的使用说明 ## 已确认的归属与范围
1. Gitea / Actions:登录、创建仓库、选择 runner,以及可信任务限制。 - 维护者于 2026-09-16 指定 Samba AD、OCI、Proxmox 优先 IaC、以代码为准;
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 说明 codex-proxy“应该是退役的”,已从现役应用列表移至归档范围;
未查询运行环境,也没有删除源码或数据。LiteLLM、Tailscale、ps3netsrv、vlmcsd 无需补充动态事项,
已基于仓库配置补使用指南;这不等于新增的现场验收。
- `docs/cicd.md` 提及 `rustfs`,但无独立组件目录;需要先向维护者确认现状与归属。
- e5renew 和 research-auto 已由维护者明确为 GitHub 上的[外部消费者](services/external-consumers.md), - e5renew 和 research-auto 已由维护者明确为 GitHub 上的[外部消费者](services/external-consumers.md),
不属于 homelab 基础设施,不再列为盘点盲区或缺失组件。 不属于 homelab 基础设施,不再列为盘点盲区或缺失组件。
- `gitea-microvm-runner` 已更名 `gitea-dynamic-runner`,按维护者指定查阅 README, - `gitea-microvm-runner` 已更名 `gitea-dynamic-runner`,按维护者指定查阅 README,
@@ -58,7 +60,128 @@ SPIFFE/SPIRE 按维护者指定,以 [#34](https://git.ddupan.top/panxiao81/hom
operator 仍按项目记录标为 API 骨架阶段;本轮未查询运行环境。 operator 仍按项目记录标为 API 骨架阶段;本轮未查询运行环境。
- workload-sts 已按维护者提供的信息查阅:仓库已归档,停止开发、不部署 PoC, - workload-sts 已按维护者提供的信息查阅:仓库已归档,停止开发、不部署 PoC,
作为[早期设计与替代决策的历史来源](architecture/workload-sts-history.md)保留,不列为待接入服务。 作为[早期设计与替代决策的历史来源](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);
未部署或进行现场验收。
凭据存储切片及冷缓存准备修复已通过 CI #815 的 test、lint、database-integration,
维护者批准后合并 [PR #12](https://git.ddupan.top/panxiao81/ayatori/pulls/12),合并提交
[22ab72e](https://git.ddupan.top/panxiao81/ayatori/commit/22ab72ec60dd5a0bf852e4563e107597dd56e81f)。
后续 Kubernetes 认证与短期会话续期已提交为
[f0aa86f](https://git.ddupan.top/panxiao81/ayatori/commit/f0aa86f67673fbfb5f182f3ce35679c614be968d),
由 [PR #13](https://git.ddupan.top/panxiao81/ayatori/pulls/13) 跟踪 CI 与 review。
首版依赖投射 SA 文件的假设已按维护者意见撤除:集群外 kubeconfig 与集群内配置共用 manager
客户端,通过受限 TokenRequest 获取登录 JWT。manager 显式配置、Runnable 与 readiness 已装配;
三轮真实 API/OpenBao race、本地全量测试与两种 lint 通过,覆盖 RBAC 撤回/恢复和越权拒绝。
源码文档与 wiki 已同步边界和正式链接;后续合并及 CI 结果见下文,不把本地验证等同于远端 CI;
未部署生产 auth/RBAC,也未接入 Database 供应或 ESO 交付。
同一 PR 的公共 infra 拆分已提交为
[65c60cc](https://git.ddupan.top/panxiao81/ayatori/commit/65c60cca4528bc8bf14783fb7b59922283059c02)。
Bao client/TLS 与认证不再归 Database;Secret 凭据适配器注入 manager 的直连 reader,
领域继续维护凭据格式和写入结果语义。分层约定已同步
[控制面边界](architecture/ayatori-control-plane.md#controller-公共基础设施边界)及源码文档。
全量单元/API 测试、真实 PostgreSQL/OpenBao 集成、公共 infra race 与两种 lint 本地通过;
最终 head 为 `356e216`,包含 bootstrap 职责拆分、配置测试与真实 API 启动测试。
2026-09-27 维护者批准合并为
[6b2808c](https://git.ddupan.top/panxiao81/ayatori/commit/6b2808ce91b03215f466746a15d0c3d7442bb9d4)。
请求设置了 `merge_when_checks_succeed=true`、`force_merge=false`,但 Gitea 在
database-integration 仍运行时执行了合并,不能将自动合并参数视为全部 CI 通过的保证。
随后确认 CI #931 已结束,test、lint、database-integration 全部成功;不声称已部署。
## 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 源码当时尚未提交,固定版本现关联 [合并提交 f6d12d6](https://git.ddupan.top/panxiao81/homelab-infra/commit/f6d12d6);
服务恢复不等于全部整改完成。
## 共享 etcd 与 PostgreSQL 来源同步
2026-09-25 shared etcd 三成员、新 PG 生产主从与开发实例、稳定入口、本地备份已部署,
监控 CR 已现场应用。OIDC 恢复后,专用身份与 etcd/PG 每日续签均已启用;此前 Bao 权限阻塞已解除。
真实 PG 自动切换、回切、SQL/TLS、备份恢复与配置幂等通过,边界见
[共享 PostgreSQL](services/shared-postgresql.md#k3s-外实例的实现与验收边界2026-09-25)和
[共享 etcd](services/shared-etcd.md)。
源码 `infrastructure/etcd/`、`infrastructure/shared-postgresql/`、DNS 和监控已提交至 [IaC PR #159](https://git.ddupan.top/panxiao81/homelab-infra/pulls/159),已合并。
2026-09-25 合并后现场验证:Flux observability Ready,应用版本 `f6d12d6`;
两份 VMRule 和两份 VMStaticScrape 均在 Flux inventory 中,状态 operational。
三个 etcd 和两个 Patroni 目标均 up=1,相关 11 条规则 health=ok、inactive。
监控声明已由 GitOps 接管。既有 CNPG 应用未迁移,异地备份后置;数据库细项告警仍待补齐。
Ayatori 按维护者决定继续使用独立控制面,本轮只准备接入材料,尚未验收 controller/Instance Ready。
两仓事实已同步,源码文档已直接推送 main:[文档 acd4b55](https://git.ddupan.top/panxiao81/homelab-infra/commit/acd4b55);IaC 固定版本为
[3a2fe5f](https://git.ddupan.top/panxiao81/homelab-infra/commit/3a2fe5f)。
## laptop ARC 预算(2026-09-27)
维护者授权的 4 GiB 上限已在线应用并持久化,Ansible 复查零变更。
源码 [PR #165](https://git.ddupan.top/panxiao81/homelab-infra/pulls/165) 已获授权并合并至 main,
提交为 [06943d4](https://git.ddupan.top/panxiao81/homelab-infra/commit/06943d4c6583f1b62fea6176b56f237da54a12e7),与已部署配置一致。
配置及验证范围见 [ARC 内存预算](guides/laptop-arc-budget.md)。本次合并未重复应用或重启主机;下一次更新负载下的效果仍待观察。
## 共享数据维护告警接管边界
2026-09-27 主机端采集、低开销 exporter 和三目标网络验证完成,6 项采集测试及 12 个新增规则场景通过。
相关 [PR #166](https://git.ddupan.top/panxiao81/homelab-infra/pulls/166) 已合并,版本
[589c34e](https://git.ddupan.top/panxiao81/homelab-infra/commit/589c34e)。现场确认 Flux observability Ready,
VMStaticScrape/PrometheusRule 已入 inventory;converter 生成的 VMRule 为 operational。
三个目标均 up=1,八条规则 health=ok、inactive,新增告警已启用。
详细事实见[维护告警](services/shared-postgresql.md#维护告警2026-09-27)。现有 PR #159 的接管验收不受影响。
## iam-login Hydra 接入的来源同步(2026-09-28)
[Hydra 服务页](services/hydra.md#独立登录服务的-hydra-接入)中的新增 Login/Consent、客户端
管理与注销实现已签名提交并推送,固定源码为
[62b6e9d](https://git.ddupan.top/panxiao81/iam-login/commit/62b6e9d),包含在
[PR #6](https://git.ddupan.top/panxiao81/iam-login/pulls/6),尚未合并。此前 GPG agent 阻塞已解除。
本轮 wiki 同步实现边界与隔离验收结果,不代表生产入口已切换。