我的 Homelab 架构梳理:双 K3s 集群的 IaC 与 GitOps 实践
目录
这篇的状态(2026-08-20 补记):下面写的是 2026-02-28 那一版架构。之后有几处变动大到会让原文失真,先列在这里,正文细节我没有逐段回填:
- CNI 和入口层换掉了:两个集群在 3 月初都从 Flannel 迁到了 Cilium;homelab 随后又启用 kube-proxy replacement,并用 Cilium Gateway API 顶掉了 K3s 自带的 Traefik。原文里凡是出现 Traefik 的地方(外部流量路径、ForwardAuth),只对 3 月之前的 homelab 成立。oracle-k3s 在迁移时刻意留着 Traefik 没动,后来只补上了 kube-proxy replacement。
- 跨集群多了一层 ClusterMesh:Tailscale 仍是底层通道,但两个集群之间接上了 Cilium ClusterMesh(当时只用到节点发现和身份联邦,没用跨集群 Service)。
- 节点的 Tailscale IP 换过,原文里的
100.107.254.112早就不是当前值。- Kopia 备份和 KaraKeep 都已停用,相关内容已经从正文里去掉,当时的实现记录留在备份体系和信息管道两篇里。
- 服务清单只跟到 2026-02 那一批:Stirling-PDF 已经换成 BentoPDF(表里改过来了),后来上线的 Playgrounds、Jobs SG、Trends、Excalidraw、Open Notebook 还没补进去。
网络这一层的当前状态,以这三篇为准:homelab CNI 迁移、oracle-k3s 迁移、ClusterMesh。
为什么写这篇文章#
从 2024 年用 Docker Compose 起步,到现在运行着两个 K3s 集群、十几个服务、完整的 GitOps 流水线——这个 Homelab 项目已经迭代了很多轮。每次新增功能都会写一篇专题博客,但一直缺少一篇把所有东西串起来的全景文章。
这篇文章更像是那张地图。它不会深入每个组件的部署细节(那些在各自的博客里),而是回答一个问题:这些东西现在是怎么组合在一起工作的?
整体架构#
整个 Homelab 分为五层:
┌─────────────────────────────────────────────────────────────────┐
│ Layer 5: GitOps │
│ ArgoCD — 自动同步 Git → 集群,3 分钟轮询 │
├─────────────────────────────────────────────────────────────────┤
│ Layer 4: External Access & Security │
│ Cloudflare Tunnel + DNS + WAF ← Terraform │
│ ZITADEL SSO + oauth2-proxy ForwardAuth │
├─────────────────────────────────────────────────────────────────┤
│ Layer 3: Applications │
│ Helm Charts + Raw K8s Manifests │
│ 十几个服务分布在两个集群 │
├─────────────────────────────────────────────────────────────────┤
│ Layer 2: Kubernetes │
│ K3s 单节点集群 × 2(Ansible 安装) │
│ Tailscale 跨集群 Pod/Service 网络互通 │
├─────────────────────────────────────────────────────────────────┤
│ Layer 1: Infrastructure │
│ Proxmox VE (本地) + Oracle Cloud (远端) ← Terraform │
└─────────────────────────────────────────────────────────────────┘
Layer 1: 基础设施#
Proxmox 虚拟机(本地集群)#
Homelab 的物理基础是一台旧 Laptop,运行 Proxmox VE 虚拟化平台。通过 Terraform 在上面创建一台 Ubuntu 虚拟机:
proxmox/
├── terraform/ # IaC: VM 规格、网络、磁盘
├── ansible/ # 下载 cloud image、生成 VM 模板
- 节点 IP:
10.10.10.10(LAN)/100.107.254.112(Tailscale,这个值后来变过,见文首补记) - Proxmox 主机:
192.168.50.3 - 存储: NFS 服务器
192.168.50.106:/export,通过nfs-clientStorageClass 提供 PV
Oracle Cloud(远端集群)#
利用 Oracle Cloud 的永久免费 ARM 实例,通过 Terraform 创建一台 VM:
cloud/oracle/
├── terraform/ # OCI VM 资源
├── ansible/ # 节点初始化
├── manifests/ # 工作负载 YAML
- 节点 IP:
10.0.0.26(VCN)/100.107.166.37(Tailscale)
两个节点通过 Tailscale 互联,形成一个跨地域的虚拟网络。
Layer 2: Kubernetes#
两个集群都使用 K3s(轻量级 K8s 发行版),通过 Ansible 自动安装:
cd k8s/ansible && just setup-k8s # homelab 集群
cd cloud/oracle/ansible && just setup # oracle-k3s 集群
跨集群网络:Tailscale Subnet Routing#
这是这套架构里比较关键的一层网络设计。两个集群通过 Tailscale 的子网路由功能实现 Pod/Service 网络互通:
homelab 广播: 10.42.0.0/16 (Pod) 10.43.0.0/16 (Service)
oracle-k3s 广播: 10.52.0.0/16 (Pod) 10.53.0.0/16 (Service)
效果是:oracle-k3s 上的 Pod 可以直接访问 homelab 的 ClusterIP(如 10.43.158.192 — ArgoCD),反之亦然。延迟约 80ms,就我目前的使用场景看,这对监控和异步通信已经基本够用。
这使得很多有趣的架构成为可能:
- Uptime Kuma(oracle-k3s)通过 ClusterIP 直接监控 homelab 的所有服务
- 集中式 Vault(homelab)为两个集群的 ExternalSecret 提供密钥
Layer 3: 应用服务#
服务全景#
两个集群上的主要服务:
| 服务 | 集群 | 用途 | URL |
|---|---|---|---|
| Grafana | homelab | 可观测性仪表盘 | grafana.meirong.dev |
| ArgoCD | homelab | GitOps 持续部署 | argocd.meirong.dev |
| HashiCorp Vault | homelab | 密钥管理 | vault.meirong.dev |
| ZITADEL | homelab | SSO 身份提供者 | auth.meirong.dev |
| Calibre-Web | homelab | 电子书管理 | book.meirong.dev |
| Gotify | homelab | 推送通知 | notify.meirong.dev |
| Homepage | oracle-k3s | 导航仪表盘 | home.meirong.dev |
| IT-Tools | oracle-k3s | 开发者工具集 | tool.meirong.dev |
| BentoPDF | oracle-k3s | PDF 处理工具 | pdf.meirong.dev |
| Squoosh | oracle-k3s | 图片压缩 | squoosh.meirong.dev |
| Miniflux | oracle-k3s | RSS 阅读器 | rss.meirong.dev |
| Uptime Kuma | oracle-k3s | 可用性监控 | status.meirong.dev |
| Redpanda Connect | oracle-k3s | 流处理引擎 | 内部服务 |
| PostgreSQL | oracle-k3s | 关系数据库 | 内部服务 |
(homelab 侧 ZITADEL 自带的 PostgreSQL 没有单列;后来新上线的几个服务见文首补记。)
集群分工原则#
- homelab:运行基础设施服务(Vault、ArgoCD、Grafana)和需要 NFS 持久化存储的应用(如 Calibre-Web)
- oracle-k3s:运行无状态或轻量有状态的面向用户服务(工具类、RSS、Homepage),利用 Oracle Cloud 免费的公网带宽
可观测性:LGTM Stack#
Homelab 集群运行完整的 LGTM 可观测性栈:
- Prometheus — 指标采集(homelab 本地 scrape)
- Loki — 日志聚合
- Tempo — 分布式追踪
- Grafana — 统一仪表盘
我目前给多集群监控定下的一条约定是:所有指标都尽量带上 cluster 标签。
- homelab:Prometheus
scrapeClasses为所有本地指标添加cluster=homelab - oracle-k3s:不部署 Prometheus,而是用一个 OTel Collector DaemonSet 同时采集日志和指标,通过
prometheusremotewrite推送到 homelab 的 Prometheus,自动附加cluster=oracle-k3s
homelab: oracle-k3s:
┌────────────┐ ┌──────────────────┐
│ Prometheus │◄─── scrape ─── │ OTel Collector │
│ (本地指标) │ │ (DaemonSet) │
│ │◄── remote write ────────│ logs → Loki │
│ │ │ metrics → Prom │
├────────────┤ └──────────────────┘
│ Loki │◄── OTLP HTTP ──────────
│ Tempo │
│ Grafana │
└────────────┘
密钥管理:Vault + ESO#
在当前这套设计里,HashiCorp Vault 是密钥的主来源,External Secrets Operator (ESO) 负责把 Vault 中的 Secret 同步到 K8s Secret:
Vault (homelab) K8s Cluster
┌─────────────┐ ┌────────────────┐
│ secret/ │ │ ExternalSecret │
│ homelab/ │◄──── ESO ────│ spec: │
│ grafana │ 同步 │ key: ... │
│ cloudflare│ │ │
│ oracle-k3s/│ │ → K8s Secret │
│ ... │ └────────────────┘
└─────────────┘
两个集群的密钥都存在同一个 Vault 实例中(secret/homelab/* 和 secret/oracle-k3s/*),oracle-k3s 的 ESO 通过 Tailscale 跨集群访问 Vault。
Layer 4: 外部访问与安全#
Cloudflare Tunnel + DNS#
除少数例外外,大多数外部流量都通过 Cloudflare Tunnel 进入,不暴露公网端口:
Internet → Cloudflare DNS (CNAME) → Cloudflare Tunnel → Traefik → Service
两个集群各有一个独立的 Tunnel,DNS 和 Tunnel 配置全部由 Terraform 管理:
cloudflare/terraform/ # homelab tunnel: argocd/auth/book/grafana/vault/...
cloud/oracle/cloudflare/ # oracle tunnel: home/tool/pdf/rss/status/...
例外是那些需要长连接或者跨集群直连的入口:它们不走 Tunnel,而是通过 Tailscale + NodePort 暴露在内网(跨集群的 Loki / Prometheus / Tempo 入口就是这么接的,见双集群全链路追踪)。gRPC 双向流尤其明显——放在 Cloudflare Tunnel 后面会 524 超时。
Cloudflare WAF#
Zone 级 WAF 规则保护 meirong.dev 下所有子域名(两个集群共享):
| 层级 | 规则 |
|---|---|
| Zone 安全设置 | SSL Full、TLS 1.2+、强制 HTTPS、浏览器完整性检查等 8 项 |
| 自定义 WAF (5/5) | 拦截 WP/PHP 扫描路径、敏感文件、恶意 UA、高威胁 IP 质询(这条基于 cf.threat_score,实际上是空转的,原因见 WAF 那篇的补记)、非标准 HTTP 方法 |
| 速率限制 | 认证端点 10 req/10s per IP |
全部在 cloudflare/terraform/waf.tf 中用 Terraform 管理。
SSO 单点登录#
ZITADEL(自托管 OIDC 身份提供者)+ oauth2-proxy(认证代理)实现全站 SSO:
浏览器 → Traefik → ForwardAuth 检查 → oauth2-proxy
│
cookie 有效?
├── 是 → 放行到后端服务
└── 否 → 302 重定向到 ZITADEL 登录
│
登录成功 → 设置 .meirong.dev cookie
→ 7 天免登录
- 受保护服务:book / grafana / vault / argocd / notify / home / pdf
- 公开服务:
status.meirong.dev(状态页)、rss.meirong.dev(Miniflux 自带登录)、tool.meirong.dev、squoosh.meirong.dev
补记:ForwardAuth 这条链是挂在 Traefik 的 Middleware 上的,3 月 homelab 切到 Cilium Gateway API 之后这套配置就不适用了,我还没写新的接法。
Layer 5: GitOps#
ArgoCD#
ArgoCD 运行在 homelab 集群,每 3 分钟轮询 Git 仓库,自动同步变更到集群:
git push → ArgoCD 检测到变更 → 自动 apply YAML → 服务更新
ArgoCD 管理的应用(auto-sync + selfHeal):
| Application | 内容 | 集群 |
|---|---|---|
personal-services |
Calibre-Web, Gotify | homelab |
it-tools |
IT-Tools (Kustomize + Image Updater) | oracle-k3s |
gateway |
Gateway API HTTPRoute | homelab |
cloudflare |
Cloudflare Tunnel 配置 | homelab |
vault-eso |
ESO 配置 + ExternalSecret | homelab |
zitadel |
ZITADEL SSO | homelab |
rss-system |
Miniflux, Redpanda Connect | oracle-k3s |
monitoring-dashboards |
Grafana Dashboard ConfigMap | homelab |
不由 ArgoCD 管理的组件:Vault(需手动 init/unseal)、Prometheus/Loki/Tempo(Helm release)、PostgreSQL(有状态)、NFS Provisioner(基础设施层)。
新增服务时我现在常走的流程#
1. 创建 manifests/<service>.yaml — 定义 K8s 资源
2. 修改 manifests/gateway.yaml — 添加 HTTPRoute
3. 修改 argocd/applications/personal-services.yaml — include 列表
4. 修改 cloudflare/terraform/terraform.tfvars — 添加子域名
5. git push — ArgoCD 3分钟内自动部署
6. cd cloudflare/terraform && just apply — 创建 DNS
7. 更新 Uptime Kuma provisioner — 添加健康检查
ArgoCD Image Updater#
对于需要自动跟踪镜像更新的服务(如 IT-Tools),使用 ArgoCD Image Updater 的 CRD 模式:检测到新镜像后自动写回 Kustomize overlay,触发 ArgoCD 同步。
健康监控#
Uptime Kuma 运行在 oracle-k3s,覆盖两个集群的主要服务(14 个 monitor,内部组件没有全部纳入)。
- oracle-k3s 本地服务:通过 K8s DNS 直接访问(如
homepage.homepage.svc:3000) - homelab 服务:通过 Tailscale 跨集群访问 ClusterIP(如
10.43.70.241— Grafana) - 公开状态页:
status.meirong.dev(不受 SSO 保护)
所有 monitor 定义在 provisioner.yaml 的 Python 脚本中,以代码形式管理。
工具链#
| 工具 | 用途 |
|---|---|
| Terraform | VM 创建(Proxmox、OCI)、Cloudflare DNS/Tunnel/WAF、Tailscale ACL |
| Ansible | K3s 安装、节点配置 |
| Helm | Prometheus stack、Loki、Tempo、Vault、ESO 等 |
| ArgoCD | GitOps 持续部署 |
| just | 任务运行器(替代 Makefile,除 Proxmox Terraform 外) |
| Vault | 密钥管理 |
| ESO | Vault → K8s Secret 同步 |
| Tailscale | 跨集群网络 |
项目结构#
homelab/
├── proxmox/ # Layer 1: Proxmox VM IaC
│ ├── terraform/
│ └── ansible/
├── cloud/oracle/ # Layer 1: Oracle Cloud VM IaC
│ ├── terraform/
│ ├── ansible/
│ ├── cloudflare/ # Oracle Tunnel DNS
│ └── manifests/ # oracle-k3s 工作负载
├── k8s/
│ ├── ansible/ # Layer 2: K3s 安装
│ └── helm/
│ ├── values/ # Layer 3: Helm values
│ └── manifests/ # Layer 3: K8s YAML
├── argocd/ # Layer 5: ArgoCD 配置
│ ├── install/
│ ├── projects/
│ └── applications/
├── cloudflare/terraform/ # Layer 4: DNS + Tunnel + WAF
├── tailscale/terraform/ # Layer 2: 跨集群网络
└── docs/ # 文档、runbooks、plan 记录
演进历程#
回顾这个 Homelab 的发展路径:
| 时间 | 里程碑 |
|---|---|
| 2024-07 | Docker Compose → K8s 迁移 |
| 2025-10 | Proxmox + Terraform + Ansible 自动化 |
| 2025-10 | LGTM 可观测性栈 |
| 2026-02-19 | ArgoCD GitOps + Image Updater |
| 2026-02-20 | Oracle Cloud 第二集群 + Tailscale 互联 |
| 2026-02-21 | OTel Collector 多集群日志/指标 |
| 2026-02-25 | ZITADEL SSO 全站登录 |
| 2026-02-27 | Vault + ESO 密钥管理 |
| 2026-02-28 | 信息管道 + Cloudflare WAF |
接下来#
几个还没做的方向:
- Cert-Manager:自动证书管理(Let’s Encrypt + Cloudflare DNS-01)
- Vault Dynamic Secrets:PostgreSQL 动态凭证,自动轮换
当时列的另外两项后来有了结果:告警推送在 2026-04 接上了(见Alertmanager 通过 Gotify 推送告警),Kopia 备份落地过一轮,但服务本身已经停用。
相关文章#
这篇是架构全景,以下是各组件的深入专题: