代表性面试主题

系统设计面试:如何用 Kubernetes Gateway API ListenerSet 支持多租户入口?

系统设计困难
Offer.cc 编辑团队发布 更新

题干

请设计一个共享 Kubernetes Gateway:平台团队维护底层负载均衡,多个应用团队独立提交 hostname、端口、路由和 TLS 证书。要求避免互相覆盖、支持约 1000 个域名、保留状态可观测性,并说明 ListenerSet、授权、冲突、扩展和故障处理。

题干与适用场景

请设计一个共享 Kubernetes Gateway。平台团队负责 Gateway 和负载均衡基础设施,应用团队在各自命名空间维护入口 hostname、端口、HTTPRoute 和证书。目标规模约 20 个团队、每队 50 个 listener,即约 1000 个域名;单个 Gateway 的基础 listener 上限按 64 估算。

回答要解释如何把 listener 从巨大 Gateway 对象拆到多个 ListenerSet,如何授权跨命名空间附加,如何在冲突时保持流量稳定,以及控制器如何通过 status 让团队知道配置是否 Accepted、Programmed 或 Conflicted。

面试官考察点

资源边界与委托

强回答会把共享基础设施、租户配置和路由绑定分开,说明为什么应用团队不能直接编辑平台 Gateway。

冲突与安全默认值

候选人应说清楚默认拒绝 ListenerSet、允许的命名空间来源、同名 hostname 的确定性优先级和证书引用边界。

控制器一致性

要覆盖 watch、合并、校验、状态条件和重试,不能只写一份 YAML 就假设数据面立即生效。

可扩展性与迁移

需要比较一个 Gateway、每租户一个 Gateway、Ingress 注解等替代方案,并解释何时 ListenerSet 的复杂度值得承担。

回答前需要澄清的问题

  • 1000 个域名是否共享一个负载均衡地址,还是每个团队需要独立入口?
  • 应用团队能否管理自己的 TLS Secret,平台是否保留证书审批权?
  • 跨命名空间附加是允许全部命名空间、标签选择,还是只允许同命名空间?
  • 冲突发生时要求旧配置继续服务,还是允许新配置抢占?
  • 控制器需要多快反映配置,是否要求跨集群复制?
  • HTTPRoute、TLSRoute 和其他 Route 类型的授权边界是否相同?

30 秒回答框架

“我让平台团队创建 Gateway,并默认禁止 ListenerSet;通过 allowedListeners 明确允许的命名空间范围。每个应用团队在自己的命名空间提交 ListenerSet 和 Route,控制器先校验 ParentRef、hostname、端口、协议、证书引用和 AllowedRoutes,再按 Gateway 优先、创建时间更早、namespace/name 字典序的规则合并。冲突的对象标记 Accepted=False、Conflicted=True,不能取代已经生效的 listener。数据面只由控制器从合并后的期望状态编程,状态条件和指标让租户能区分拒绝、冲突、未编程和已生效。”

分步骤深入解答

第一步:估算规模并选择资源模型

20 个团队乘以每队 50 个 listener 约为 1000 个入口。把 1000 条配置塞进一个 Gateway 会造成单对象写竞争、权限过宽和控制器重算;ListenerSet 把每队配置拆成独立资源,Gateway 只保留平台级地址、类和允许附加的策略。

第二步:建立授权握手

Gateway 的 allowedListeners 是安全门。默认 None 表示不接受任何 ListenerSet;平台可以选择 Same、标签 SelectorAll。ListenerSet 用 parentRef 指向 Gateway,控制器只有在两端授权、引用有效且对象被允许时才进入合并集合。

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gateway
spec:
  allowedListeners:
    namespaces:
      from: Selector
      selector:
        matchLabels:
          gateway-access: shared
---
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
  name: team-a-listeners
  namespace: team-a
spec:
  parentRef:
    name: shared-gateway
    namespace: platform
  listeners:
  - name: app-a
    hostname: app-a.example.com
    protocol: HTTPS
    port: 443

第三步:定义合并和冲突规则

先把 Gateway 自带 listeners 与被授权的 ListenerSet 拼成候选集合,再按端口、协议和适用 hostname 判断是否同一 listener。冲突优先级固定为:父 Gateway 优先;然后 ListenerSet 创建时间更早者优先;仍相同则按 namespace/name 字典序。失败者写入 Conflicted,不能静默覆盖现有流量。

第四步:隔离路由和证书

ListenerSet 的 allowedRoutes 限制哪些命名空间可以绑定 Route;Route 通过 parentRefs 指向 ListenerSet 的特定 section。TLS Secret 由平台策略限制引用范围,证书审批与应用发布权限分开。应用团队只能修改自己的 ListenerSet 和 Secret,不能借 ParentRef 读取其他租户资源。

第五步:让控制器可收敛

控制器 watch Gateway、ListenerSet、Route、Namespace 标签和 Secret,生成按 Gateway 分组的期望模型。每次事件做去重和短暂防抖,校验通过后再编程负载均衡。status 返回 Accepted、Programmed、ResolvedRefs 和 Conflicted 条件;重试必须幂等,旧期望状态保留到新配置成功编程。

第六步:比较替代方案与故障路径

每租户一个 Gateway 能简化权限,却增加地址、负载均衡和证书成本;单 Gateway 加注解便宜,但缺少统一 schema、冲突语义和跨实现互操作。ListenerSet 控制面不可用时保留最后一次 Programmed 配置,拒绝未知新 listener;平台 Gateway 删除或 ParentRef 失效时把子资源标记为未接受,恢复后重新收敛。

高质量示范回答

“我会把 Gateway 当作平台拥有的共享边界,把 ListenerSet 当作租户拥有的声明。平台先配置 GatewayClass、地址和 allowedListeners,默认不允许任何附加;只有带有 gateway-access=shared 标签的命名空间可以引用它。每队提交自己的 ListenerSet、HTTPRoute 和证书引用。

控制器收到事件后,先验证 ParentRef、命名空间授权、端口/协议/hostname、AllowedRoutes 与 Secret 引用,再把 listener 合并。父 Gateway 优先,之后按 ListenerSet 创建时间和 namespace/name 解决冲突;输家标记 Accepted=False、Conflicted=True,不夺走已经运行的配置。合并成功后才更新负载均衡,Programmed 状态表示数据面已生效。

按 20 队乘 50 条约 1000 个 listener,拆分资源可避免单对象写竞争和权限集中。控制器不可用时继续服务最后的稳定快照,新的冲突配置不进入数据面。若租户需要完全独立的地址、合规域或故障域,我会改用每租户 Gateway,并接受更高基础设施成本。”

常见错误

  • 让所有团队直接编辑 Gateway → 配置互相覆盖且权限过大 → Gateway 归平台,ListenerSet 按命名空间委托。
  • 默认允许全部命名空间 → 任意租户可申请共享入口 → 默认 None,再用 Same 或 Selector 收窄范围。
  • 让新 listener 最后写入即生效 → 新配置可能劫持旧域名 → 使用确定性优先级并将输家标记冲突。
  • 只检查 hostname 不检查端口和协议 → 不同协议仍可能撞在同一入口 → 以端口、协议和适用 hostname 共同判定。
  • 直接把 Secret 名称交给数据面 → 跨命名空间越权或证书泄露 → 通过引用授权和控制器校验后再编程。
  • 收到事件就立即改负载均衡 → 短暂非法状态造成抖动 → 防抖、幂等合并、成功后切换并保留旧快照。
  • status 只写 Ready → 租户无法区分拒绝、冲突和未编程 → 使用 Accepted、Programmed、ResolvedRefs、Conflicted 条件。
  • 把 ListenerSet 当作无限扩展 → 控制器和负载均衡仍有容量瓶颈 → 按 Gateway 分片、限制每租户配额并监测收敛延迟。

追问及应对

追问一:两个团队提交同一个 hostname 和端口,谁赢?

父 Gateway 优先;两个 ListenerSet 冲突时创建时间更早者优先,仍相同按 namespace/name 字典序。输家保持可见但标记 Conflicted,不能用重试时间改变结果。

追问二:平台想临时冻结一个租户,怎么做?

移除其命名空间标签或缩小 allowedListeners 选择器,控制器会让该 ListenerSet 变为未接受并保留最后快照。冻结动作写审计记录,恢复时重新验证而不是直接信任旧对象。

追问三:一个 ListenerSet 有 64 条 listener,还能继续扩展吗?

单个 ListenerSet 自身仍要遵守实现限制,不能把总量当成无限。把租户拆成多个 ListenerSet、按 Gateway 分片,并为每个分片设置配额;如果地址或证书隔离更重要,则改用多个 Gateway。

追问四:证书 Secret 更新时如何避免中断?

监听 Secret 版本并先校验证书链、hostname 与有效期;在数据面确认新证书已编程后再更新 Programmed。旧证书在宽限窗口内保留,失败则继续使用已知良好版本并告警。

追问五:控制器重启期间新 Route 会不会覆盖旧流量?

不会。控制器持久化或重建期望状态,数据面继续使用最后成功快照;重启后先完整重算、校验冲突和引用,再以一次可观察的版本切换。

来源一:Gateway API ListenerSet 用户指南

用户指南定义了 ListenerSet 的多租户委托用途、64 条 listener 限制、allowedListeners、parentRef 和冲突优先级。本文的资源模型、授权握手、冲突处理与状态设计据此展开。

来源二:GEP-1713

GEP-1713 说明 ListenerSet 解决共享 Gateway 的资源争用、跨命名空间管理和大规模域名场景,并给出父 Gateway、创建时间和字典序的合并规则。本文的容量估算和替代方案比较以此为约束。

来源三:Kubernetes Gateway API v1.5 发布说明

发布说明记录 ListenerSet 进入 Standard,并说明它针对多租户、委托 listener 和超过 64 条 listener 的场景。本文把这些公开变更转化为面试中的迁移与治理问题。

来源四:系统设计面试公开指南

公开面试指南强调先澄清需求、讨论扩展和故障、解释取舍。本文的澄清问题、估算、冲突追问和替代方案用于训练这些可观察的答题信号。

公开来源

同类题目

相关面试工具

用 Solve 整理系统设计回答

从澄清需求开始,展开规模、架构、组件选择和取舍。

查看工具