先渲染,再写入集群
Kustomize 不是模板语言,它以 Kubernetes YAML 为基础,通过 resources、patches、images、namespace 等机制组合最终 manifests。kubectl 已内置常用 Kustomize 能力:
| |
前者只渲染到标准输出,不修改集群;后者把渲染结果提交给 API Server。
一个稳妥习惯是:
| |
本项目的 Kustomize 分层
| |
deploy/operator 与 deploy/gateway 是独立入口。安装 Operator 不会自动安装 Gateway,也不会创建 SubPool 或 Secret。
这能防止一次看似普通的控制面安装,顺便启动真实代理或创建业务实例。
resources 是组合,不是复制
例如 config/default/kustomization.yaml 引用:
| |
Kustomize 递归加载这些资源,形成一个最终对象集合。deploy/operator 再引用 config/default,并通过 images 修改 Operator 镜像。
因此修改基础文件会影响所有引用它的入口。排查最终内容时,不要只看当前目录那几行 kustomization,要渲染完整结果。
images transformer 做什么
项目通过:
| |
把基础 Deployment 中的镜像名称和 tag 替换为环境要使用的版本。
远程集群必须能从它自己的节点网络拉取该镜像。本地电脑能 docker pull,不代表集群 Node 一定能拉取。
生产更推荐不可变版本或 digest,并在发布前确认:
- registry 可达;
- 私有仓库凭据已配置;
- CPU architecture 匹配;
- 镜像 tag/digest 正确;
- imagePullPolicy 符合预期。
Dockerfile 的两阶段构建
项目先在 Go 镜像中编译静态 manager,再复制到 distroless nonroot 镜像:
| |
优点是最终镜像不包含完整编译工具链和 shell,体积与攻击面更小。代价是进入容器临时执行 shell 命令并不可用,排障应依赖日志、metrics、健康端点和 Kubernetes 对象,而不是假设能 sh 进去。
部署前本地验证
项目提供:
| |
这些命令不向集群写资源。它们分别验证 Go 行为和 manifests 能否渲染,并检查渲染结果是否违反项目约束。
本地通过不保证集群部署一定成功,因为 StorageClass、Gateway API、镜像仓库和 CNI 等依赖属于目标环境。
推荐部署顺序
第一步:构建并准备 Operator 镜像
| |
远程集群需推送到可拉取 registry,并更新 deploy/operator/kustomization.yaml。
第二步:渲染并安装 Operator Bootstrap
| |
这会安装:
subpool-systemNamespace;- SubPool CRD;
- RBAC;
- immutable Operator Configuration;
- Operator Deployment;
- metrics Service;
- Operator PDB。
检查:
| |
第三步:按需安装共享 Gateway
先通过安全流程创建 mihomo-gateway-providers Secret,再执行:
| |
这会安装 subpool-gateway Namespace、Shared Mihomo、GatewayClass 和 Gateway。它不会安装 Envoy Gateway controller,也不包含 Secret value。
检查:
| |
第四步:创建第一个 Internal Pool
| |
Internal 是最适合第一次验证的模式,因为它不依赖外部 DNS、TLS 和 Gateway route。
创建后的观察顺序
| |
等待 Ready:
| |
若超时,立即转为 Conditions 驱动的排查,不要反复 apply 同一文件期待随机恢复。
Internal 模式的访问
| |
两个命令需要分别占用一个持续运行的终端。它们只适合开发与受控管理访问。
更新操作
镜像或 CPU/内存资源应修改 SubPool spec,由 Operator 同步到 StatefulSet。生产镜像优先使用 digest。
不要直接编辑受管 StatefulSet。即使暂时成功,下一轮 reconcile 也会按 SubPool 恢复。
storage.size 当前不可修改。若业务需要更大容量,必须先设计受支持的数据迁移或未来扩容流程,不能通过手工改 PVC 与 CR 制造状态分叉。
暂停与恢复
暂停:
| |
预期结果:
- StatefulSet replicas 为 0;
- HTTPRoute 被删除;
- Namespace、PVC、Secret 保留;
- Ready=False,reason 为 Suspended。
恢复:
| |
Operator 会重新创建运行 Pod,并继续使用旧 PVC。
删除前先停一下
| |
删除会销毁专属 Namespace、PVC、Credential Secret 和运行数据。当前项目不提供备份恢复。
不要使用 --force,不要手工删除 subrelay.example.com/finalizer。如果只是临时不用,选择 suspend。
删除卡住时检查:
| |
关注 DeletionBlocked、Namespace/PVC finalizers 以及负责相关资源的第三方 controller。
Conditions 驱动的排障地图
| Condition/Reason | 首要对象 |
|---|---|
OperatorConfigurationInvalid | subpool-system 中版本化 ConfigMap 与 Operator 参数 |
InvalidPoolResources | SubPool 的 requests/limits |
ResourcesExceedBaseline | SubPool 合计申请与 maxPerPool |
NamespaceConflict | 派生 Namespace labels、ownerReferences、UID |
CredentialConflict | subpool-credentials ownerReferences |
CredentialInvalid | Secret 必需 key 是否存在且非空,不读取 value |
WorkloadMissing | StatefulSet 是否创建 |
WorkloadsNotReady | Pod、PVC、镜像、探针和 Event |
ServiceMissing | CPA 与 cpa-manager Service |
EndpointsUnavailable | Shared Mihomo Pod 与 EndpointSlice |
RouteNotAccepted | HTTPRoute parent conditions 与 allowedRoutes |
GatewayNotProgrammed | Envoy Gateway controller 和 Gateway status |
NamespaceTerminating | Namespace 内资源及第三方 finalizers |
三层排障法
第一层:API 与控制器
| |
确认 CR 被接受、generation 被观察、Operator 没有 Forbidden 或 reconcile error。
第二层:Kubernetes 资源
| |
确认调度、存储、镜像和探针。
第三层:数据路径
| |
每次只验证相邻两个跳点,避免一句“网络不通”覆盖十种不同故障。
不要用破坏架构的方式排障
以下动作可能让表面症状消失,却破坏项目边界:
- 删除 default-deny NetworkPolicy;
- 给 CPA 临时开直接公网出站后忘记恢复;
- 把 CPA Service 改成每 Pool LoadBalancer;
- 给 cpa-manager 创建公网 Route;
- 强删 Namespace 或 finalizer;
- 手工覆盖 Credential Secret;
- 直接修改 Operator 管理的 StatefulSet。
更可靠的做法是记录具体 Condition、对象、Event 和时间点,修复负责该层的依赖,再验证状态是否自然收敛。
最终验收清单
- Operator 两个 Pod 正常,leader election 无持续错误;
- SubPool CRD 已安装,
kubectl get sp可用; - Operator Configuration 名称与 Deployment 参数一致;
- Shared Mihomo 有 Ready Endpoint;
- SubPool 派生 Namespace 所有权正确;
- runtime StatefulSet、PVC、两个 Service 均存在;
- Pod probes Ready,重启次数无异常增长;
- Internal 模式 port-forward 可用,或 Gateway 模式 Route Accepted 且 Gateway Programmed;
metadata.generation == status.observedGeneration;Ready=True的含义没有被误解为账号和真实模型请求也已验证。
部署完成不是“apply 命令退出码为 0”,而是从声明、控制器、资源到数据路径都有证据证明系统达到了它承诺的状态。