写在前面
要阅读本文,您至少应该了解envoy 相关的概念。
本文是一个类似demo 的测试,只是为了学习Istio,更好地理解Istio 的控制平面和数据平面(pilot proxy)如何交互。就是下图中的蓝色虚线。
首先,我们来解释一下什么是go-control-plane。这是一个用于实现xDS API 的golang 库。 xDS API 是Envoy 用于动态配置的协议。您可以通过实施go-control-plane 来做到这一点
动态配置管理:使控制平面能够动态更新数据平面代理的配置。支持多个xDS 资源缓存和版本控制。提供快照缓存机制来管理配置版本和更新。
go-control-plane 允许您创建自定义控制平面来管理Envoy 以实现动态服务发现、负载平衡、路由等。
xds是一系列服务发现的总称
lds 侦听器服务发现rds 路由服务发现cds 集群服务发现eds 端点服务发现ad 聚合服务发现
请稍等。还有其他一些服务未在本文中介绍。如果您不明白这些概念,我们建议您先访问官网https://www.envoyproxy.io进行学习。
实现 go-control-plane
功能描述
上面是envoy代理的架构,并用闪回的方式来解释程序中的逻辑。
创建的端点的地址是www.envoyproxy.io。创建的集群名称为xds_demo_cluster。创建的路由位于filter_chins下的http_connection_manager中。根(用于请求转发目的)(位置)的集群名称称为xds_demo_cluster。最后创建的侦听器名称是listener_xds_demo。监听地址为0.0.0.0:12000。
这意味着当您访问localhost:12000 时,您的请求将被转发到www.envoyproxy.io。
如果你运行的是默认的envoy,你会看到我的程序中发布的配置是你默认运行envoy时的配置,但是运行envoy的默认方式是静态配置文件。即所有配置都写入envoy。yaml 本文是一种动态方法。
运行Envoy 的方法有很多种,但本文不会详细介绍它们。
功能实现
包主
进口(
\’语境\’
\’日志\’
\’网\’
\’时间\’
集群“github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3”
corev3“github.com/envoyproxy/go-control-plane/envoy/config/core/v3”
端点“github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3”
监听器“github.com/envoyproxy/go-control-plane/envoy/config/listener/v3”
路线“github.com/envoyproxy/go-control-plane/envoy/config/route/v3”
routerv3 \’github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3\’
http_connection_manager \’github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3\’
tlsv3 \’github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3\’
集群服务“github.com/envoyproxy/go-control-plane/envoy/service/cluster/v3”
Discoverygrpc \’github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3\’
端点服务“github.com/envoyproxy/go-control-plane/envoy/service/endpoint/v3”
监听器服务“github.com/envoyproxy/go-control-plane/envoy/service/listener/v3”
路由服务“github.com/envoyproxy/go-control-plane/envoy/service/route/v3”
“github.com/envoyproxy/go-control-plane/pkg/cache/types”
“github.com/envoyproxy/go-control-plane/pkg/cache/v3”
“github.com/envoyproxy/go-control-plane/pkg/resource/v3”
“github.com/envoyproxy/go-control-plane/pkg/server/v3”
“google.golang.org/grpc”
“google.golang.org/protobuf/types/known/anypb”
“google.golang.org/protobuf/types/known/durationpb”
)
函数主() {
ctx :=上下文.背景()
松鼠,错误:=net.Listen(\’tcp\’, \’:18000\’)
如果出现错误!=nil {
log.Fatalf(\’监听失败: %v\’, err)
}
sc :=cache.NewSnapshotCache(true,cache.IDHash{},nil)
srv :=服务器.NewServer(ctx, sc, nil)
//新的grpc 服务器
GS :=grpc.NewServer()
集群服务.RegisterClusterDiscoveryServiceServer(gs, srv)
端点服务.RegisterEndpointDiscoveryServiceServer(gs,srv)
侦听器服务.RegisterListenerDiscoveryServiceServer(gs, srv)
RouteService.RegisterRouteDiscoveryServiceServer(gs, srv)
Discoverygrpc.RegisterAggreatedDiscoveryServiceServer(gs,srv)
err=setSnapshot(ctx, \’xds-node-id\’, sc)
如果出现错误!=nil {
log.Fatalf(\’快照配置错误: %v\’, err)
} 除此之外{
log.Println(\’快照设置成功\’)
}
log.Println(\’正在启动控制平面服务器.\’)
if err :=gs.Serve(lis); err !=nil {
log.Fatalf(\’服务失败: %v\’, err)
}
}
func setSnapshot(ctx context.Context, nodeId string, sc cache.SnapshotCache) 错误{
集群名称:=\’xds_demo_cluster\’
Manager :=buildHttpManager(集群名称)
fcs :=buildFilterChain(经理)
serviceListener :=buildListener(\’0.0.0.0\’, 12000, fcs)
服务端点:=buildEndpoint()
serviceCluster :=buildCluster(集群名称,服务端点)
rs :=地图[资源.类型][]类型.资源{
resource.ClusterType: {服务集群},
resource.EndpointType: {服务端点},
resource.ListenerType: {服务监听器},
资源.RouteType: {经理},
}
快照,错误:=cache.NewSnapshot(\’1\’, rs)
如果出现错误!=nil {
log.Fatalf(\’新快照错误: %v\’, err)
}
return sc.SetSnapshot(ctx, 节点ID, 快照)
}
func buildFilterChain(manager *http_connection_manager.HttpConnectionManager) []*listener.FilterChain {
PB经理,错误:=anypb.New(经理)
如果出现错误!=nil {
log.Fatalf(\’无法封送HttpConnectionManager: %v\’, 错误)
}
fcs :=make([]*listener.FilterChain, 0, 0)
fcs=追加(fcs,listener.FilterChain{
Filters: []*listener.Filter{
{
Name: \’envoy.filters.network.http_connection_manager\’,
ConfigType:listener.Filter_TypedConfig{
TypedConfig: 管理器PB,
},
},
},
})
返回FC
}
func buildHttpManager(clusterName string) *http_connection_manager.HttpConnectionManager {
xdsRoute :=路由.RouteConfiguration{
Name: \’xds_demo_route\’,
VirtualHosts: []*route.VirtualHost{
{
Name: \’xds_demo_service\’,
Domains:[]字符串{\’*\’},
Routes: []*route.Route{
{
Match: 路线.RouteMatch{
PathSpecifier: 路线.RouteMatch_Prefix{
前缀: \’/\’,
},
},
Action: 路线.Route_Route{
Route: 路线.RouteAction{
HostRewriteSpecifier: Route.RouteAction_HostRewriteLiteral{
HostRewriteLiteral: \’www.envoyproxy.io\’,
},
//簇必须匹配:
ClusterSpecifier: Route.RouteAction_Cluster{
Cluster: 集群名称,
},
},
},
},
},
},
},
}
routerConfig, _ :=anypb.New(routerv3.Router{})
//http链接管理器
经理:=http_connection_manager.HttpConnectionManager{
StatPrefix: \’ingress_http\’,
RouteSpecifier: http_connection_manager.HttpConnectionManager_RouteConfig{
RouteConfig: xdsRoute,
},
HttpFilters: []*http_connection_manager.HttpFilter{
{
Name: \’envoy.filters.http.router\’,
ConfigType: http_connection_manager.HttpFilter_TypedConfig{
类型Config: routerConfig,
},
},
},
SchemeHeaderTransformation: corev3.SchemeHeaderTransformation{
Transformation: corev3.SchemeHeaderTransformation_SchemeToOverwrite{
SchemeToOverwrite: \’https\’,
},
},
}
退货经理
}
func buildEndpoint() *endpoint.LbEndpoint {
epTarget :=端点.LbEndpoint{
HostIdentifier: Endpoint.LbEndpoint_Endpoint{
端点:端点.端点{
地址: corev3.地址{
地址: corev3.Address_SocketAddress{
SocketAddress: corev3.SocketAddress{
地址: \’www.envoyproxy.io\’,
PortSpecifier: corev3.SocketAddress_PortValue{
端口值: 443,
},
},
},
},
},
},
}
返回epTarget
}
func buildCluster(clusterName string, ep *endpoint.LbEndpoint) *cluster.Cluster {
serviceCluster :=cluster.cluster{
name:集群名称,
ConnectTimeout:durationpb.New(时间.秒* 3),
ClusterDiscoveryType: Cluster.Cluster_Type{
类型: cluster.Cluster_STRICT_DNS,
},
DnsLookupFamily: Cluster.Cluster_V4_ONLY,
LbPolicy: cluster.Cluster_ROUND_ROBIN,
LoadAssignment:端点.ClusterLoadAssignment{
集群名称: 集群名称,
Endpoints: []*endpoint.LocalityLbEndpoints{
{
LbEndpoints: []*端点.LbEndpoint{ep},
},
},
},
TransportSocket: corev3.TransportSocket{
Name: \’envoy.transport_sockets.tls\’,
ConfigType: 无,
},
}
我们:=tlsv3.UpstreamTlsContext{
Sni: \’www.envoyproxy.io\’,
}
tlsConfig, _ :=anypb.New(us)
serviceCluster.TransportSocket.ConfigType=corev3.TransportSocket_TypedConfig{
类型Config: tlsConfig,
}
返回服务集群
}
func buildListener(ip string, port uint32, fcs []*listener.FilterChain) *listener.Listener {
返回侦听器。听众{
Name: \’listener_xds_demo\’,
地址: corev3.地址{
地址: corev3.Address_SocketAddress{
SocketAddress: corev3.SocketAddress{
地址:ip,
PortSpecifier: corev3.SocketAddress_PortValue{
PortValue:端口,
},
},
},
},
//过滤器链
FilterChains: fcs,
}
}
SnapshotCache 是go-control-plane 的核心组件,用于管理和存储Envoy 所需的xDS 资源的快照,并将更新推送到Envoy 实例服务器。 NewServer 创建一个xDS 服务实例。使用sc.SetSnapshot。在指定节点上设置生成的配置快照是动态配置和更新Envoy 代理的行为。输入参数有一个ID,就是下面Envoy启动配置中的ID。
这个时候就可以启动这个服务了。当前服务正在监听的地址在envoy.yaml 中使用,因此您需要记住它。
为 envoy 设置引导配置
在引导配置(bootstrap configuration)中,引导配置文件通常会指定控制平面地址(如xDS服务器地址)、监听器、集群、管理接口等基本信息。
节点:
id: xds 节点ID
集群: xds 节点集群
动态资源:
ads_config:
api_type: GRPC
grpc_services:
-envoy_grpc:
集群名称: xds_cluster
cds_config:
ad: {}
lds_config:
ad: {}
静态资源:
集群:
– name: xds_cluster
connect_timeout: 1 秒
type: STRICT_DNS
lb_policy: ROUND_ROBIN
http2_protocol_option: {}
负载分配:
集群名称: xds_cluster
端点:
– lb_endpoints:
-端点:
地址:
套接字地址:
地址: 127.0.0.1
端口值: 18000
管理员:
access_log_path: /dev/null
地址:
套接字地址:
地址: 0.0.0.0
端口值: 9901
解释
静态资源
定义静态集群xds_cluster 与xDS 服务器通信。这里的xDS 服务器运行在127.0.0.1:18000 上。这是上述服务监听动态资源的地址。
ads_config: 配置聚合发现服务(ADS) 以动态检索配置并使用gRPC 服务与xds_cluster 进行通信。每一个都表示使用ADS来获得配置管理。
定义管理接口并监听0.0.0.0:9901,用于显示Envoy节点状态和配置。
id 节点的唯一标识符,用于区分xDS 服务器集群中的不同Envoy 实例。 节点所属集群的名称。
接下来,启动特使。输出日志显示通过控制平面发布的配置已成功加载。
[2024-06-27 07:47:53.524][1][info][main] [source/server/server.cc:977]启动主调度循环
[2024-06-27 07:47:53.526][1][info][upstream] [source/common/upstream/cds_api_helper.cc:32] cds: 添加1 个集群,删除1 个集群
[2024-06-27 07:47:53.527][1][info][upstream] [source/common/upstream/cds_api_helper.cc:71] cds: 添加/更新了1 个集群,跳过了0 个未更改的集群
[2024-06-27 07:47:53.544][1][信息][上游][源/公共/上游/cluster_manager
_impl.cc:240] cm init: all clusters initialized
[2024-06-27 07:47:53.544][1][info][main] [source/server/server.cc:957] all clusters initialized. initializing init manager
[2024-06-27 07:47:53.546][1][info][upstream] [source/common/listener_manager/lds_api.cc:106] lds: add/update listener \’listener_xds_demo\’
[2024-06-27 07:47:53.546][1][info][config] [source/common/listener_manager/listener_manager_impl.cc:930] all dependencies initialized. starting workers
下一步我们可以访问一下监听的地址,可以看到成功转发到了envoy的官方网站。
~ $ curl http://localhost:12000 | grep title
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
19 15571 19 3098 0 0 5286 0 0:00:02 –:–:– 0:00:02 5286 <title>Envoy proxy – home</title>
100 15571 100 15571 0 0 21685 0 –:–:– –:–:– –:–:– 21686
我们还可以通过 ~ $ curl http://localhost:9901/config_dump 来查看envoy的实时配置
写在最后
动态配置的方式是在内存中加载配置,不会更新到静态的文件中。
更高级、复杂的用法可以参考istio;具体来说pilot watch集群中的服务、端点、配置等资源的变化。当检测到这些资源的变化时,pilot会生成新的配置,并通过xDS API将更新推送到相应的Envoy实例,从而实现动态配置和管理服务网格中的流量控制和路由规则。这样可以确保 Envoy始终具有最新的服务发现信息和路由配置。
源码目录 https://github.com/istio/istio/tree/master/pilot
#以上关于使用 go的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92623.html