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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 本文通过介绍美图线上容器化的实践经验,包括线上遇到的实际问题,来探讨 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网络方案设计

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
9天前
|
安全 虚拟化
在数字化时代,网络项目的重要性日益凸显。本文从前期准备、方案内容和注意事项三个方面,详细解析了如何撰写一个优质高效的网络项目实施方案,帮助企业和用户实现更好的体验和竞争力
在数字化时代,网络项目的重要性日益凸显。本文从前期准备、方案内容和注意事项三个方面,详细解析了如何撰写一个优质高效的网络项目实施方案,帮助企业和用户实现更好的体验和竞争力。通过具体案例,展示了方案的制定和实施过程,强调了目标明确、技术先进、计划周密、风险可控和预算合理的重要性。
26 5
|
11天前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker和Kubernetes入门
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
45 2
|
13天前
|
存储 Kubernetes Docker
【赵渝强老师】Kubernetes中Pod的基础容器
Pod 是 Kubernetes 中的基本单位,代表集群上运行的一个进程。它由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。基础容器负责维护 Pod 的网络空间,对用户透明。文中附有图片和视频讲解,详细介绍了 Pod 的组成结构及其在网络配置中的作用。
【赵渝强老师】Kubernetes中Pod的基础容器
|
1天前
|
云安全 监控 安全
云计算环境下的网络安全策略与实践
在数字化时代,云计算已成为企业和个人存储、处理数据的重要方式。然而,随着云服务的普及,网络安全问题也日益凸显。本文将探讨如何在云计算环境中实施有效的网络安全措施,包括加密技术、访问控制、安全监控和应急响应计划等方面。我们将通过具体案例分析,展示如何在实际场景中应用这些策略,以保护云中的数据不受威胁。
|
13天前
|
运维 Kubernetes Shell
【赵渝强老师】K8s中Pod的临时容器
Pod 是 Kubernetes 中的基本调度单位,由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。临时容器用于故障排查和性能诊断,不适用于构建应用程序。当 Pod 中的容器异常退出或容器镜像不包含调试工具时,临时容器非常有用。文中通过示例展示了如何使用 `kubectl debug` 命令创建临时容器进行调试。
|
13天前
|
Kubernetes 调度 容器
【赵渝强老师】K8s中Pod中的业务容器
Pod 是 Kubernetes 中的基本调度单元,由一个或多个容器组成。除了业务容器,Pod 还包括基础容器、初始化容器和临时容器。本文通过示例介绍如何创建包含业务容器的 Pod,并提供了一个视频讲解。示例中创建了一个名为 "busybox-container" 的业务容器,并使用 `kubectl create -f firstpod.yaml` 命令部署 Pod。
|
13天前
|
Kubernetes 容器 Perl
【赵渝强老师】K8s中Pod中的初始化容器
Kubernetes的Pod包含业务容器、基础容器、初始化容器和临时容器。初始化容器在业务容器前运行,用于执行必要的初始化任务。本文介绍了初始化容器的作用、配置方法及优势,并提供了一个示例。
|
13天前
|
数据采集 网络协议 算法
移动端弱网优化专题(十四):携程APP移动网络优化实践(弱网识别篇)
本文从方案设计、代码开发到技术落地,详尽的分享了携程在移动端弱网识别方面的实践经验,如果你也有类似需求,这篇文章会是一个不错的实操指南。
38 1
|
13天前
|
Kubernetes 监控 Java
如何在Kubernetes中配置镜像和容器的定期垃圾回收
如何在Kubernetes中配置镜像和容器的定期垃圾回收
|
1天前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的知识,并提供一些实用的技巧和建议,帮助读者更好地保护自己的网络安全和信息安全。

相关产品

  • 容器服务Kubernetes版