一文搞懂 Kubernetes Gateway API 的 Policy Attachment

一文搞懂 Kubernetes Gateway API 的 Policy Attachment

背景

《SMI 与 Gateway API 的 GAMMA 倡议意味着什么?》的一文中,介绍过 Kubernetes Gateway API 处理东西向(网格)流量的可能性。让我们重新看下 Gateway API 中对流量定义(路由)的定义,以 HTTP 路由为例:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: my-route
  namespace: gateway-api-example-ns2
spec:
  parentRefs:
  - kind: Gateway
    name: foo-gateway
    namespace: gateway-api-example-ns1
  hostnames:
  - foo.example.com
  rules:
  - backendRefs:
    - name: foo-svc
      port: 8080

上面的 YAML 中,使用 parentRefs 字段将路由策略附加到了网关资源 foo-gateway 上。网关 foo-gateway 会根据请求头部的 HOST 来选择合适的 HTTPRoute,然后将流量代理到上游 Service foo-svc。简单来说,就是定义了“网关 -> 路由 -> 后端”的映射。

ingress-vs-mesh

通过对流量的定义以及处理流量的资源的选择,实现 7 层 HTTP 协议的反向代理和负载均衡。但在实际的场景下,简单的代理路由策略还并不够,可能还需要配合治理策略来提升服务的健壮性,比如限流、重试、超时、熔断、自定义健康检查等等。

我们看下 Istio 的超时配置,首先使用了 reviews 进行流量的匹配,然后再根据路由的策略 uri 前缀 /review 进行路由匹配,将流量代理到目的地 v2reviews。与此同时,该路由的超时为 0.5s

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - match:
    - uri:
        prefix: "/review"
    route:
    - destination:
        host: reviews
        subset: v2
    timeout: 0.5s

在这段定义中耦合了流量匹配、路由匹配、后端指定、超时,如果需要配置重试呢,再加个 retries 字段。如此一来,灵活性大大折扣。

目标

Kubernetes Gateway API 的 策略附件(Policy Attachment) 的设计目标:

  • 策略和资源关联标准化
  • 支持策略的默认值和覆盖值
  • 不同资源上策略生效的优先级

为资源施加策略的时候,既要考虑通用性(标准化)又要考虑灵活性(策略值优先级)。

这里说的资源可以是网关相关的任何资源,比如 GatewayClassGateway、路由(如 HTTPRoute、TCPRouteGRPCRoute)、Kubernetes 核心资源(如 NamespaceService )。后面几种资源还会分命名空间,比如是请求发起方(Gateway、服务消费方)或者请求接收方(服务提供方)的命名空间。

resource-level

这些资源的影响范围各有不同,我们暂且称为粒度,比如 GatewayClass 影响某类网关实现所有实例上的流量;Gateway 资源则特指进入某个网关实例的流量;Namespace 特指由该命名空间下的资源发出或者接收的流量;路由则特指具有某种特征的流量,并且路由的定义可以定义在发起方的命名空间,也可以定义在接收方的命名空间。

可见虽然策略是附加在资源上,但作用的最终目标还是流量:南北向流量和东西向流量,分别对应入口策略和网格策略。

入口策略

ingress-policy-attachment

网格策略

mesh-policy-attachment

设计

策略与资源关联标准化

策略与资源关联的设计引入了 Target Reference API 的概念,即每个策略上必须要有一个 targetRef 字段,通过该字段将资源与策略进行关联,完成解耦。

apiVersion: networking.example.net/v1alpha1
kind: TimeoutPolicy
metadata:
  name: foo
spec:
  default:
    connectionTimeout: 3
    readTimeout: 5
  targetRef:
    kind: HTTPRoute
    name: example

targetRef 字段一次只能指定一个资源,但是每个策略配置配置不同粒度的资源。比如上面的重试策略,附加在同命名空间下名为 exampleHTTPRoute 上。将所有具有该特征的流量,连接超时为 3,读取超时为 5

targetRef 字段的结构固定的,由 Gateway API 的 PolicyTargetReference 进行定义,包含了资源的最最基础信息。

type PolicyTargetReference struct {
	Group Group `json:"group"`
	Kind Kind `json:"kind"`
	Name ObjectName `json:"name"`
	Namespace *Namespace `json:"namespace,omitempty"`
}

默认值和覆盖值

默认值体现的是缺省状态下的策略设置,比如前面具有 HTTPRoute example 描述的特征的流量,通过 spec.default 配置了默认超时时间。

下面的策略,则使用 spec.override 对所有进入 Gateway 资源 example(网关实例)的流量连接超时为 5

那最终哪个值会生效呢?我们可以这样理解,所有的覆盖值的优先级会高于默认值。也就是符合匹配策略条件的流量,会优先使用覆盖值。

apiVersion: networking.example.net/v1alpha1
kind: TimeoutPolicy
metadata:
  name: foo
spec:
  override:
    connectionTimeout: 5
  targetRef:
    kind: Gateway
    name: example

策略的优先级

默认值和覆盖值的优先级已经有了,上面在介绍资源的时候提到了资源的级别,并且策略也可以附加到不通的资源上。比如下面的策略定义了读取超时的默认值以及连接超时的覆盖值,附加到了 Service example 上,实际作用的资源是后端(Backend)工作负载。

apiVersion: networking.example.net/v1alpha1
kind: TimeoutPolicy
metadata:
  name: foo
spec:
  override:
    connectionTimeout: 1
  default:
    readTimeout: 10
  targetRef:
    kind: Service
    name: example

流量的路径是 Gateway example -> HTTPRoute example -> Backend example,

对于 覆盖值,优先级与资源的级别相同;而 默认值,则与资源的级别正好相反。因此,最终的生效设置是:

connectionTimeout: 5 # from gateway override
readTimeout: 10 # from backend default

policy-hierarchy

现状

目前 Policy Attachment 只是提供了概念的设计,还有很多方面暂未完善,而且具体的处理细节也依赖各个实现的设计。比如如何为外部资源(服务)配置策略、同一资源上的策略优先级、如何为多种资源配置相同的策略等等,同时 Policy Attachment 并未提供各种策略的 API。

截止文章发出时,了解到的 Linkerd 在 1.12 中参考 Policy Attachment 的设计实现了 AuthorizationPolicy,并计划待 Gateway API 中的设计稳定后切换到 Gateway API 的 CRD。

如果你了解有其他的 Policy Attachment 实现,可以在下面留言。

关注云原生指北微信公众号

(转载本站文章请注明作者和出处乱世浮生,请勿用于任何商业用途)

comments powered by Disqus