当前位置: 首页 > 科技观察

如何解决 K8s 在云边协同下的运维监控挑战

时间:2023-03-15 19:21:04 科技观察

如何解决云边协同下的K8s运维监控挑战在各个行业和场景中,成为解决这些领域数据传输效率的关键途径。同时,随着边缘计算的形式、规模和复杂度不断增加,边缘计算领域的运维方式和能力在支撑边缘业务创新速度方面越来越薄弱。因此,Kubernetes迅速成为边缘计算的关键要素,帮助企业更好地在边缘运行容器,最大限度地利用资源,缩短研发周期。但是如果将原生的Kubernetes直接应用到边缘计算场景中,还有很多问题需要解决。例如云端和边缘一般位于不同的网络平面,边缘节点一般位于防火墙内部。K8s系统运维监控能力面临以下挑战:K8s原生运维能力缺失(如kubectllogs/exec无法执行),社区主流监控运维组件无法工作(如作为普罗米修斯/指标服务器)。面对边缘场景应用生命周期管理、云端网络连接、云端设备运维协同、异构资源支持等挑战,基于K8s的边缘计算云原生开源平台OpenYurt应运而生。成为。云原生景观的重要组成部分。本文将详细介绍OpenYurt的核心组件之一Yurt-Tunnel如何在边缘场景扩展原生K8s系统的相关能力。Yurt-Tunnel设计思路既然边缘可以访问云端,那么可以考虑在云的边缘建立一个反向穿透的隧道,从而保证云端(中心)可以基于隧道主动访问边缘.当时我们也研究了很多开源的隧道解决方案。在能力和生态兼容方面,我们最终选择基于ANP设计和实现Yurt-Tunnel整体解决方案,具有安全、不可入侵、可扩展、高效传输等优点。实现方式在K8s云边一体化架构中构建安全、非侵入、可扩展的反向通道解决方案。该解决方案至少需要包括以下能力。云边隧道建设隧道两端的自管云组件请求证书无缝回流到隧道的Yurt-tunnel架构模块如下图所示:3.1云边隧道建设当边缘yurt-tunnel-agent启动后,它会与yurt-tunnel-server建立连接并注册,并定期检测连接的健康状态并重建连接。#https://github.com/openyurtio/apiserver-network-proxy/blob/master/pkg/agent/client.go#L189#yurt-tunnel-agent注册信息:"agentID":{nodeName}"agentIdentifiers":ipv4={nodeIP}&host={nodeName}”当yurt-tunnel-server收到来自某个云组件的请求时,需要将请求转发给对应的yurt-tunnel-agent。因为除了转发初始请求外,requestsession会有后续的数据返回或者持续的数据转发(比如kubectlexec),所以需要数据的双向转发,同时需要支持云组件请求的并发转发,也就是说一个独立的每个请求生命周期都需要建立身份,因此设计一般有两种方案方案一:初始云端连接只通知转发请求,tunnel-agent会与云端建立新的连接处理请求。新的连接可以解决请求独立识别的问题,并发也是一个很好的解决方案。但是每次请求都需要建立一个连接,会消耗很多资源。方案二:只使用初始的云端连接转发请求。为了对大量请求复用同一个连接,需要对每个请求创建一个连接进行封装,并添加独立的标识来解决并发转发的诉求。同时,由于需要复用一个连接,需要将连接管理和请求生命周期管理解耦,即独立管理请求转发的状态转换。解决方案涉及到解包、请求处理状态机等方案会比较复杂,OpenYurt选择的ANP组件采用了上述方案2,这也符合我们最初的设计意图。#https://github.com/openyurtio/apiserver-network-proxy/blob/master/konnectivity-client/proto/client/client.pb.go#L98#云边通信typePacketstruct{TypePacketType`的数据格式和数据类型protobuf:"varint,1,opt,name=type,proto3,enum=PacketType"json:"type,omitempty"`//TypesthatarevalidtobeassignedtoPayload://*Packet_DialRequest//*Packet_DialResponse//*Packet_Data//*Packet_CloseRequest//*Packet_CloseResponsePayloadisPacket_Payload`protobuf_oneof:"payload"`}请求转发链路构建封装在Packet_DialRequest和Packet_DialResponse中,其中Packet_DialResponse.ConnectID用于标识请求,相当于隧道中的requestID。请求和相关数据封装在Packet_Data中。Packet_CloseRequest和Packet_CloseResponse用于转发链路资源回收。具体可以参考下面的时序图:RequestInterceptor模块的作用从上面的分析可以看出,在yurt-tunnel-server转发请求之前,请求者需要发起HttpConnect请求来构建转发链接。但是Prometheus、metrics-server等开源组件很难添加相应的处理。因此在Yurt-tunnel-server中增加了一个请求劫持模块Interceptor来发起HttpConnect请求。相关代码如下:#https://github.com/openyurtio/openyurt/blob/master/pkg/yurttunnel/server/interceptor.go#L58-82proxyConn,err:=net.Dial("unix",udsSockFile)费!=nil{returnnil,fmt.Errorf("dialingproxy%qfailed:%v",udsSockFile,err)}varconnectHeadersstringfor_,h:=rangesupportedHeaders{ifv:=header.Get(h);len(v)!=0{connectHeaders=fmt.Sprintf("%s\r\n%s:%s",connectHeaders,h,v)}}fmt.Fprintf(proxyConn,"CONNECT%sHTTP/1.1\r\n主机:%s%s\r\n\r\n",addr,"127.0.0.1",connectHeaders)br:=bufio.NewReader(proxyConn)res,err:=http.ReadResponse(br,nil)iferr!=nil{proxyConn.Close()returnnil,fmt.Errorf("readingHTTPResponsefromCONNECTto%sviaproxy%sfailed:%v",addr,udsSockFile,err)}ifres.StatusCode!=200{proxyConn.Close()returnnil,fmt.Errorf("proxyerrorfrom%swhiledialing%s,code%d:%v",udsSockFile,addr,res.StatusCode,res.Status)}3.2证书管理为了保证云端通道的长期安全通信,支持HTTPS请求转发,yurt-tunnel需要自行生成证书,并保持证书自动轮换。具体实现如下:#1.yurt-tunnel-server证书:#https://github.com/openyurtio/openyurt/blob/master/pkg/yurttunnel/pki/certmanager/certmanager.go#L45-90-证书存放位置:/var/lib/yurt-tunnel-server/pki-CommonName:"kube-apiserver-kubelet-client"//kubeletserver-Organization的webhook验证:{"system:masters","openyurt:yurttunnel"}//用于kubeletserver的webhook验证和yurt-tunnel-server证书的autoapprove-SubjectAlternateNamevalues:{x-tunnel-server-svc,x-tunnel-server-internal-svc的ips和dnsnames}-KeyUsage:"any"#2.yurt-tunnel-agent证书:#https://github.com/openyurtio/openyurt/blob/master/pkg/yurttunnel/pki/certmanager/certmanager.go#L94-112-certificate存放位置:/var/lib/yurt-tunnel-agent/pki-CommonName:"yurttunnel-agent"-Organization:{"openyurt:yurttunnel"}//自动批准yurt-tunnel-agent证书-SubjectAlternateNamevalues:{nodeName,nodeIP}-KeyUsage:"any"#3.yurt-隧道证书申请(CSR)由yurt-tunnel-server批准#https://github.com/openyurtio/openyurt/blob/master/pkg/yurttunnel/pki/certmanager/csrapprover.go#L115-Monitorcsrresources-filternon-yurt-tunnelcsr(组织中没有“openyurt:yurttunnel”)-approve还没有通过的csr#4.证书自动轮换处理#https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/client-go/util/certificate/certificate_manager.go#L2243.3无缝引导云组件请求to因为隧道需要把云组件的请求无缝转发到yurt-tunnel-server,也意味着不需要对云组件做任何修改,所以需要分析云组件的请求。目前组件的运维请求有两种类型::类型1:直接使用IP地址访问,如:http://{nodeIP}:{port}/{path}类型2:使用域名访问,如:http://{nodeName}:{port}/{path}不同类型的请求需要采用不同的方案进行导流。方案一:使用iptablesdnat规则保证type1请求无缝转发到yurt-tunnel-server#相关iptablesrules维护代码:https://github.com/openyurtio/openyurt/blob/master/pkg/yurttunnel/iptables/iptables.go#yurt-tunnel-server维护的iptablesdnatrules如下:[root@xxx/]#iptables-nv-tnat-LOUTPUTTUNNEL-PORTtcp--**0.0.0.0/00.0.0.0/0/*edgetunnelserverport*/[root@xxx/]#iptables-nv-tnat-LTUNNEL-PORTTUNNEL-PORT-10255tcp--**0.0.0.0/00.0.0.0/0tcpdpt:10255/*jumptoport10255*/TUNNEL-PORT-10250tcp--**0.0.0.0/00.0.0.0/0tcpdpt:10250/*jumptoport10250*/[root@xxx/]#iptables-nv-tnat-LTUNNEL-PORT-10255RETURNtcp--**0.0.0.0/0127.0.0.1/*returnrequesttoaccessnodedirectly*/tcpdpt:10255RETURNt--**0.0.0.0/0172.16.6.156/*returnrequesttoaccessnodedirectly*/tcpdpt:10255DNATtcp--**0.0.0.0/00.0.0.0/0/*dnattotunnelforaccessnode*/tcpdpt:10255to:172.16:16.154Option2:使用dns域名解析nodeName是yurt-tunnel-server的访问地址,所以出于不同的目的,类型2请求被无缝转发到yurt-tunnel#x-tunnel-server-svc和x-tunnel-server-internal-svc:-x-tunnel-server-svc:mainexpose10262/10263端口,用于公网访问yurt-tunnel-server如yurt-tunnel-agent-x-tunnel-server-internal-svc:主要用于云组件从内网访问,如prometheus,metrics-server等#dns域名解析原理:1.yurt-tunnel-servertokube-apiserver创建或更新yurt-tunnel-nodesconfigmap,其中tunnel-nodes字段格式为:{x-tunnel-server-internal-svcclusterIP}{nodeName},保证映射关系记录所有nodeNames和yurt-tunnel-server服务之间的关系2在.corednspod中挂载yurt-tunnel-nodesconfigmap,使用host插件使用configmap的dnsrecords3。同时在x-tunnel-server-internal-svc中配置端口映射,10250映射到10263,10255映射到102644。通过上面的配置,可以实现http://{nodeName}:{port}/{path}请求无缝转发到yurt-tunnel-servers云请求扩展:如果用户需要访问边缘的其他端口(10250和10255除外),则需要在iptables中添加相应的dnat规则或者添加相应的端口映射在x-tunnel-server-internal-svc中,如下图:#比如需要访问边缘的9051端口#添加iptablesdnatrule:[root@xxx/]#iptables-nv-tnat-LTUNNEL-PORTTUNNEL-PORT-9051tcp--**0.0.0.0/00.0.0.0/0tcpdpt:9051/*jumptoport9051*/[root@xxx/]#iptables-nv-tnat-LTUNNEL-PORT-9051RETURNtcp--**0.0.0.0/0127.0.0.1/*returnrequesttoaccessnodedirectly*/tcpdpt:9051RETURNtcp--**0.0.0.0/0172.16.6.156/*returnrequesttoaccessnodedirectlyly*/tcpdpt:9051DNATtcp--**0.0.0.0/00.0.0.0/0/*dnattotunnelforaccessnode*/tcpdpt:9051to:172.16.6.156:10264#x-tunnel-server-internal-svc添加端口映射规范:端口:-name:httpsport:10250protocol:TCPtargetPort:10263-name:httpport:10255protocol:TCPtargetPort:10264-name:dnat-9051#新建映射port:9051protocol:TCPtargetPort:10264当然上面的iptablesdnat规则和服务端口映射,都是由yurt-tunnel-server自动更新。用户只需要在yurt-tunnel-server-cfgconfigmap中添加端口配置即可。详情如下:#注:由于证书不可控因素,新端口目前只支持从yurt-tunnel-server的10264转发不支持)kind:ConfigMapmetadata:name:yurt-tunnel-server-cfgnamespace:kube-system近期计划支持kube-apiserver的EgressSelector功能验证yurt-tunnel-server多实例部署验证支持yurt-tunnel-agent配置多个yurt-tunnel-server地址支持证书存放目录自定义支持更细粒度的定义证书使用,确保证书使用范围可控支持yurt-tunnel-serveryurt-tunnel-server访问地址发生变化后,yurt-tunnel-server证书可自动更新支持yurt-tunnel-agent自动刷新yurt-tunnel-server访问地址的支持非NodeIP/NodeName类型的请求转发(如非宿主网络Pod的云访问边缘)支持accessingcloudPodfromedgePodthroughtunnels支持独立部署yurt-tunnel(未绑定k8s)支持更多协议转发,如gRPC、websocket、ssh等。