在这篇博客文章中,我们将展示如何使用 Gateway API 的 HTTPRoutes 在单个 Kubernetes 集群中轻松地将流量路由到部署在不同命名空间的工作负载——这个过程比以往任何时候都更简单。
之前,我们只有 Ingress API 来定义入口路由规则。它很好地为我们服务,但也存在我们必须克服的缺点和局限性,有时我们甚至不得不采用一些不太优雅的方式。其中一个局限性就是,将流量路由到与我们的 Ingress 定义在不同命名空间中的 Services。
完整的示例请参考我们创建的 Gist 。欢迎联系我们的中国合作伙伴咨询 consultant@gingxing.com。
使用 ReferenceGrants 实现跨命名空间的 HTTPRoute 和 Service 引用
假设我们想要将 Kubernetes 集群分成三个命名空间,每个团队一个:
-
infra - 用于部署公司的 API Gateway 以及配置其行为所需的资源(即 Ingress、Gateway、HTTPRoute 等)。
-
apples - 用于部署 apples 团队管理的工作负载。
-
bananas - 用于部署 bananas 团队管理的工作负载。
在 Ingress API 中,要使用一个 Service,我们必须确保在 Ingress 规则中引用的 Service 定义在与 Ingress 相同的命名空间中。因此,如果我们想在 infra 命名空间中创建一个 Ingress,并使用来自 apples 和 bananas 命名空间的 Service,我们就必须使用一些非标准的变通方法——比如在 Ingress 命名空间中创建一个额外的 ExternalName Service,该 Service 指向另一个命名空间中 Service 的 FQDN。更多内容可以参考 Stack Overflow 上的这两个讨论(点击这里1 和 点击这里2.)。
好消息是?使用 Gateway API 不再需要这些变通方法,因为这些用例从一开始就被考虑在内了。
在 Gateway API 中,Ingress 的等价物是 HTTPRoute 资源。根据设计,它可以在单个规则中使用多个 Service 作为其后端,以便使用用户定义的权重对流量进行负载均衡。更重要的是,只要在 Service 的命名空间中定义了 ReferenceGrant 对象,允许在指定的资源(例如 HTTPRoute)中引用它,那么这些 Service 就可以部署在任何命名空间中。
假设我们希望在 infra 命名空间中定义一个 HTTPRoute,将发送到 /fruits 端点的 70% 的流量路由到团队的 bananas Service(部署在 bananas 命名空间中),其余的流量则路由到团队的 apples Service(部署在 apples 命名空间中)。这样的 HTTPRoute 可能如下所示:
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: echo-route
namespace: infra
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: kong
rules:
- matches:
- path:
type: PathPrefix
value: /fruits
backendRefs:
- name: bananas-echo
port: 1027
kind: Service
namespace: bananas
weight: 30
- name: apples-echo
port: 1027
kind: Service
namespace: apples
weight: 70
假设我们在 bananas 和 apples 命名空间中未定义任何 ReferenceGrants,就定义这样的 HTTPRoute。在这种情况下,我们的 Gateway API 实现(在我们的案例中为 Kong Ingress Controller)将拒绝这种引用,并在 HTTPRoute 父级的状态的 ResolvedRefs 条件中通知我们这一点:
$ kubectl get httproute -n infra echo-route -o=jsonpath='{.status.parents[0].conditions}' | jq
[
...
{
"observedGeneration": 1,
"reason": "RefNotPermitted",
"status": "False",
"type": "ResolvedRefs"
},
...
]
为了解析这些引用,我们只需要为这两个命名空间创建 ReferenceGrants 即可:
kind: ReferenceGrant
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: allow-apples-echo-in-infra
namespace: bananas
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: infra
to:
- group: ""
kind: Service
name: bananas-echo # This could be left empty to allow ANY service in the namespace.
# A similar one for apples namespace and apples-echo service should be created as well.
ReferenceGrant 的 spec.from 和 spec.to 列表定义了我们可以从哪些资源引用我们在定义 ReferenceGrant 的命名空间中定义的资源。在我们的案例中,我们允许在 infra 命名空间中定义的 HTTPRoute 引用在 bananas 命名空间中名为 banana-echo 的 Service(因为 ReferenceGrant 在这里定义)。
有了这些设置,我们现在可以确保引用已被正确解析,并且我们的流量已按预期转发。
首先,让我们检查 Gateway 是否已解析这些引用:
$ kubectl get httproute -n infra echo-route -o=jsonpath='{.status.parents[0].conditions}' | jq
[
{
"observedGeneration": 2,
"reason": "ResolvedRefs",
"status": "True",
"type": "ResolvedRefs"
},
]
引用已解析后,现在我们可以确保流量按预期进行路由:
$ http 'http://${PROXY_IP}/fruits'
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 22
Content-Type: text/plain; charset=utf-8
Date: Mon, 06 Nov 2023 18:06:01 GMT
Via: kong/3.4.2
X-Kong-Proxy-Latency: 2
X-Kong-Upstream-Latency: 3
In namespace apples.
$ http 'http://${PROXY_IP}/fruits'
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 23
Content-Type: text/plain; charset=utf-8
Date: Mon, 06 Nov 2023 18:06:02 GMT
Via: kong/3.4.2
X-Kong-Proxy-Latency: 0
X-Kong-Upstream-Latency: 1
In namespace bananas.
正如预期的那样,我们的流量通过部署在 infra 命名空间中的 Gateway 被路由到部署在 apples 和 bananas 团队的命名空间中的 Service。
跨命名空间的 HTTPRoute 共享 Gateway
既然我们已知 ReferenceGrant 可以作为将来自不同命名空间的 Service 用作 Gateway API Routes 的后端的补救措施,那么现在让我们思考一下公司基础设施的另一种略有不同的场景。
我们不想为基础设施(Gateway、HTTPRoutes 等)设置单独的命名空间,而是希望允许团队在他们的命名空间中定义 HTTPRoute,以便他们可以对入口流量规则进行更多的控制。我们命名空间的特性将如下:
-
infra - 用于部署我们公司的 API Gateway(即 Gateway、GatewayClass)。
-
apples - 用于部署团队 apples 管理的工作负载和 Gateway API Routes,允许入口流量进入。
-
bananas - 用于部署团队 bananas 管理的工作负载和 Gateway API Routes,允许入口流量进入。
首先,让我们在团队的 apples 命名空间中创建一个 HTTPRoute,看看默认的 Gateway 配置会发生什么。
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: route
namespace: apples
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: kong
namespace: infra # We need to explicitly specify the namespace of the Gateway as now it is not in the same namespace
# as our HTTPRoute (apples).
rules:
- matches:
- path:
type: PathPrefix
value: /apples
backendRefs:
- name: apples-echo
port: 1027
kind: Service
# We can omit the namespace as the Service is in the same namespace as our HTTPRoute (apples).
在创建了上述 HTTPRoute 后,让我们查看其状态条件。
$ kubectl get -n apples httproute route -o=jsonpath='{.status.parents[0].conditions}' | jq
[
{
"lastTransitionTime": "2023-12-07T12:31:56Z",
"observedGeneration": 1,
"reason": "NotAllowedByListeners",
"status": "False",
"type": "Accepted"
},
]
我们得到了状态为 False 的 Accepted 条件,原因是 NotAllowedByListeners。这意味着我们的 Gateway 的监听器不允许将我们的 HTTPRoute 附加到它们上。默认情况下,Gateway 仅接受来自其命名空间的 Routes。如果我们想克服这个限制,可以使用 Gateway 的监听器的 allowedRoutes 字段。
在我们的示例中,我们将修改 Gateway 的配置,以允许来自 apples 和 bananas 命名空间的 HTTPRoutes。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: kong
namespace: infra
spec:
gatewayClassName: kong
listeners:
- name: proxy
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Selector
selector:
matchExpressions:
# Allow attaching Routes from apples and bananas namespaces.
- key: kubernetes.io/metadata.name
operator: In
values: [apples, bananas]
在将代理监听器的 allowRoutes 更改为上述内容后,我们现在应该能够看到我们的 HTTPRoute 被 Gateway 成功接受。
$ kubectl get -n apples httproute route -o=jsonpath='{.status.parents[0].conditions}' | jq
[
{
"lastTransitionTime": "2023-12-07T13:09:58Z",
"observedGeneration": 1,
"reason": "Accepted",
"status": "True",
"type": "Accepted"
},
]
为了最终验证在 apples 命名空间中创建的 HTTPRoute 是否已成功附加到 Gateway 并进行了配置,我们可以调用预期返回 200 状态码的端点。
$ http "http://${PROXY_IP}/apples?details=true"
HTTP/1.1 200 OK
In namespace apples.
完成!
结论
总结我们所学的知识,Gateway 的监听器的 allowedRoutes 和 ReferenceGrant 都是有用的 Gateway API 工具。它们允许明确配置 Gateway 控制器在解析可能在 Gateway API 对象定义中出现的跨命名空间引用时将遵循的规则。
如果您想进一步了解这个主题,以下是一些可能有用的参考链接:
-
跨命名空间路由(https://gateway-api.sigs.k8s.io/guides/multiple-ns/) - 来自 Gateway API 官方文档的指南
-
Gateway 监听器的 AllowedRoutes API 参考(https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.AllowedRoutes)
-
ReferenceGrant API 参考(https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1alpha2.ReferenceGrant)
-
欢迎联系我们的中国合作伙伴咨询 consultant@gingxing.com。