使用 FluxCD 构建 Homelab GitOps:从私有 Git 仓库到 Hoteler 自动部署
使用 FluxCD 构建 Homelab GitOps:从私有 Git 仓库到 Hoteler 自动部署
最近我重新整理了自己的 Homelab 部署方式。
过去 Kubernetes 应用虽然已经使用 Kustomize管理,但本质上仍然需要人为执行部署操作。既然集群已经运行FluxCD,更合理的方式应该是:
Git 描述期望状态,FluxCD 负责让 Kubernetes 的实际状态持续向 Git
中的状态收敛。
这次以 Hoteler 为例,将现有 Kustomize 部署配置接入FluxCD,并将应用源码、应用部署配置和集群配置拆分。
1. 仓库职责划分
整个 GitOps 体系拆成三个部分:
Application Repository
hoteler 是应用源码仓库,负责:
1 | Source Code |
CI 最终产生类似:
1 | ghcr.io/damingerdai/hoteler:v0.0.5 |
这样的应用镜像。
应用仓库本身不直接操作 Kubernetes。
Application GitOps Repository
独立的 hoteler-deployment 仓库负责描述:
Hoteler 应该以什么状态运行。
目录类似:
1 | hoteler-deployment/ |
这里使用 Kustomize 的 Base + Overlay 模式管理不同环境。
Fleet Repository
fleet-infra 负责回答:
某个 Kubernetes Cluster 应该运行哪些应用?
例如:
1 | fleet-infra/ |
三个仓库的职责:
1 | hoteler |
2. GitRepository 与 Kustomization
FluxCD 中的核心关系可以理解为:
1 | GitRepository |
GitRepository 解决:
Flux 去哪里获取配置?
Kustomization 解决:
获取 Repository 后,应该部署其中哪个目录?
这里需要区分两个同名但不同的 Kustomization。
Flux CRD:
1 | apiVersion: kustomize.toolkit.fluxcd.io/v1 |
负责告诉 Flux 持续 reconcile Git 中的某个目录。
Kustomize 自己的配置:
1 | apiVersion: kustomize.config.k8s.io/v1beta1 |
负责组合 Deployment、Service、ConfigMap 等 Kubernetes Manifest。
因此实际关系是:
1 | Flux GitRepository |
3. 接入私有 GitOps Repository
hoteler-deployment 位于 Homelab 内部的私有 Git 服务:
1 | ssh://[email protected]:1022/hoteler/hoteler-deployment.git |
首先为 Flux 创建 SSH Credential:
1 | flux create secret git hoteler-deployment-auth \ |
Flux 会生成 SSH Deploy Key,并创建:
1 | Secret/hoteler-deployment-auth |
将生成的 Public Key 添加到私有 Git Repository 的 Deploy Keys 中即可。
目前 Flux 只需要读取部署配置,因此只需要 Read 权限。
4. 创建 GitRepository
在 fleet-infra 中创建:
1 | clusters/192.168.31.222/apps/hoteler-source.yaml |
1 | apiVersion: source.toolkit.fluxcd.io/v1 |
形成:
1 | GitRepository/hoteler-deployment |
5. 让 Fleet Repository 加载应用
clusters/192.168.31.222/apps/kustomization.yaml:
1 | apiVersion: kustomize.config.k8s.io/v1beta1 |
Cluster 根目录:
1 | clusters/192.168.31.222/kustomization.yaml |
1 | apiVersion: kustomize.config.k8s.io/v1beta1 |
这样 Flux Bootstrap 管理 clusters/192.168.31.222 时,就能继续发现apps 中声明的资源。
6. 验证私有 Git Repository
通过:
1 | flux get sources git -A |
检查:
1 | NAMESPACE NAME REVISION READY |
hoteler-deployment READY=True 意味着:
1 | Flux |
整条 Source 链路已经成功建立。
7. 使用 Flux Kustomization 部署 Hoteler
增加:
1 | clusters/192.168.31.222/apps/hoteler-api.yaml |
1 | apiVersion: kustomize.toolkit.fluxcd.io/v1 |
组合起来表达的是:
使用
hoteler-deploymentRepository 中的hoteler-api/overlays/lan
作为当前集群中 Hoteler API 的期望状态。
1 | fleet-infra |
8. Base 与 Overlay 的 Namespace 设计
部署过程中遇到的一个问题是 Namespace。
最初 Base 中存在:
1 | namespace: hoteler-namespace |
但 LAN 环境希望部署到:
1 | hoteler-dev-namespace |
对于这个项目,更合理的职责是:
1 | base |
既然 Namespace 属于环境差异,就由 Overlay 决定。
Base:
1 | apiVersion: kustomize.config.k8s.io/v1beta1 |
LAN 环境增加:
1 | overlays/lan/namespace.yaml |
1 | apiVersion: v1 |
然后:
1 | overlays/lan/kustomization.yaml |
1 | apiVersion: kustomize.config.k8s.io/v1beta1 |
最终生成:
1 | Namespace/hoteler-dev-namespace |
9. 实际踩坑:Base 中固定 Namespace
最开始 Base 中存在:
1 | namespace: hoteler-namespace |
导致 configMapGenerator 生成的 ConfigMap 仍然属于:
1 | hoteler-namespace |
而 LAN Overlay 创建的是:
1 | hoteler-dev-namespace |
Flux 因此报告:
1 | ConfigMap/hoteler-namespace/hoteler-api-config-td7c9kg7m5 not found: |
删除 Base 中固定的 Namespace,让 Overlay 统一决定环境 Namespace 后解决。
这里得到的经验是:
Base 尽可能描述环境无关的应用结构;真正因环境不同而变化的内容交给
Overlay。
10. Flux 不需要手动 Reconcile
调试时可以执行:
1 | flux reconcile kustomization flux-system --with-source |
立即触发 reconciliation。
但它不是正常部署流程必须执行的命令。
正常流程应该是:
1 | git push |
所以日常修改 hoteler-deployment 后只需要:
1 | git add . |
Flux 会自动完成后续操作。
可以使用:
1 | flux get kustomizations -A --watch |
观察 reconciliation。
GitOps 最终希望达到的效果就是:
1 | git push |
而不是:
1 | git push |
11. 最终链路
修复 Namespace 后,Flux 成功创建 hoteler-dev-namespace,并创建 Hoteler
Deployment。
Pod 被 Kubernetes Scheduler 分配到节点后,kubelet 开始拉取:
1 | ghcr.io/damingerdai/hoteler:v0.0.5 |
完整链路:
1 | fleet-infra |
12. 当前架构总结
最终三个 Repository 分别回答三个问题:
hoteler
我要构建什么软件?
负责源码、测试、CI 和 Container Image。
hoteler-deployment
这个软件应该怎么运行?
负责 Kustomize Base、Overlay、镜像版本和环境配置。
fleet-infra
哪个 Cluster 应该运行这个软件?
负责 FluxCD、Cluster 和 Application GitRepository/Kustomization。
把三个职责拆开以后,整个部署模型更加清晰。
13. 下一步
下一步可以继续引入 Flux Image Automation:
1 | ImageRepository |
最终实现:
1 | Application Commit |
从而形成完整的 GitOps 发布闭环。
