共计 7070 个字符,预计需要花费 18 分钟才能阅读完成。
作者 | 郑超
导读:OpenYurt 是阿里巴巴开源的云边协同一体化架构,与同类开源计划相比,OpenYurt 领有可实现边缘计算全场景笼罩的能力。在之前的一篇文章中,咱们介绍了 OpenYurt 是如何在弱网和断网场景下实现边缘自治的。本文作为 OpenYurt 系列文章的第四篇,咱们将着重介绍 OpenYurt 的另一个外围能力——云边通信,以及相干组件 Yurttunnel。
应用场景
在利用的部署和运维过程中,用户经常须要获取利用的日志,或间接登录到利用的运行环境中进行调试。在 Kubernetes 环境中,咱们通常应用 kubectl log,kubectl exec 等指令来实现这些需要。如下图所示,在 kubectl 申请链路上,kubelet 将表演服务器端,负责解决由 kube-apiserver(KAS) 转发来的申请,这就要求 KAS 和 kubelet 之间须要存在一条网络通路,容许 KAS 被动拜访 kubelet。
图一:kubectl 执行流程
然而,在边缘计算场景中,边缘节点常位于本地专有网络中,这尽管保障了边缘节点的平安,但也造成位于云端管控节点的 KAS 无奈间接拜访位于边缘节点的 kubelet。因而,为了反对通过云端节点对边缘端利用进行运维操作,咱们必须在云、边之间建设反向运维通道。
反向通道
Yurttunnel 是 OpenYurt 近期开源的一个重要组件,用来解决云边通信问题。反向通道是解决跨网络通信的一种常见形式,而 Yurttunnel 的实质就是一个反向通道。一个边缘集群上司的节点常位于不同的 network region 中,而位于同一个 region 内的节点之间是能够互相通信的,因而在设置反向通道时,咱们只需保障在每个 region 内设置一个与 proxy server 相连的 agent 即可(如下图所示)。具体包含以下几个步骤:
- 在管控组件所在网络内,部署 proxy server。
- proxy server 对外开放一个公网能够拜访的 IP。
- 在每个 region 部署个 agent,并通过 server 的公网 IP 与 server 建设长连贯。
- 管控组件对边缘节点的拜访申请都将转发致 proxy server。
- proxy server 再将申请通过对应的长连贯发往指标节点。
图二
在 Yurttunnel 中,咱们抉择应用上游我的项目 apiserver-network-proxy(ANP) 来实现 server 和 agent 间的通信。ANP 是基于 kubernetes 1.16 Alpha 新性能 EgressSelector 开发,意在实现 Kubernetes 集群组件的跨 intranet 通信(例如,master 位于管控 VPC,而 kubelet 等其余组件位于用户 VPC)。
读者可能会好奇,既然 OpenYurt 是基于 ACK@Edge 开源的,而在生产环境中,ACK@Edge 的云边运维通道应用的是自研组件 tunnellib,那为什么在开源版本里咱们要选用一个新的组件呢?这里不得不再次提到 OpenYurt 的外围设计理念“Extend upstream Kubernetes to Edge”。
诚然,tunnellib 通过了简单线上环境的考验,组件性能稳固,但咱们更心愿能与上游放弃最大的技术公约数,让 OpenYurt 的用户体验更靠近原生 Kubernetes;同时,在 ACK@Edge 的开发和运维过程中,咱们发现,边缘集群的许多需要也同样存在于其余场景中(例如,大多数云厂商也须要实现节点跨网络通信),并且运维通道的传输效率也能进一步优化(4.5 章将详述优化过程)。因而,秉承凋谢分享、平等普惠的开源精力,咱们心愿能将开发和运维过程中积攒的的贵重教训在上游社区与更多的开发者分享。
ANP 并非开箱即用
然而 ANP 我的项目仍处于起步阶段,性能尚未欠缺,许多问题仍有待解决。咱们从实际中发现的次要问题包含:
- 如何转发云端节点的申请 — 反向通道失常工作的一个前提是,管控节点发往边缘节点的申请必须先通过 proxy server。对于 Kubernetes 1.16 + 版本,KAS 能借由 EgressSelector 将发往节点的申请先发往指定的 proxy server。但对于 1.16 以前的版本,KAS 及其他管控组件(Prometheus 和 metrics server)只能间接拜访节点,而不能绕道 proxy server。能够预感的是,局部用户在短期内,仍将应用 1.16 以前的版本,并且 Prometheus 和 metrics server 等管控组件在短期内也没有反对 EgressSelector 的打算。因而,咱们要解决的第一个问题是, 如何将管控组件发往节点的申请转发致 proxy server。
- 如何确保 server 正本笼罩所有的 region — 在生产环境中,一个边缘集群经常蕴含上万个节点,并同时服务上百名用户,如果一个集群只有一个 proxy server,那么,一旦 proxy server 呈现故障,所有用户都将无奈对位于边缘节点上的 pod 进行操作。因而,咱们必须同时部署多个 proxy server 正本以保障集群高可用。同时,proxy server 的工作负荷将随着拜访流量的增大而增大,用户的拜访延时也势必减少。因而在部署 proxy server 时,咱们还需思考如何对 proxy server 进行程度拓展,以应答高并发场景。一个应答单点故障和高并发场景的经典解决方案是,部署多个 proxy server 正本,并应用负载平衡进行流量散发。然而在 OpenYurt 场景下,对于 KAS 发来的任意申请,LoadBalancer (LB) 会转发给哪个 server 正本是不可控的,因而,须要解决的第二个问题是,如何保障每个 server 正本都能与所有的 agent 建设连贯。
- 如何将申请转发给正确的 agent — 在运行过程中,proxy server 在收到申请后,需依据申请的 destination IP,将申请转发至位于对应 network region 内的 agent。然而,ANP 目前的实现,假如所有的节点都位于一个网络空间内,server 会随机筛选一个 agent 转发申请。因而,咱们须要解决的第三个问题是,如何将申请正确地转发给指定的 agent。
- 如何解除组件对节点证书的依赖 — 在运行时,咱们须要为 server 提供一套 TLS 证书,以实现 server 与 KAS,server 与 agent 间的平安通信。同时,咱们也须要为 agent 筹备一套 TLS client 证书,用以建设 agent 和 server 间的 gRPC 信道。ANP 目前的实现,要求 server 必须和 KAS 部署在同一个节点上,并且在启动时挂载节点 volume 共享 KAS tls 证书。同样,agent 也须要在启动时挂载 volume 共享 kubelet tls 证书。这无形中升高了部署的灵活性,造成了组建对节点证书的强依赖,在有些状况下,用户可能心愿将 server 部署在非 KAS 所在节点上。因而,另一个须要关注的问题是, 如何解除组件对节点证书的依赖。
- 如何放大 Tunnel 带宽 — ANP 的一个外围设计思维,是应用 gRPC 封装 KAS 所有对外 HTTP 申请。这里抉择 gRPC,次要是看重其对流(stream)的反对和清晰的接口标准,此外,强类型的客户端和服务器端能够无效缩小运行时谬误,进步零碎稳定性。然而,咱们也发现,相较于间接应用 TCP 协定,采纳 ANP 也会带来额定的开销减少带宽。从产品层面思考,Tunnel 流量走的是公网,带宽的减少也意味着用户老本的减少。因而,一个十分重要的问题是, 在进步零碎稳定性的同时,咱们是否也能放大带宽?
Yurttunnel 设计解析
1. 制订 DNAT 规定转发云端节点的申请
如前文所述,ANP 是基于上游新性能 EgressSelector 开发的,该性能容许用户在启动 KAS 时通过传入 egress configuration 来要求 KAS 将 egress 申请转发到指定的 proxy server。但因为咱们须要兼顾新老版本的 Kubernetes 集群,并且思考到,其余管控组件(Prometheus 和 metric server)并不反对 EgressSelector 个性,咱们须要保障在无奈应用 EgressSelector 的状况下也能将 KAS egress 申请转发致 proxy server。为此,咱们在每一个云端管控节点上都部署一个 Yurttunnel Server 正本,并在 Server 中内嵌一个新组件 Iptabel Manager。Iptable Manager 会通过在宿主机的 Iptable 中的 OUTPUT 链中增加 DNAT 规定,将管控组件对节点的申请转发致 Yurttunnel Server。
同时,当启用 EgressSelector 后,KAS 对外申请都遵循一个对立的格局,因而咱们新增一个组件,ANP interceptor。ANP interceptor 会负责截取从 master 发来的 http 申请,并将其封装成 EgressSelector 格局。Yurttunnel 申请转发的具体流程见图三。
图三:Yurttunnel 申请转发流程
2. 动静获取 Server 正本数
在上一节中,咱们提到,咱们将采纳负载平衡的形式来治理 yurttunnel server,所有的 ingress 申请都会通过 LB 分发给一个 server 正本。因为咱们无奈预测 LB 会筛选哪个 server 正本,咱们必须保障每个 server 正本都要与所有的 agent 建设连贯。这里,咱们将应用 ANP 自带的性能实现这一需要,具体流程如下:
- 在启动 yurttunnel server 时,咱们会将正本数(serverCount)传入每个 server 正本中,并且为每个正本指定一个 server ID;
- agent 连贯 LB 后,LB 会随机抉择一个 server 正本并让其与 agent 建设长连贯;
- 与此同时,server 会通过该通道向 agent 返回一个 ACK package,这个 package 中将蕴含 serverCount 和 serverID;
- agent 通过解析 ACK package,能够获悉 server 正本的个数,并在本地记录已连贯的 serverID;
- 如果 agent 发现,本地连接的 server 正本数小于 serverCount,则会再次向 LB 发送连贯申请,直至本地记录的 serverID 数与 server Count 数统一为止。
该机制尽管帮忙咱们实现了 server 正本的全网段笼罩。但同时,也存在不可漠视的毛病,因为 agent 无奈抉择与哪个 server 正本建设连贯,因而,为了连贯所有的 server 正本,agent 必须重复拜访 LB。在这个过程中,server 因为还没有与所有的 agent 建设连贯,KAS 发来的申请可能无奈转发至对应的节点。一个潜在的解决方案是,为每个 server 正本创立一个独立的 LB,负责与 agent 之间的连贯,同时在 agent 端记录所有 server 正本对应 LB 的信息,这一计划能帮忙 agent 疾速地与所有的 server 正本建设连贯。该计划的具体实现细节,目前仍在与上游社区的开发者探讨中。
3. 为 ANP 增加代理策略
在 OpenYurt 的网络模型下,边缘节点散布在不同的 network region 中,随机抉择的 agent 可能无奈将申请转发至位于其余 region 内的节点上。因而咱们不得不批改 ANP server 底层代理转发的逻辑。然而,依据长期的教训,咱们置信,proxy server 反对不同的代理策略,例如,将申请转发至指定数据中心,region,或者指定主机,是一个较为通用的需要。通过和 ANP 社区开发者探讨,咱们决定重构 ANP 治理 agent 连贯的接口,容许用户依据需要实现新的代理策略,并打算将该 feature 最终合入上游代码库。目前重构工作仍在进行中,在 Yurttunnel 第一个开源版本中,咱们临时采纳以下配置:
- 在每个边缘节点上部署一个 agent。
- agent 在 server 处注销时,应用 agent 所在节点的 IP 作为 agentID。
- server 在转发申请时,通过匹配申请指标 IP 和 agentID,将申请转发至对应的 agent。
咱们打算在 OpenYurt 后续公布 Yurt Unit(边缘节点分区管控)之后,配合新增的 ANP 代理转发策略,实现 agent 的分区部署,和申请的分区转发。
4. 动静申请平安证书
为了解除 yurttunnel 组件对节点证书的依赖,咱们在 yurttunnel 中新增 cert manager 组建,cert manager 会在 server 和 agent 运行后,向 KAS 提交 certificate signning request(CSR)。server 将应用申请到的证书来确保其与 KAS 和 agent 间的平安通信,agent 会应用申请到的证书确保其与 server 间 gRPC 信道的平安。因为 agent 和 kubelet 间是通过 tcp 协定连贯,因而,咱们无需为 agent 和 kubelet 间的连贯筹备证书。
5. 压缩 Tunnel 带宽,节约老本
在 3.5 中,咱们提到,应用 gRPC 封装 Tunnel 尽管能够进步传输稳定性,但同时也会减少公网流量。这是否意味着稳定性和性能,咱们只能二选一?通过对不同用户场景的剖析,咱们发现,在大多数状况下,用户应用运维通道是为了获取容器日志(即 kubectl log),而传统日志文件,存在许多雷同的文本信息,因而咱们推断应用 gzip 等压缩算法能无效放大带宽。为了验证这一假如,咱们在 ANP 底层的 gRPC 库中增加了 gzip compressor,并且比照了与应用原生 TCP 连贯场景下的数据传输量。
咱们思考的第一个试验场景是,别离通过 TCP 连贯和 ANP 获取同一 kubeproxy 容器的日志,咱们截取了这一过程中 Tunnel 上双向 package 和 bytes 总量。
表 1: 原生 TCP V.S. ANP (kubectl logs kube-proxy)
如表 1 所示,通过应用 ANP,总传输数据量降落了 29.93%。
通过长时间运行,容器的日志文本经常能够达到十几兆,为了模仿获取大文本日志的场景。咱们创立了一蕴含 10.5M systemd log(即 journalctl)的 ubuntu 容器,同样咱们别离应用原生 TCP 连贯和 ANP 传输该日志文件,并测量了 Tunnel 上的数据总量。
表 2: 原生 TCP V.S. ANP (large log file)
如表 2 所示,在日志文本较大的状况下,通过应用 ANP,总传输数据量降落了 40.85%。
由此可见,相较于原生 TCP 连贯,ANP 不仅能提供更高的传输稳定性,还能够大幅升高公网流量。思考到边缘集群动辄上万的节点规模,新的解决方案将帮忙用户在公网流量方面节约大量开销。
Yurttunnel 零碎架构
图四:Yurttunnel 零碎架构
综上,Yurttunnel 次要蕴含以下组件:
Yurttunnel Server – 负责将 apiserver,prometheus,metrics server 等管控组件发往节点的申请,转发至对应的 agent。具体包含以下子组件:
- ANP Proxy Server – 对 ANP gRPC server 的封装,负责管理与 Yurttunnel Agent 之间的长连贯,并转发申请。
- Iptable Manager – 批改管控节点的 DNAT 规定,以确保管控组件的申请能被转发至 Yurttunnel Server。
- Cert Manager – 为 Yurttunnel Server 生成 TLS 证书。
- Request Interceptor – 将 KAS 对节点的 HTTP 申请封装到合乎 ANP 规定的 gRPC 包里。
Yurttunnel Agent – 与 Yurttunnel Server 被动建设连贯,并将 Yurttunnel Server 发来的申请转发给 Kubelet。具体包含两个子组件:
- ANP Proxy Agent – 对 ANP gRPC agent 的封装,相较于上游,咱们额定退出了 gzip compressor 以压缩数据。
- Cert Manager – 为 Yurttunnel Agent 生成 TLS 证书。
- Yurttunnel Server Service – 通常是一个 SLB,负责将管控组件发来的申请分发给适合的 Yurttunnel Server 正本,保障 Yurttunnel 的高可用和负载平衡。
总结与瞻望
Yurttunnel 作为 OpenYurt 近期开源的重要组件,买通了 OpenYurt 集群的云边通道,为边缘集群上的容器运维提供了一个对立的入口。通过对上游解决方案进行革新,Yurttunnel 不仅提供了更高的传输稳定性,也大幅升高了数据传输量。
OpenYurt 于 2020 年 5 月 29 日正式对外开源,借助社区和宽广开发者的力量疾速成长,开源仅 3 个月后就正式成为 CNCF 沙箱级别边缘计算云原生我的项目。将来,OpenYurt 将连续“Extending your upstream Kubernetes to edge”的外围设计理念,在抉择与上游放弃最大技术公约数的同时,发挥开源分享的精力,与宽广开发者一起推动 Kubernetes 社区的提高。
OpenYurt 已入围“2020 年度 10 大新锐开源我的项目”,欢送大家点击链接:https://www.infoq.cn/talk/sQ7eKfv1KW1A0kUafBgv,抉择“25 号”,为 OpenYurt 加油助力!
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术畛域、聚焦云原生风行技术趋势、云原生大规模的落地实际,做最懂云原生开发者的公众号。”