一文搞懂 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
。简单来说,就是定义了“网关 -> 路由 -> 后端”的映射。
通过对流量的定义以及处理流量的资源的选择,实现 7 层 HTTP 协议的反向代理和负载均衡。但在实际的场景下,简单的代理路由策略还并不够,可能还需要配合治理策略来提升服务的健壮性,比如限流、重试、超时、熔断、自定义健康检查等等。
我们看下 Istio 的超时配置,首先使用了 reviews
进行流量的匹配,然后再根据路由的策略 uri 前缀 /review
进行路由匹配,将流量代理到目的地 v2
的 reviews
。与此同时,该路由的超时为 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) 的设计目标:
- 策略和资源关联标准化
- 支持策略的默认值和覆盖值
- 不同资源上策略生效的优先级
为资源施加策略的时候,既要考虑通用性(标准化)又要考虑灵活性(策略值优先级)。
这里说的资源可以是网关相关的任何资源,比如 GatewayClass
、Gateway
、路由(如 HTTPRoute、TCPRoute
、GRPCRoute
)、Kubernetes 核心资源(如 Namespace
、Service
)。后面几种资源还会分命名空间,比如是请求发起方(Gateway、服务消费方)或者请求接收方(服务提供方)的命名空间。
这些资源的影响范围各有不同,我们暂且称为粒度,比如 GatewayClass
影响某类网关实现所有实例上的流量;Gateway
资源则特指进入某个网关实例的流量;Namespace
特指由该命名空间下的资源发出或者接收的流量;路由则特指具有某种特征的流量,并且路由的定义可以定义在发起方的命名空间,也可以定义在接收方的命名空间。
可见虽然策略是附加在资源上,但作用的最终目标还是流量:南北向流量和东西向流量,分别对应入口策略和网格策略。
入口策略
网格策略
设计
策略与资源关联标准化
策略与资源关联的设计引入了 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
字段一次只能指定一个资源,但是每个策略配置配置不同粒度的资源。比如上面的重试策略,附加在同命名空间下名为 example
的 HTTPRoute
上。将所有具有该特征的流量,连接超时为 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 Attachment 只是提供了概念的设计,还有很多方面暂未完善,而且具体的处理细节也依赖各个实现的设计。比如如何为外部资源(服务)配置策略、同一资源上的策略优先级、如何为多种资源配置相同的策略等等,同时 Policy Attachment 并未提供各种策略的 API。
截止文章发出时,了解到的 Linkerd 在 1.12 中参考 Policy Attachment 的设计实现了 AuthorizationPolicy
,并计划待 Gateway API 中的设计稳定后切换到 Gateway API 的 CRD。
如果你了解有其他的 Policy Attachment 实现,可以在下面留言。