ListenerSet
原文:https://gateway-api.sigs.k8s.io/guides/user-guides/listener-set/
ListenerSet 允许团队把 port、hostname 和 TLS 证书 放在独立资源里定义,而不是把所有这些都堆在一个最多 64 个 listener 的 Gateway 资源里。这套机制支撑起一种可分权管理的模型,特别适合大规模、多租户环境。
基于此,你可能在以下场景下会用到 ListenerSet:
- 多租户:可以让不同团队各自创建自己的 ListenerSet,共享同一个 Gateway 和底层负载均衡基础设施。
- 大规模部署:借助 ListenerSet,单个 Gateway 可以拥有超过 64 个 listener。团队间也可以共用同一份 ListenerSet 配置,避免重复。
- 单 Gateway 持有更多证书:由于单个 Gateway 现在可以拥有超过 64 个 listener,因此一个 Gateway 就可以为更多后端转发加密流量,每个后端都可以使用自己的证书。这种做法与服务级别的证书诉求天然契合,例如 Istio Ambient Mesh 或 Knative。
下图展示了 ListenerSet 如何帮助把多租户环境中的路由配置去中心化:
- 团队 1 和团队 2 各自管理自己命名空间内的 Service 和 HTTPRoute 资源。
- 每个 HTTPRoute 都引用一个本命名空间内的 ListenerSet。这样,每个团队就能自主决定他们的路由如何对外暴露(协议、端口、TLS 证书等)。
- 两个团队的 ListenerSet 共享一个独立命名空间中的 Gateway。另一个 Gateway 团队可以负责集中基础设施的搭建与管理,或按需执行统一策略。
flowchart TD
subgraph team1 namespace
SVC1[Services]
HR1[HTTPRoutes]
LS1[ListenerSet]
end
subgraph team2 namespace
SVC2[Services]
HR2[HTTPRoutes]
LS2[ListenerSet]
end
subgraph shared namespace
GW[Gateway]
end
HR1 -- "parentRef" --> LS1
LS1 -- "parentRef" --> GW
HR1 -- "backendRef" --> SVC1
HR2 -- "parentRef" --> LS2
LS2 -- "parentRef" --> GW
HR2 -- "backendRef" --> SVC2使用 ListenerSet
Gateway 配置
默认情况下,Gateway 不允许 ListenerSet 被附加进来。用户可以通过配置 Gateway 的 allowedListeners 字段显式启用这种行为,指定允许哪些命名空间贡献 listener。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: parent-gateway
spec:
allowedListeners:
namespaces:
from: SameListenerSet 配置
ListenerSet 通过 parentRef 引用其父 Gateway:
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: workload-listeners
spec:
parentRef:
name: parent-gateway
kind: Gateway
group: gateway.networking.k8s.io路由附加(Route Attachment)
要把 HTTPRoute(或任何其它 Route 类型)附加到 ListenerSet 上,HTTPRoute 必须在 parentRefs 中把该 ListenerSet 列为父资源:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httproute-example
spec:
parentRefs:
- name: workload-listeners
kind: ListenerSet
group: gateway.networking.k8s.io
sectionName: secondListener 冲突
由于多个 ListenerSet 可以附加到同一个 Gateway,因此需要规则来管理冲突。一个 Listener 是否能被一组 Listener(无论这组 Listener 是位于同一个 ListenerSet 对象里,还是分布在附加到同一个 Gateway 的多个 ListenerSet 中)所区分,取决于 Port、Protocol,以及(依协议而定)Hostname 这三者的组合。
当 Listener 之间无法被区分时,会用 Listener 优先级规则 来解决冲突、决定哪个 Listener 生效。把它当作一场比赛来想通常最直观——"赢家"就是那个实际生效的 Listener。规则如下(在比较项相等时继续向下一条):
- 父 Gateway 自身的 Listener 优先级最高。
- 创建时间最早的 ListenerSet 优先。
- 字典序最靠前的 ListenerSet 优先。
赢的 ListenerSet 会被打上 Accepted: true 标记;输的 ListenerSet 会被打上 Accepted: false 并 Conflicted: true 标记。
与 Gateway API 中的所有其它冲突解决规则一样,这套规则也是为了保证流量稳定——也就是说,新增一个冲突的 ListenerSet 永远不会"抢走"已有的配置。
示例
下面这个示例展示一个带一个 HTTP listener的 Gateway,以及两个子级 HTTPS ListenerSet(各自拥有独立的 hostname 和证书)。只有 belongs-to: shared-gateway 这个 label 的命名空间中的 ListenerSet 才会被接受:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: parent-gateway
spec:
gatewayClassName: example
allowedListeners:
namespaces:
from: Selector
selector:
matchLabels:
belongs-to: shared-gateway
listeners:
- name: foo
hostname: foo.com
protocol: HTTP
port: 80
---
apiVersion: v1
kind: Namespace
metadata:
name: team-1-ns
labels:
belongs-to: shared-gateway
---
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: first-workload-listeners
namespace: team-1-ns
spec:
parentRef:
namespace: default
name: parent-gateway
kind: Gateway
group: gateway.networking.k8s.io
listeners:
- name: first
hostname: first.foo.com
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
group: ""
name: first-workload-cert
---
apiVersion: v1
kind: Namespace
metadata:
name: team-2-ns
labels:
belongs-to: shared-gateway
---
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: second-workload-listeners
namespace: team-2-ns
spec:
parentRef:
namespace: default
name: parent-gateway
kind: Gateway
group: gateway.networking.k8s.io
listeners:
- name: second
hostname: second.foo.com
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
group: ""
name: second-workload-cert