从美图容器优化实践谈Kubernetes网络方案设计

简介: 本文通过介绍美图线上容器化的实践经验,包括线上遇到的实际问题,来探讨 Kubernetes 环境下的网络方案设计。值得正在转型 K8S 的架构师学习和借鉴。 李连荣,美图高级系统研发工程师,曾建立支持千万的长连接服务,从零开始在建立美图的容器化服务,并主导完成美图容器化的网络方案。

本文通过介绍美图线上容器化的实践经验,包括线上遇到的实际问题,来探讨 Kubernetes 环境下的网络方案设计。值得正在转型 K8S 的架构师学习和借鉴。

李连荣,美图高级系统研发工程师,曾建立支持千万的长连接服务,从零开始在建立美图的容器化服务,并主导完成美图容器化的网络方案。在网络、存储方面有非常深厚的造诣。

目前,我们的 Kubernetes 集群选择使用 Calico 作为基础网络方案。


选择 Calico 网络方案的挑战

Calico 是一套基于路由(BGP)的 SDN,它通过路由转发的方式实现容器的跨主机通信。Calico 将每个节点虚拟为一个“路由器”并为之分配独立的虚拟网段,该路由器为当前节点上的容器提供路由服务。

更多 Calico 项目介绍可参阅 https://www.projectcalico.org/ 下面以具体网络为例介绍其中的设计与难点。

以上图为例,如果节点 192.168.1.2 分配的虚拟网段是 10.233.1.0/24,其上运行了一个容器 10.233.1.2,其路由信息如下:

10.233.1.2 0.0.0.0 255.255.255.255 UH 0 0 0 cali814214d5913

当物理机收到目标地址为10.233.1.2 的IP 数据包时会转发到网口 cali814214d5913,而 cali814214d5913 是通过 veth-pair 创建的网卡,它与本机上 IP 地址为 10.233.1.2 的容器互通,因此,IP 地址为 10.233.1.2 容器就可以收到相应的 IP 数据包。

当位于节点 192.168.1.3 上的容器 10.233.2.2 给 10.233.1.2 发送 IP 数据包时,需要知道 10.233.1.2 所在的物理节点的 IP,并添加以下路由规则:

10.233.1.0/16 192.168.1.2 eth0

Calico 通过 BGP 实现节点间相互学习路由规则。节点 192.168.1.2与节点192.168.1.3 建立 BGP 邻居,节点 192.168.1.3 可以通过 BGP 学习到上面的路由规则。当容器 10.233.2.2 发送 IP 数据包给 10.233.1.2 时,会根据上面的路由规则转发到节点 192.168.1.2,并由节点 192.168.12 转发给 10.233.1.2,进而实现容器的跨主机通信。

但是当两个容器所在的节点处于不同的子网时,如10.233.3.2,其所在的节点192.168.2.2与节点192.168.1.2处于不同的子网,此时无法在192.168.2.2上添加以下路由:

10.233.1.0/16 192.168.1.2 eth0

这是因为物理机 192.168.2.2与物理机 192.168.1.2 链路层不通。为了解决这个问题,Calico 选择了 IPIP。IPIP 是将虚拟网络的 IP 数据包封装到物理网络的 IP 数据包里传输。启用 IPIP 后,节点上会出现相应的虚拟网卡,通常是 tunl0,节点1 92.168.2.2 可以添加以下路由规则:

10.233.1.0/16 192.168.1.2 tunl0

与之前的路由的区别在网口换成了 tunl0。当 10.233.3.2 发送 IP 数据包给10.233.1.2 时,其所在的节点会将 IP 数据包转发到网口 tunl0,转发到 tunl0 的 IP 数据包会被 IPIP 驱动接管。IPIP 驱动会将每个 IP 数据包封装到物理网络的 IP 数据包内(目标地址是下一跳地址,即 192.168.1.2,Payload 是虚拟机发出的原始 IP 数据包)发送出去。

由于该 IP 数据包的目标地址是节点 192.168.1.2,因此,可以经过物理网关进行转发。运行在节点 192.168.1.2 上 IPIP 服务接收到该物理网络 IP 数据包后将其 Payload 取出,再根据节点 192.168.1.2 上路由规则转发给相应的容器,进而实现了容器的跨子网通信。

Calico 网络方案存在的问题

通过 Calico 的工作原理可以看出,Calico 存在以下问题:

  • 使用 IPIP 时,需要嵌套 IP 协议,多余的打包和拆包动作会带来的性能开销。
  • 使用 IPIP 时,嵌套的 IP 协议头导致实际有效的 MTU 长度变小,也会影响实际的带宽利用率。
  • 由于集群外的节点无法学习集群内的路由信息,故无法直接访问集群内的容器。

根据 Calico 的工作原理可知,Calico 为了解决容器的跨子网通信选择了 IPIP,也正是因为引入了 IPIP 才引发了一系列的性能问题,那么,为什么 Calico 会选择 IPIP 协议呢?

为了理解这个问题,我们先看一下传统的物理网络是如何解决跨子网通信的。仍以上图为例,物理机 192.168.2.3 访问物理机 192.168.1.2 的步骤如下:

  • 物理机 192.168.2.3 检测到目标 IP 与自己处于不同的子网,因此,通过默认路由规则发送给其所在网关 192.168.2.1。
  • 物理网关 192.168.2.1 通过路由协议可以知道网关 192.168.2.1 可以转发 IP 包给物理 192.168.1.2,因此,将相应的 IP 包转发给网关 192.168.1.1。
  • 物理网关 192.168.1.1 再将 IP 包转发给物理机 192.168.1.2。

我们再来看一下 Calico 网络。如果没有 IPIP,容器 10.233.4.2 访问容器 10.233.1.2 的步骤如下:

  • 宿主机 192.168.2.3 检测到目标 IP 与自己处于不同的子网,因此,会将目标地址为 10.233.1.2 的 IP 包转发给其所在网关 192.168.2.1。
  • 网关 192.168.2.1 没有匹配的路由规则,因此 drop 该 IP 包并会返回目标不可达。

如果引入 IPIP,容器 10.233.4.2 访问容器 10.233.1.2 的步骤如下:

  • 宿主机 192.168.2.3 匹配到路由规则 “10.233.1.0/16 192.168.1.2 tunl0”。
  • 宿主机 192.168.2.3 将该容器发出的 IP 包通过 tunl0 端口转发到物理机192.168.1.2。
  • IPIP 驱动将容器发出的 IP 包(目标地址 10.233.1.2)作为物理网络 IP 包(目标地址 192.168.1.2)的 Payload 发出。
  • 宿主机 192.168.2.3 按照物理网络的传输方式将物理网络 IP 包发送到宿主机 192.168.1.2。
  • 宿主机 192.168.1.2 上 IPIP 驱动接收到该 IP 包之后解包并将该 Payload 作为 IP 包转发给容器 10.233.1.2。

因此,在物理网关不能为虚拟网络提供路由服务的前提下,Calico 选择使用 IPIP 的方式来解决容器的跨子网通信。

如果通过某种方法,让物理网关能够学习到 Calico 虚拟网络的路由规则,那么物理网关就可以为虚拟网络提供路由服务,Calico 就可以在不引入 IPIP 的前提下实现容器的跨子网通信,但是,Calico 为什么没有选择这种方式呢?

这是因为 Calico 的主要应用场景是公有云,公有云具备以下特性:

  • 多数公有云厂商可以提供一个稳定的大二层环境,其内的主机可以工作在同一个子网段,也就不存在跨子网通信的问题
  • 不是所有的公有云厂商都可以提供 BGP 路由学习的接口,如果云厂商不提供 BGP 接口,Calico就无法同步虚拟网络路由规则给公有云

因此,在这个前提下,Calico 选择 IPIP 方式是非常合理的。

对于私有云场景:

  • 不是所有的私有云环境都支持大二层,对 Calico 跨子网通信的需求是非常强烈的。
  • 所有硬件(包括网关)都在可控范围内,只要物理网关支持 BGP 协议,Calico 就可以同步路由规则给物理网关。

因此,对于私有云场景,通过让 Calico 同步虚拟网络路由规则给物理网关的方式来解决跨子网通信会是更好的选择。

性能提升方案

其实 Calico 的文档中提到了一种同步路由规则给物理网关的方式,具体可以参考如下链接:

https://docs.projectcalico.org/v2.6/usage/external-connectivity

本文参考这种设计,将虚拟网络路由规则同步给物理网关,虚拟网络与物理网络建立 BGP 邻居的方式有两种:

  • 方案一:各节点分别物理网关建立 BGP 邻居
  • 方案二:中心化组件与物理网关建立 BGP 邻居

下面针对两种方案进行分析。

方案一

如下图所示,方案一需要每个 SDN 节点分别与其所在的物理网关建立 BGP 邻居。由于每个 SDN 节点作为本机容器的网关,如果运行在该物理机上 Calico 服务能够与物理网关建立 BGP,并将自己的路由规则同步给物理网关,那么,物理网关就可以学习虚拟网络的路由规则。

运行在节点上的 SDN 服务可以通过编码或者脚本实现自动建立 BGP 邻居的逻辑,但是,这也需要物理网关的支持。如果物理网关不支持自动建立 BGP 邻居,仅仅是在 SDN 端实现是没有意义的。

传统的 BGP 路由器需要逐个配置 BGP 邻居,这对容器化集群来说是不可接受到。因为容器化集群的规模一般都比较大,在集群使用过程中也会经常的调整节点,如扩容、缩容、机器故障等。如果每次调整节点都需要运维手动完成 BGP 邻居的配置,运维成本是巨大的,而且容易因误操作而影响集群稳定性,因此,需要网关支持自动建立 BGP 邻居。

要实现自动建立 BGP 邻居需要使用支持 Dynamic Neighbors 功能的路由器。传统的路由器在配置 BGP 邻居时需要指定明确的 IP 地址,而支持 Dynamic Neighbors 的路由器可以指定一个 IP 网段,该路由器可以自动接受指定网段内BGP设备发起的建立邻居的请求。

集群部署前先配置好路由器的 Dynamic Neighbors,调整集群节点时运行在节点上的 SDN 服务主动与之建立 BGP 邻居,并将其所在节点的路由信息同步给物理网关。例如,运行在物理机 192.168.1.2 上的 SDN 服务自动与物理网关 192.168.1.1 建立 BGP 邻居(eBGP)并将以下路由规则同步给物理网关:

10.233.1.0/24 192.168.1.2 eth0

物理网关 192.168.1.1 学习到以上规则之后会通过 BGP 或者其它路由同步协议同步给物理网关 192.168.2.1,通过这种方式,整个物理网络都可以学习上以上规则。集群的容器要发送数据到 10.233.1.0/24 网段时,直接通过其宿主机将数据包发送给物理网关,物理网关即可根据其学到的虚拟网络路由信息转发到目标主机,最后,再由目标主机转发给相应的容器。

方案二

方案二需要引入中心化组件,本文称之为 BGP Speaker,其网络结构如下:

BGP Speaker 运行在 SDN 集群内,它负责收集 SDN 集群内的路由信息并通过BGP 同步给物理网关。由于该模块可以收集 SDN 集群内的全部路由信息,故不再需要每个 SDN 节点单独与物理网关建立 BGP 邻居,也就不再依赖物理网关的的 Dynamic Neighbors 功能。

如下图所示,BGP Speaker 主要分为两部分:observer 和 publisher。

  • observer:负责收集 SDN 集群的路由信息。
  • publisher:将 observer 收集到的路由信息同步给物理网关。

Calico 将 SDN 集群相关的信息(包括配置信息、每个节点的虚拟网段等)保存在 etcd 里,而 etcd 的支持 watch,因此,observer 可以通过watch方式实时获取 Calico 集群的节点信息。observer 主要关注每个 SDN 节点划分的虚拟网段信息,并根据获取到的虚拟网段信息生成对应的路由规则,如节点 192.168.1.2 划分的虚拟网段是 10.233.1.0/24,observer 会生成以下路由规则:

10.233.1.0/24 192.168.1.2 eth0

publisher 实现了 BGP 协议,它与物理网关建立 BGP 邻居(eBGP),主要工作是将 observer 收集到的路由信息同步给物理网关。由于 publisher 需要将不同节点的路由信息同步给物理网关,因此,publisher 对物理网关来讲,实际上是个 BGP Route Reflector。

gobgp 提供了开源的 BGP 协议库,支持完整的 BGP 协议,可以作为 publisher的基础库。另外,BGP 是双向的,publisher 不仅可以将自己持有的路由信息同步给物理路由器,物理路由器也会同步路由信息给 publisher,由于 SDN 不需要了解物理网络的路由信息,因此,publisher 可以过滤掉这些路由信息。

由于 BGP Speaker 是中心化部署的,因此 BGP Spaker 的高可用程度会直接影响 SDN 集群的稳定性。BGP Speaker 直接从 SDN 集群的 etcd 存储中获取集群信息,其自身不需要保存任何数据(包括生成的路由信息),故 BGP Speaker是无状态的,因此,只需要在 SDN 集群内部署多套 BGP Speaker 即可实现高可用。

多套 BGP Speaker 之间相互不感知,各自独立运行。部署 BGP Speaker时,还可以根据物理网络的拓扑结构将 BGP Speaker 部署在不同的机架或者机房,保证某个机架或机房出现故障时 SDN 集群仍可正常工作。

安全隐患

以上两种方案都可以实现物理网络与虚拟网络的互通,但两种方案都是虚拟网络通过 BGP 协议自动的同步路由规则给物理网关,如果虚拟网络产生了错误的路由规则或者产生的路由规则与物理网络冲突,就会影响集群所处物理网络的运行状态;如果同一物理网络内部署了多套 SDN 集群且这多套 SDN 的网段有冲突时,也会造成虚拟网络的路由规则紊乱,影响 SDN 的稳定性。

因此,还需要采取一些措施来保证 SDN 之间以及 SDN 与物理网络之间不冲突。

确保 SDN 与物理网络不冲突

现在的物理网关大多都支持路由过滤,也就是说当网关通过 BGP 学习到新的路由规则时,可以根据一定的规则进行过滤,只有满足要求的路由规则,才会同步到自己的路由表。部署容器化集群时,应先规划好 SDN 的网络地址,要保证 SDN 的网络地址与物理网络不冲突。

配置物理网关时,可以通过设置过滤规则来保证 SDN 不能修改其所属网段以外的任何任何路由规则(例如,限制 SDN 只能更新目标地址处于 10.233.0.0/16 网段内的路由规则),通过这种方式,可以确保 SDN 不会影响物理网络稳定性。

确保 SDN 之间不冲突

物理网络与虚拟网络互通后,部署在同一个物理网络内的多个 SDN 集群的路由信息都会同步到物理网关,如果不同 SDN 的网络地址有重叠,就会引发冲突,导致 SDN 网络无法稳定工作,因此,在部署 SDN 集群时,还需要为不同的 SDN 集群分配不同的网络地址(这些地址都与物理网络不冲突)。配置网关时,限制每个 SDN 只能同步处于自己网络地址内的路由规则。

总结

Calico 存在性能问题的根本原因是物理网络与虚拟网络不互通,本文设计了两种方案实现物理网络与虚拟网络的互通,解决了 Calico 引入 IPIP 和 NAT 带来的性能问题,也带来了一定的安全隐患,但是,可以通过额外的保障措施排除安全隐患,保证物理网络与 SDN 网络的稳定运行。

本文转自kubernetes中文社区-从美图容器优化实践谈Kubernetes网络方案设计

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
11月前
|
机器学习/深度学习 自然语言处理 数据可视化
基于图神经网络的自然语言处理:融合LangGraph与大型概念模型的情感分析实践
本文探讨了在企业数字化转型中,大型概念模型(LCMs)与图神经网络结合处理非结构化文本数据的技术方案。LCMs突破传统词汇级处理局限,以概念级语义理解为核心,增强情感分析、实体识别和主题建模能力。通过构建基于LangGraph的混合符号-语义处理管道,整合符号方法的结构化优势与语义方法的理解深度,实现精准的文本分析。具体应用中,该架构通过预处理、图构建、嵌入生成及GNN推理等模块,完成客户反馈的情感分类与主题聚类。最终,LangGraph工作流编排确保各模块高效协作,为企业提供可解释性强、业务价值高的分析结果。此技术融合为挖掘非结构化数据价值、支持数据驱动决策提供了创新路径。
614 6
基于图神经网络的自然语言处理:融合LangGraph与大型概念模型的情感分析实践
|
10月前
|
运维 Kubernetes 前端开发
如何用 eBPF 实现 Kubernetes 网络可观测性?实战指南
本文深入探讨了Kubernetes网络观测的挑战与eBPF技术的应用。首先分析了传统工具在数据碎片化、上下文缺失和性能瓶颈上的局限性,接着阐述了eBPF通过零拷贝观测、全链路关联和动态过滤等特性带来的优势。文章进一步解析了eBPF观测架构的设计与实现,包括关键数据结构、内核探针部署及生产环境拓扑。实战部分展示了如何构建全栈观测系统,并结合NetworkPolicy验证、跨节点流量分析等高级场景,提供具体代码示例。最后,通过典型案例分析和性能数据对比,验证了eBPF方案的有效性,并展望了未来演进方向,如智能诊断系统与Wasm集成。
440 0
|
6月前
|
监控 负载均衡 安全
WebSocket网络编程深度实践:从协议原理到生产级应用
蒋星熠Jaxonic,技术宇宙中的星际旅人,以代码为舟、算法为帆,探索实时通信的无限可能。本文深入解析WebSocket协议原理、工程实践与架构设计,涵盖握手机制、心跳保活、集群部署、安全防护等核心内容,结合代码示例与架构图,助你构建稳定高效的实时应用,在二进制星河中谱写极客诗篇。
WebSocket网络编程深度实践:从协议原理到生产级应用
|
12月前
|
存储 SQL 运维
中国联通网络资源湖仓一体应用实践
本文分享了中国联通技术专家李晓昱在Flink Forward Asia 2024上的演讲,介绍如何借助Flink+Paimon湖仓一体架构解决传统数仓处理百亿级数据的瓶颈。内容涵盖网络资源中心概况、现有挑战、新架构设计及实施效果。新方案实现了数据一致性100%,同步延迟从3小时降至3分钟,存储成本降低50%,为通信行业提供了高效的数据管理范例。未来将深化流式数仓与智能运维融合,推动数字化升级。
589 0
中国联通网络资源湖仓一体应用实践
|
10月前
|
Docker 容器
Docker网关冲突导致容器启动网络异常解决方案
当执行`docker-compose up`命令时,服务器网络可能因Docker创建新网桥导致IP段冲突而中断。原因是Docker默认的docker0网卡(172.17.0.1/16)与宿主机网络地址段重叠,引发路由异常。解决方法为修改docker0地址段,通过配置`/etc/docker/daemon.json`调整为非冲突段(如192.168.200.1/24),并重启服务。同时,在`docker-compose.yml`中指定网络模式为`bridge`,最后通过检查docker0地址、网络接口列表及测试容器启动验证修复效果。
1571 39
|
9月前
|
存储 Linux 容器
【Container App】在容器中抓取网络包的方法
本文介绍在Azure Container App中安装tcpdump抓取网络包,并通过Storage Account上传抓包文件的方法。内容包括使用curl和nc测试外部接口连通性、长Ping端口、安装tcpdump、抓取网络包、以及通过crul命令上传文件至Azure Storage。适用于需要分析网络请求和排查网络问题的场景。
261 0
|
11月前
|
网络协议 Docker 容器
使用网络--容器互联
使用网络--容器互联
211 18
|
11月前
|
Kubernetes Cloud Native 区块链
Arista cEOS 4.30.10M - 针对云原生环境设计的容器化网络操作系统
Arista cEOS 4.30.10M - 针对云原生环境设计的容器化网络操作系统
338 0
|
人工智能 运维 监控
领先AI企业经验谈:探究AI分布式推理网络架构实践
当前,AI行业正处于快速发展的关键时期。继DeepSeek大放异彩之后,又一款备受瞩目的AI智能体产品Manus横空出世。Manus具备独立思考、规划和执行复杂任务的能力,其多智能体架构能够自主调用工具。在GAIA基准测试中,Manus的性能超越了OpenAI同层次的大模型,展现出卓越的技术实力。
|
8月前
|
Kubernetes Docker Python
Docker 与 Kubernetes 容器化部署核心技术及企业级应用实践全方案解析
本文详解Docker与Kubernetes容器化技术,涵盖概念原理、环境搭建、镜像构建、应用部署及监控扩展,助你掌握企业级容器化方案,提升应用开发与运维效率。
1132 108

相关产品

  • 容器服务Kubernetes版