KubeBYON 公网访问改造清单(LoadBalancer 方案)

最后更新:2026-04-11

目标:把当前以 NodePort 为中心的公网访问实现,改造成支持多宿主机 / 多节点宿主集群LoadBalancer 方案。

注:该文档属于设计记录。其中多数改造点已经落地,阅读当前行为时请以 current-architecture.mdhttp-api.md 与相关 runbook 为准。


1. 背景

当前 KubeBYON 的 vCluster 公网访问实现以 NodePort 为主,适合单机或“单固定入口”场景,但对真正的多机宿主集群支持还不完整。

当前代码中的几个关键限制:

  1. vCluster Service 暴露模式只围绕 NodePort / ClusterIP 设计
  2. clusters 表只保存一个 control_plane_host,默认更像“单固定入口”
  3. 创建和更新流程都默认 public_access_enabled=true -> NodePort
  4. 当时前端与系统设置里还没有“公网暴露模式”概念
  5. 多机部署时,即使宿主 k3s 能调度多个 vCluster control plane,对外入口仍然容易绑定到某一台宿主机 IP

因此,本次改造选择:

  • 保留现有 public_access_enabled
  • 增加 public_access_mode
  • 新增并支持 loadbalancer 模式
  • 第一阶段要求 LoadBalancer 模式下显式提供 control_plane_host

2. 改造目标

2.1 本次目标

  1. 支持集群公网访问模式:
    • nodeport
    • loadbalancer
  2. 关闭公网访问时仍然落到 ClusterIP
  3. 管理员可配置“新建集群默认公网模式”
  4. 前端可在创建集群、编辑集群时选择模式
  5. 后端在 LoadBalancer 模式下正确返回:
    • api_endpoint
    • kubeconfig
    • 连接探测结果
  6. 文档补齐多机部署前提(MetalLB / 云 LB 等)

2.2 第一阶段约束

为避免 TLS SAN 与动态地址不匹配,第一阶段约束如下:

  • public_access_enabled=truepublic_access_mode=loadbalancer 时:
    • control_plane_host 必须非空
    • 后端需把该地址注入 vCluster extraSANs

也就是说,第一阶段不直接依赖“LB 动态分配出来的 IP”作为证书名,而是要求提前规划:

  • 预留 IP
  • 统一域名
  • 或可稳定访问的 VIP / LB Hostname

3. 非目标

本次不包含以下内容:

  1. 不把普通 HTTP Ingress 直接用作 Kubernetes API Server 代理
  2. 不在本次引入 Gateway API / TLSRoute / TCP Route
  3. 不在本次把默认存储从 local-path 替换为共享存储
  4. 不在本次处理“vCluster control plane 均匀摊到所有宿主机”的调度优化
  5. 不在本次重新设计 join 脚本主链路

这些能力可作为后续阶段继续推进。


4. 总体设计

4.1 集群公网访问模式语义

建议使用:

  • public_access_enabled=false
    • Service 最终应为 ClusterIP
  • public_access_enabled=true && public_access_mode=nodeport
    • Service 最终应为 NodePort
  • public_access_enabled=true && public_access_mode=loadbalancer
    • Service 最终应为 LoadBalancer

4.2 第一阶段推荐校验规则

条件校验
public_access_enabled=false允许不填 control_plane_host
public_access_mode=nodeport允许按当前逻辑继续使用
public_access_mode=loadbalancer必须填写 control_plane_host

4.3 保留字段的兼容策略

  • public_access_enabled:继续保留,兼容现有开关逻辑
  • public_access_port
    • 仅在 nodeport 模式下有意义
    • loadbalancer 模式下应清空或忽略
  • api_endpoint
    • 由连接探测逻辑按实际 Service 类型回写

5. 详细改造清单

5.1 领域模型与数据库

目标

在后端模型和数据库里显式保存公网访问模式。

需修改文件

  • internal/domain/cluster/cluster.go
  • internal/infra/repository/sql.go
  • internal/infra/repository/sql_test.go
  • docs/architecture/database-design.md(功能落地后同步更新)

具体改造

  1. cluster.Cluster 中新增字段:
    • PublicAccessMode string(建议后续再收敛成强类型)
  2. clusters 表增加列:
    • public_access_mode TEXT NOT NULL DEFAULT 'nodeport'
  3. 更新 SQL:
    • select columns
    • insert
    • update
    • scan
  4. 老数据迁移策略:
    • 所有历史集群默认回填 nodeport

验收点

  • 旧集群升级后不报错
  • 新旧数据都能正确读写 public_access_mode

5.2 系统设置:增加默认公网模式

目标

让管理员在系统设置中配置“新建集群默认采用 NodePort 还是 LoadBalancer”。

需修改文件

  • internal/domain/settings/system_settings.go
  • internal/app/admin_system_settings.go
  • internal/api/http/admin_system_settings.go
  • internal/infra/repository/sql_system_settings.go
  • web/lib/console-api.ts
  • web/app/dashboard/admin/settings/page.tsx
  • web/i18n/messages/*.json

具体改造

新增系统设置字段,例如:

  • default_cluster_public_access_mode

建议可选值:

  • nodeport
  • loadbalancer

推荐默认值

  • 单机 / 简化部署:nodeport
  • 多宿主机集群:loadbalancer

验收点

  • 管理员保存后可持久化
  • 新建集群默认带出该值

5.3 创建集群接口支持 public_access_mode

目标

创建集群时即可指定公网模式。

需修改文件

  • internal/api/http/handlers.go
  • internal/app/service.go
  • internal/api/http/console.go
  • web/lib/console-api.ts

具体改造

  1. POST /api/console/clusters 请求体增加字段:
    • public_access_mode
  2. CreateClusterInput 增加字段:
    • PublicAccessMode
  3. 创建逻辑改为:
    • 请求有值 -> 使用请求值
    • 请求无值 -> 使用系统默认值
  4. 第一阶段增加校验:
    • 如果 public_access_enabled=truepublic_access_mode=loadbalancer
    • control_plane_host 必填

验收点

  • 能创建 nodeport 集群
  • 能创建 loadbalancer 集群
  • loadbalancer + 空 control_plane_host 被正确拒绝

5.4 更新集群接口支持切换公网模式

目标

让已有集群可以在 nodeport / loadbalancer / 关闭公网 三种状态间切换。

需修改文件

  • internal/api/http/handlers.go
  • internal/app/cluster_quota.go
  • web/app/dashboard/clusters/[id]/page.tsx
  • web/lib/console-api.ts
  • web/i18n/messages/*.json

具体改造

  1. updateClusterRequest 增加:
    • public_access_mode
  2. UpdateClusterResourcesInput 增加:
    • PublicAccessMode *string
  3. hasChanges() 增加对 mode 的判断
  4. describeClusterSettingsChange() 文案同步覆盖 mode
  5. 异步更新逻辑补 mode 的同步与回写

额外注意

切换模式时必须避免旧元数据残留:

  • nodeport -> loadbalancer
    • 不能继续向前端暴露旧 public_access_port
  • loadbalancer -> nodeport
    • 要重新允许 public_access_port 回写
  • public_access_enabled=false
    • 要清空 api_endpoint
    • 要清空 kubeconfig_available

验收点

  • 模式切换成功
  • 前端回显与数据库一致
  • 不残留旧模式元数据

5.5 vCluster Helm values 支持 LoadBalancer

目标

让创建与升级流程能把 vCluster Service 改成 LoadBalancer

需修改文件

  • internal/infra/vcluster/helm.go
  • deployments/single-node/docker-compose/kubebyon-vcluster-values.example.yaml(文档说明为主)

具体改造

当前 applyClusterOverrides() 里仅支持:

  • NodePort
  • ClusterIP

需要扩展到:

  • NodePort
  • LoadBalancer
  • ClusterIP

并且在第一阶段补充:

  • cluster.ControlPlaneHost 注入到 controlPlane.proxy.extraSANs

关键原因

如果只把 Service 类型切成 LoadBalancer,但证书 SAN 里没有对应 host, 则 kubeconfig 指向新 LB 地址后容易出现 TLS 校验失败。

验收点

  • loadbalancer 集群安装后,values 正确渲染
  • extraSANscontrol_plane_host

5.6 Service reconcile 逻辑支持三态

目标

让底层同步逻辑根据模式正确更新 Service。

需修改文件

  • internal/infra/vcluster/manager.go

具体改造

需要重构这些函数:

  1. desiredPublicAccessServiceType()
  2. applyPublicAccessServiceSpec()
  3. syncPublicAccessState()

预期行为

开启公网 + nodeport

  • ServiceTypeNodePort
  • public_access_port 可写回

开启公网 + loadbalancer

  • ServiceTypeLoadBalancer
  • 不应继续沿用 httpsNodePort 语义
  • public_access_port 应清空或忽略

关闭公网

  • ServiceTypeClusterIP
  • 清理对外暴露相关字段

验收点

  • 切换 Service 类型后对象状态正确
  • 不会错误保留旧 NodePort

5.7 连接探测与 kubeconfig 生成逻辑补齐约束

目标

GetClusterConnection()、kubeconfig 解析、API endpoint 生成在 LoadBalancer 模式下工作正常。

需修改文件

  • internal/infra/vcluster/kubeconfig.go
  • internal/infra/vcluster/connection.go
  • internal/app/service.go

当前现状

kubeconfig.go 已经可以识别:

  • NodePort
  • LoadBalancer
  • ClusterIP

因此这里不是从零开始,而是补约束和状态同步。

具体改造

  1. loadbalancer 第一阶段必须保证 control_plane_host 存在
  2. 解析 endpoint 时优先使用:
    • control_plane_host
    • 否则再根据 LB ingress 回退(仅作为兜底)
  3. GetClusterConnection() 更新数据库时:
    • 正确回填 api_endpoint
    • 不在 loadbalancer 模式下误写 public_access_port
  4. observeCluster() / latestClusterForWrite() 链路中:
    • 保证 PublicAccessMode 不被旧值覆盖

验收点

  • loadbalancer 模式下可正确生成 kubeconfig
  • kubectl version / kubectl get ns 可正常访问

5.8 前端:管理员系统设置页面

目标

让管理员可以设置默认公网模式。

需修改文件

  • web/app/dashboard/admin/settings/page.tsx
  • web/lib/console-api.ts
  • web/i18n/messages/zh-CN.json
  • web/i18n/messages/en.json
  • 其他 locale 文件

具体改造

新增表单项:

  • 默认公网访问模式:
    • NodePort
    • LoadBalancer

并在说明文案中提示:

  • LoadBalancer 适合多机宿主集群
  • 宿主集群需要提前具备 LB 能力

5.9 前端:创建集群页面

目标

让用户在新建集群时选择公网模式。

需修改文件

  • 集群创建页 / 创建弹窗所在前端文件
  • web/lib/console-api.ts
  • i18n 文案

具体改造

新增字段:

  • 公网访问开关
  • 公网访问模式:
    • NodePort
    • LoadBalancer

当选择 LoadBalancer 时:

  • 必须提示填写 control_plane_host
  • 文案应明确:
    • 推荐填可长期访问的域名、VIP 或预留 IP

5.10 前端:集群详情页 / 设置页 / 加入页

目标

让详情展示和编辑能力与新模式一致。

需修改文件

  • web/app/dashboard/clusters/[id]/page.tsx
  • web/app/dashboard/clusters/[id]/join/page.tsx
  • web/lib/console-api.ts
  • i18n 文案

具体改造

  1. 展示 public_access_mode
  2. 仅在 nodeport 模式下展示 public_access_port
  3. loadbalancer 模式下展示:
    • api_endpoint
    • control_plane_host
  4. 编辑时支持三态:
    • 关闭公网
    • NodePort
    • LoadBalancer

5.11 部署文档与运维前提

目标

明确说明:LoadBalancer 模式不是单靠代码切换就能工作,宿主集群必须先具备 LB 能力。

需修改文档

  • docs/runbooks/deploy-kubebyon-backend.md
  • docs/runbooks/deploy-kubebyon-backend-docker-compose.md
  • deployments/single-node/docker-compose/README.md
  • 相关 values 示例说明

需补充内容

  1. 裸金属 / 自建机房:
    • 需要 MetalLB、kube-vip + cloud-provider 等能力
  2. 云环境:
    • 需要宿主集群具备可用的 LoadBalancer Provider
  3. control_plane_host 规划建议:
    • 预留 IP
    • 域名
    • VIP

5.12 历史集群迁移

目标

让现有 NodePort 集群可以平滑迁移到 LoadBalancer。

迁移步骤

  1. 数据库写入:
    • public_access_mode = 'loadbalancer'
  2. 把旧的 control_plane_host 从宿主机单 IP 改成:
    • 新域名 / VIP / 预留 IP
  3. 触发集群配置更新
  4. 等待 Service 获取 LoadBalancer 地址
  5. 刷新连接信息:
    • api_endpoint
    • kubeconfig_available
    • connection_status

注意

如果直接保留旧 control_plane_host(某一台宿主机 IP), 则即使底层 Service 已切成 LoadBalancer,最终返回的 kubeconfig 仍可能继续指向旧地址。


5.13 测试清单

单元测试

需重点补充:

  • internal/infra/vcluster/manager_test.go
  • internal/app/service_test.go
  • internal/infra/repository/sql_test.go
  • internal/api/http/handlers_test.go

必测场景

  1. 创建集群:
    • enabled + nodeport
    • enabled + loadbalancer
    • disabled
  2. 更新集群:
    • nodeport -> loadbalancer
    • loadbalancer -> nodeport
    • public off -> on
  3. endpoint 解析:
    • control_plane_host 优先
    • loadBalancer.ingress 回退
  4. 元数据清理:
    • public_access_port 不残留
    • api_endpoint 不残留旧值
  5. 老数据兼容:
    • 历史集群自动视为 nodeport

集成 / E2E 测试

  1. 宿主 k3s 多节点
  2. LB Provider 正常工作(MetalLB 或云 LB)
  3. 创建 loadbalancer 模式集群
  4. kubeconfig 可用
  5. 关闭再开启公网访问成功
  6. 多集群并存时地址不串

6. 实施顺序

第一阶段(最小可用)

  1. clusters.public_access_mode
  2. 后端 model / repository / API
  3. helm.go / manager.go 支持 LoadBalancer
  4. control_plane_host 注入 extraSANs
  5. 前端创建 / 编辑 / 展示支持 mode
  6. 文档补充宿主集群前提

第二阶段(完善可用性)

  1. 系统设置支持默认公网模式
  2. 历史集群迁移脚本 / 管理操作
  3. 多机 E2E 验证

第三阶段(后续优化)

  1. podAntiAffinity / topologySpreadConstraints
  2. 共享存储替代 local-path
  3. 更正式的域名网关方案(Gateway API / TLS passthrough)

7. 暂不修改的部分

本次原则上不修改以下主链路:

  • join command 代理路径
  • GET /api/join/clusters/{clusterID}/script
  • internal/infra/vcluster/join_script.go
  • BYON 节点加入协议本身

原因:

当前 join 已经通过 KubeBYON 后端代理到 vCluster 内部地址, 不再强依赖公网 NodePort,因此不属于本轮必须改造项。


8. 验收标准

满足以下条件可视为本次改造完成:

  1. 新建集群可选择 NodePortLoadBalancer
  2. LoadBalancer 模式下可正确生成 api_endpoint 和 kubeconfig
  3. 前端可查看和修改公网模式
  4. 历史集群不受影响,默认继续以 nodeport 工作
  5. 文档已说明多机部署前提和配置要求
  6. 单元测试与至少一轮多机环境 E2E 测试通过

9. 附:本次改造的核心判断

  • 短期目标:先让 KubeBYON 真正支持多宿主机场景下的稳定公网入口
  • 推荐实现LoadBalancer 模式 + 显式 control_plane_host
  • 后续方向:再进一步演进到域名化的网关接入方案