Dawn's Blogs

分享技术 记录成长

0%

Kuma学习笔记 (4) KDS

Kuma 通过 KDS(Kuma Discovery Service)进行 Global kuma-cp 和 Zone kuma-cp 的资源交换,以实现跨集群的通信。

在第一节首先会简要说明 KDS 中需要同步的资源,第二节说明 KDS 的实现。

资源

KDS 同步的资源按照资源的流向,可以分为两种类型:

  • ZoneToGlobal:区域 cp 到全局 cp 同步的信息。
  • GlobalToZone:全局 cp 到区域 cp 同步的信息。

ZoneToGlobal

Dataplane

Dataplane:允许 Zone kuma-cp -> Global kuma-cp,Dataplane 定义了一个数据面 sidecar 代理的配置,spec 包括:

  • Network:网络,描述数据面代理的入站和出站地址。
  • Metrics: 定义数据面收集的指标。
  • Probes:暴露健康检查端口,健康检查配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Dataplane defines a configuration of a side-car proxy.
type Dataplane struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

// Networking describes inbound and outbound interfaces of the data plane
// proxy.
Networking *Dataplane_Networking `protobuf:"bytes,1,opt,name=networking,proto3" json:"networking,omitempty"`
// Configuration for metrics that should be collected and exposed by the
// data plane proxy.
//
// Settings defined here will override their respective defaults
// defined at a Mesh level.
Metrics *MetricsBackend `protobuf:"bytes,2,opt,name=metrics,proto3" json:"metrics,omitempty"`
// Probes describe a list of endpoints that will be exposed without mTLS.
// This is useful to expose the health endpoints of the application so the
// orchestration system (e.g. Kubernetes) can still health check the
// application.
//
// See
// https://kuma.io/docs/latest/policies/service-health-probes/#virtual-probes
// for more information.
Probes *Dataplane_Probes `protobuf:"bytes,3,opt,name=probes,proto3" json:"probes,omitempty"`
}

DataplaneInsight:表示了数据平面的运行时状态,包括:

  • Subscriptions:描述了由数据平面向控制平面创建的 ADS 订阅。
  • MTLS:数据平面代理的 mTLS 状态,如证书过期时间,上次证书的生成时间等。
1
2
3
4
5
6
7
8
9
10
11
// DataplaneInsight defines the observed state of a Dataplane.
type DataplaneInsight struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

// List of ADS subscriptions created by a given Dataplane.
Subscriptions []*DiscoverySubscription `protobuf:"bytes,1,rep,name=subscriptions,proto3" json:"subscriptions,omitempty"`
// Insights about mTLS for Dataplane.
MTLS *DataplaneInsight_MTLS `protobuf:"bytes,2,opt,name=mTLS,proto3" json:"mTLS,omitempty"`
}

Egress

Egress:用于定义 Zone Egress。

  • Zone:所属的 Zone 名称。
  • Network:描述了 Egress 监听的地址和端口。
1
2
3
4
5
6
7
8
9
10
11
12
// ZoneEgress allows us to configure dataplane in the Egress mode.
type ZoneEgress struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

// Zone field contains Zone name where egress is serving, field will be
// automatically set by Global Kuma CP
Zone string `protobuf:"bytes,1,opt,name=zone,proto3" json:"zone,omitempty"`
// Networking defines the address and port of the Egress to listen on.
Networking *ZoneEgress_Networking `protobuf:"bytes,2,opt,name=networking,proto3" json:"networking,omitempty"`
}

EgressInsight:定义了 Zone Egress 的运行时状态,包括:

  • DiscoverySubscription:定义了由 Zone kuma-cp 创建的 ADS 订阅。
1
2
3
4
5
6
7
8
9
// ZoneEgressInsight defines the observed state of a Zone Egress.
type ZoneEgressInsight struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

// List of ADS subscriptions created by a given Zone Kuma CP.
Subscriptions []*DiscoverySubscription `protobuf:"bytes,1,rep,name=subscriptions,proto3" json:"subscriptions,omitempty"`
}

Ingress

Ingress:定义了 Zone Ingress。允许 Zone kuma-cp -> Global kuma-cp,和 Global kuma-cp -> Zone kuma-cp,Global kuma-cp 接收 Zone kuma-cp 的 Ingress 资源,并向其他 Zone kuma-cp 同步 Ingress 信息

  • Zone:标识 Ingress 服务于哪个区域。
  • Networking:定义了 Zone Ingress 的监听地址和端口,以及公开的地址端口。
  • AvailableServices:定义了可以通过该 Zone Ingress 访问的服务,是 Kuma 跨集群通信的基础。
    • Tags:服务 tag。
    • Instances:给定标签可用的服务实例数量。
    • Mesh:给定标签可用的服务实例所属的服务网格名称。
    • ExternalService:表明该服务是否为外部服务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// ZoneIngress allows us to configure dataplane in the Ingress mode. In this
// mode, dataplane has only inbound interfaces. Every inbound interface matches
// with services that reside in that cluster.
type ZoneIngress struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

// Zone field contains Zone name where ingress is serving, field will be
// automatically set by Global Kuma CP
Zone string `protobuf:"bytes,1,opt,name=zone,proto3" json:"zone,omitempty"`
// Networking defines the address and port of the Ingress to listen on.
// Additionally publicly advertised address and port could be specified.
Networking *ZoneIngress_Networking `protobuf:"bytes,2,opt,name=networking,proto3" json:"networking,omitempty"`
// AvailableService contains tags that represent unique subset of
// endpoints
AvailableServices []*ZoneIngress_AvailableService `protobuf:"bytes,3,rep,name=availableServices,proto3" json:"availableServices,omitempty"`
}

type ZoneIngress_AvailableService struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

// tags of the service
Tags map[string]string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// number of instances available for given tags
Instances uint32 `protobuf:"varint,2,opt,name=instances,proto3" json:"instances,omitempty"`
// mesh of the instances available for given tags
Mesh string `protobuf:"bytes,3,opt,name=mesh,proto3" json:"mesh,omitempty"`
// instance of external service available from the zone
ExternalService bool `protobuf:"varint,4,opt,name=externalService,proto3" json:"externalService,omitempty"`
}

IngressInsight:定义了 ZoneIngress 的运行时状态。允许 Zone kuma-cp -> Global kuma-cp,和 Global kuma-cp -> Zone kuma-cp,Global kuma-cp 接收 Zone kuma-cp 的 IngressInsight 资源,并向其他 Zone kuma-cp 同步 IngressInsight 信息。

1
2
3
4
5
6
7
8
9
// ZoneIngressInsight defines the observed state of a Zone Ingress.
type ZoneIngressInsight struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields

// List of ADS subscriptions created by a given Zone Kuma CP.
Subscriptions []*DiscoverySubscription `protobuf:"bytes,1,rep,name=subscriptions,proto3" json:"subscriptions,omitempty"`
}

GlobalToZone

Global kuma-cp 到 zone kuma-cp 的资源,除了 Ingress 外剩下的均是来自于 Global kuma-cp 策略的更新

如 CircuitBreaker,FaultInjection,HealthCheck,Retry 等,这里不再详细说明。

KDS

kds

KDS v1

服务定义

在 KDS v1 中,global 和 zone 之间在一个双向 gRPC 流中进行资源同步,KDS 服务定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
service MultiplexService {
rpc StreamMessage(stream Message) returns (stream Message);
}

message Message {
oneof value {
envoy.api.v2.DiscoveryRequest legacy_request = 1;
envoy.api.v2.DiscoveryResponse legacy_response = 2;
envoy.service.discovery.v3.DiscoveryRequest request = 3;
envoy.service.discovery.v3.DiscoveryResponse response = 4;
}
}

流程

在 zone kuma-cp 和 global kuma-cp 建立连接后:

  • 创建 Session 对象,并启动两个协程用于读写 gRPC streaming。Session 底层抽象分离了 serverStream 和 clientStream 并实现了基于 buffer 的 streaming,用于表示 global 到 zone 和 zone 到 global 的连接。

  • 接着调用 OnSessionStarted 回调函数,开启两个协程用于表示 server(global kuma-cp)和 client(global kuma-cp)。

    • server 实现了 xDS 服务器,用于响应客户端的 xDS 请求。

    • client 在建立时:

      • 首先对所有需要从 zone 到 global(ZoneToGlobal)的资源发起 DiscoveryRequest。
      • 接收 xDS 响应,并同步资源到缓存中。
    • server 和 client 所有读写的数据,均从 serverStream 和 clientStream 中读取/发送。

image-20240128202501932

KDS v2

为什么引入 KDS v2

为什么要重新设计 KDS v2,因为 KDS v1 实现非常复杂并且可能存在一些 bug(如 issues #5373)。KDS v2 主要的变化如下:

  • 分离 kds 中 zone 和 global 之间流的共用(这引入了复杂性和 bug)。
  • 当数据从 zone 同步到 global 时,使用增量更新而不是全量更新。

KDS v1 使用一个双向流从同步 zone 和 global 之间的资源。KDS v2 引入 2 个独立的 RPC 来同步资源来简化逻辑,将简化逻辑和可读性,并且使用增量更新 Delta xDS

1
2
3
4
5
service KDSSyncService {
rpc GlobalToZoneSync(stream envoy.service.discovery.v3.DeltaDiscoveryRequest)
rpc ZoneToGlobalSync(stream envoy.service.discovery.v3.DeltaDiscoveryResponse)
returns (stream envoy.service.discovery.v3.DeltaDiscoveryRequest);
}

KDS v1 zone 向 global 发送 DiscoveryRequest 并等待资源的更新通知。global 将状态存储在缓存中,并在发生变化时发送响应。在 global 到 zone 同步的情况下效果很好,但在大型部署中更多的流量来自从 zone 到 global 的同步。每当有变化时,zone 控制平面需要将所有数据平面资源发送到 global。所以,KDS v2 使用 delta xDS,可以用更高效的方式同步资源

服务定义

KDS v2 分离出了两个接口,GlobalToZoneSync 和 ZoneToGlobalSync,用于 global 和 zone 之间的资源同步,使用 delta xDS。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// KDSSyncService is a service exposed by the control-plane for the
// synchronization of the resources between zone and global control-plane.
service KDSSyncService {
// GlobalToZoneSync is logically a service exposed by global control-plane
// that allows zone control plane to connect and synchronize resources from
// the global control-plane to the zone control-plane. It uses delta xDS from
// go-control-plane and responds only with the changes to the resources.
rpc GlobalToZoneSync(stream envoy.service.discovery.v3.DeltaDiscoveryRequest)
returns (stream envoy.service.discovery.v3.DeltaDiscoveryResponse);
// ZoneToGlobalSync is logically a service exposed by global control-plane
// that allows zone control plane to connect and synchronize resources to
// the global control-plane. It uses delta xDS from go-control-plane and
// responds only with the changes to the resources.
rpc ZoneToGlobalSync(stream envoy.service.discovery.v3.DeltaDiscoveryResponse)
returns (stream envoy.service.discovery.v3.DeltaDiscoveryRequest);
}

流程

GlobalToZoneSync 和 ZoneToGobalSync 在连接开始时,都从 EventBus 订阅了 ZoneWentOffline 事件,接着向 EventBus 发送 ZoneOpenStream 事件(用于通知 HealthCheck 对新的 zone 和 的健康检查),用于结束与 zone 之间的连接(如正常结束,发生错误,健康检查超时)。

  • 在 GlobalToZoneSync 方法中,接着调用 OnGlobalToZoneSyncConnect 回调函数:

    • 开启 delta xDS 服务器,用于响应 zone 到 global 对 GlobalToZone 资源的 xDS 请求。
  • ZoneToGobalSync 方法中,调用 OnGlobalToZoneSyncConnect 回调函数:

    • 对所有 ZoneToGlobal 资源发起 DeltaDiscoveryRequest 请求。
    • 接收 xDS 响应,并同步资源到缓存中。

image-20240128201819505

其他服务

ZoneWatch

ZoneWatch 订阅 ZoneOpenStream 事件,用于添加活跃的 zone 列表,并通知 zone kuma-cp 下线。

  • 每次都会轮询所有的 zone,检查上一次发送 HealthCheck 请求的时间是否超时。
  • 如果超时,则会发送 ZoneWentOffline 事件,通知 KDS 服务器终止与 zone kuma-cp 的连接。

image-20240128210831447

GlobalKDSService

Kuma 提供在在 Global Zone 上获取 zone xDS 配置、状态等信息的 API,所以需要通过 GlobalKDSService 收集 zone 的信息,并暴露方法以进行健康检查。

image-20240128210844323