发布在即!企业 AIGC 应用程度测评,3 步定制专属评估报告。抢首批测评权益>>> 了解详情
写点什么

Kubernetes 的网络模型如何实现?这里有 4 种解决方案!

  • 2020-04-15
  • 本文字数:5284 字

    阅读完需:约 17 分钟

Kubernetes的网络模型如何实现?这里有4种解决方案!

由于在企业中部署私有云的场景会更普遍,所以在私有云中运行 Kubernetes + Docker 集群之前,就需要自己搭建符合 Kubernetes 要求的网络环境。现在的开源世界里,有很多开源组件可以帮助我们打通 Docker 容器和容器之间的网络,实现 Kubernetes 要求的网络模型。当然每种方案都有自己适合的场景,我们要根据自己的实际需要进行选择。

一、Kubernetes + Flannel

Kubernetes 的网络模型假定了所有 Pod 都在一个可以直接连通的扁平的网络空间中,这在 GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes 假定这个网络已经存在。而在私有云里搭建 Kubernetes 集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的 Docker 容器之间的互相访问先打通,然后运行 Kubernetes。


Flannel 是 CoreOS 团队针对 Kubernetes 设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址。而且它还能在这些 IP 地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递到目标容器内。


下面是一张它的网络原理图:



可以看到,Flannel 首先创建了一个名为 flannel0 的网桥,而且这个网桥的一端连接 docker0 的网桥,另一端连接一个名为 flanneld 的服务进程。


Flanneld 进程并不简单,它首先上连 etcd,利用 etcd 来管理可分配的 IP 地址段资源,同时监控 etcd 中每个 Pod 的实际地址,并在内存中建立了一个 Pod 节点路由表;然后下连 docker0 和物理网络,使用内存中的 Pod 节点路由表,将 docker0 发给它的数据包包装起来,利用物理网络的连接将数据包投递到目标 flanneld 上,从而完成 pod 到 pod 之间的直接的地址通信。


Flannel 之间的底层通信协议的可选余地有很多,比如 UDP、VXlan、AWS VPC 等等。只要能通到对端的 Flannel 就可以了。源 Flannel 封包,目标 Flannel 解包,最终 docker0 看到的就是原始的数据,非常透明,根本感觉不到中间 Flannel 的存在。


Flannel 的安装配置网上讲的很多,在这里就不在赘述了。在这里注意一点,就是 flannel 使用 etcd 作为数据库,所以需要预先安装好 etcd。


下面说说几个场景:


  1. 同一 Pod 内的网络通信。在同一个 Pod 内的容器共享同一个网络命名空间,共享同一个 Linux 协议栈。所以对于网络的各类操作,就和它们在同一台机器上一样,它们可以用 localhost 地址直接访问彼此的端口。其实这和传统的一组普通程序运行的环境是完全一样的,传统的程序不需要针对网络做特别的修改就可以移植了。这样做的结果是简单、安全和高效,也能减少将已经存在的程序从物理机或者虚拟机移植到容器下运行的难度。

  2. Pod1 到 Pod2 的网络,分两种情况。Pod1 与 Pod2 不在同一台主机与 Pod1 与 Pod2 在同一台主机。

  3. 先说 Pod1 与 Pod2 不在同一台主机。Pod 的地址是与 docker0 在同一个网段的,但 docker0 网段与宿主机网卡是两个完全不同的 IP 网段,并且不同 Node 之间的通信只能通过宿主机的物理网卡进行。将 Pod 的 IP 和所在 Node 的 IP 关联起来,通过这个关联让 Pod 可以互相访问。

  4. Pod1 与 Pod2 在同一台主机。Pod1 和 Pod2 在同一台主机的话,由 Docker0 网桥直接转发请求到 Pod2,不需要经过 Flannel。

  5. Pod 到 Service 的网络。创建一个 Service 时,相应会创建一个指向这个 Service 的域名,域名规则为{服务名}.{namespace}.svc.{集群名称}。之前 Service IP 的转发由 iptables 和 kube-proxy 负责,目前基于性能考虑,全部为 iptables 维护和转发。iptables 则由 kubelet 维护。Service 仅支持 UDP 和 TCP 协议,所以像 ping 的 ICMP 协议是用不了的,所以无法 ping 通 Service IP。

  6. Pod 到外网。Pod 向外网发送请求,查找路由表, 转发数据包到宿主机的网卡,宿主网卡完成路由选择后,iptables 执行 Masquerade,把源 IP 更改为宿主网卡的 IP,然后向外网服务器发送请求。

  7. 集群外部访问 Pod 或 Service


由于 Pod 和 Service 是 Kubernetes 集群范围内的虚拟概念,所以集群外的客户端系统无法通过 Pod 的 IP 地址或者 Service 的虚拟 IP 地址和虚拟端口号访问到它们。为了让外部客户端可以访问这些服务,可以将 Pod 或 Service 的端口号映射到宿主机,以使得客户端应用能够通过物理机访问容器应用。


总结:Flannel 实现了对 Kubernetes 网络的支持,但是它引入了多个网络组件,在网络通信时需要转到 flannel0 网络接口,再转到用户态的 flanneld 程序,到对端后还需要走这个过程的反过程,所以也会引入一些网络的时延损耗。另外 Flannel 默认的底层通信协议是 UDP。UDP 本身是非可靠协议,虽然两端的 TCP 实现了可靠传输,但在大流量、高并发应用场景下还需要反复调试,确保不会出现传输质量的问题。特别是对网络依赖重的应用,需要评估对业务的影响。

二、基于 Docker Libnetwork 的网络定制

容器跨主机的网络通信,主要实现思路有两种:二层 VLAN 网络和 Overlay 网络。


  • 二层 VLAN 网络的解决跨主机通信的思路是把原先的网络架构改造为互通的大二层网络,通过特定网络设备直接路由,实现容器点到点的之间通信。

  • Overlay 网络是指在不改变现有网络基础设施的前提下,通过某种约定通信协议,把二层报文封装在 IP 报文之上的新的数据格式。


Libnetwork 是 Docker 团队将 Docker 的网络功能从 Docker 核心代码中分离出去,形成一个单独的库。 Libnetwork 通过插件的形式为 Docker 提供网络功能。 使得用户可以根据自己的需求实现自己的 Driver 来提供不同的网络功能。


Libnetwork 所要实现的网络模型基本是这样的: 用户可以创建一个或多个网络(一个网络就是一个网桥或者一个 VLAN ),一个容器可以加入一个或多个网络。 同一个网络中容器可以通信,不同网络中的容器隔离。这才是将网络从 docker 分离出去的真正含义,即在创建容器之前,我们可以先创建网络(即创建容器与创建网络是分开的),然后决定让容器加入哪个网络。


Libnetwork 实现了 5 种网络模式:


  1. bridge:Docker 默认的容器网络驱动,Container 通过一对 veth pair 链接到 docker0 网桥上,由 Docker 为容器动态分配 IP 及配置路由、防火墙等。

  2. host:容器与主机共享同一 Network Namespace。

  3. null:容器内网络配置为空,需要用户手动为容器配置网络接口及路由。

  4. remote:Docker 网络插件的实现,Remote driver 使得 Libnetwork 可以通过 HTTP Resful API 对接第三方的网络方案,类似于 SocketPlane 的 SDN 方案只要实现了约定的 HTTP URL 处理函数以及底层的网络接口配置方法,就可以替代 Docker 原生的网络实现。

  5. overlay:Docker 原生的跨主机多子网网络方案。



Docker 自身的网络功能比较简单,不能满足很多复杂的应用场景。因此,有很多开源项目用来改善 Docker 的网络功能,如 Pipework、Weave、SocketPlane 等。


举例:网络配置工具 Pipework


Pipework 是一个简单易用的 Docker 容器网络配置工具。由 200 多行 shell 脚本实现。通过使用 IP、brctl、ovs-vsctl 等命令来为 Docker 容器配置自定义的网桥、网卡、路由等。有如下功能:


  • 支持使用自定义的 Linux Bridge、veth pair 为容器提供通信。

  • 支持使用 MacVLAN 设备将容器连接到本地网络。

  • 支持 DHCP 获取容器的 IP。

  • 支持 Open vSwitch。

  • 支持 VLAN 划分。


Pipework 简化了在复杂场景下对容器连接的操作命令,为我们配置复杂的网络拓扑提供了一个强有力的工具。对于一个基本应用而言,Docker 的网络模型已经很不错了。然而,随着云计算和微服务的兴起,我们不能永远停留在使用基本应用的级别上,我们需要性能更好且更灵活的网络功能。Pipework 是个很好的网络配置工具,但 Pipework 并不是一套解决方案,我们可以利用它提供的强大功能,根据自己的需求添加额外的功能,帮助我们构建自己的解决方案。


OVS 跨主机多子网网络方案


OVS 的优势是,作为开源虚拟交换机软件,它相对成熟和稳定,而且支持各类网络隧道协议,经过了 OpenStack 等项目的考验。这个网上很多,就不再赘述了。

三、Kubernetes 集成 Calico

Calico 是一个纯 3 层的数据中心网络方案,而且无缝集成像 OpenStack 这种 IaaS 云架构,能够提供可控的 VM、容器、裸机之间的 IP 通信。


通过将整个互联网的可扩展 IP 网络原则压缩到数据中心级别,Calico 在每一个计算节点利用 Linux Kernel 实现了一个高效的 vRouter 来负责数据转发,而每个 vRouter 通过 BGP 协议负责把自己上运行的 workload 的路由信息像整个 Calico 网络内传播——小规模部署可以直接互联,大规模下可通过指定的 BGP route reflector 来完成。这样保证最终所有的 workload 之间的数据流量都是通过 IP 路由的方式完成互联的。


Calico 节点组网可以直接利用数据中心的网络结构(无论是 L2 或者 L3),不需要额外的 NAT,隧道或者 Overlay Network。



Calico 基于 iptables 还提供了丰富而灵活的网络 Policy,保证通过各个节点上的 ACLs 来提供 Workload 的多租户隔离、安全组以及其他可达性限制等功能。


Calico 有两种布署方案,一般集群都配有 SSL 证书和非证书的情况。


  • 第一种无 HTTPS 连接 etcd 方案,HTTP 模式部署即没有证书,直接连接 etcd

  • 第二种 HTTPS 连接 etcd 集群方案,加载 etcd https 证书模式,有点麻烦


总结:目前 Kubernetes 网络最快的第一就是 Calico,第二种稍慢 Flannel,根据自己的网络环境条件来定。 Calico 作为一款针对企业级数据中心的虚拟网络工具,借助 BGP、路由表和 iptables,实现了一个无需解包封包的三层网络,并且有调试简单的特点。虽然目前还有些小缺陷,比如 stable 版本还无法支持私有网络,但希望在后面的版本中会更加强大。

四、应用容器 IP 固定(参考网上资料)

Docker 1.9 开始支持 Contiv Netplugin,Contiv 带来的方便是用户可以根据实例 IP 直接进行访问。


Docker 1.10 版本支持指定 IP 启动容器,并且由于部分数据库应用对实例 IP 固定有需求,有必要研究容器 IP 固定方案的设计。


在默认的 Kubernetes + Contiv 的网络环境下,容器 Pod 的 IP 网络连接是由 Contiv Network Plugin 来完成的,Contiv Master 只实现了简单的 IP 地址分配和回收,每次部署应用时,并不能保证 Pod IP 不变。所以可以考虑引入新的 Pod 层面的 IPAM(IP 地址管理插件),以保证同一个应用多次发生部署时,Pod IP 始终是不变的。


作为 Pod 层面的 IPAM,可以把这一功能直接集成在 Kubernetes 里。Pod 作为 Kubernetes 的最小调度单元,原有的 Kubernetes Pod Registry(主要负责处理所有与 Pod 以及 Pod subresource 相关的请求:Pod 的增删改查,Pod 的绑定及状态更新,exec/attach/log 等操作)并不支持在创建 Pod 时为 Pod 分配 IP,Pod IP 是通过获取 Pod Infra Container 的 IP 来获取的,而 Pod Infra Container 的 IP 即为 Contiv 动态分配得来的。


在原有 Kubernetes 代码基础上,修改 Pod 结构(在 PodSpec 中加入 PodIP)并重写了 Pod Registry 同时引入了两个新的资源对象:


  1. Pod IP Allocator:Pod IP Allocator 是一个基于 etcd 的 IP 地址分配器,主要实现 Pod IP 的分配与回收。Pod IP Allocator 通过位图记录 IP 地址的分配情况,并且将该位图持久化到 etcd;

  2. Pod IP Recycler:Pod IP Recycler 是一个基于 etcd 的 IP 地址回收站,也是实现 PodConsistent IP 的核心。Pod IP Recycler 基于 RC 全名(namespace + RC name)记录每一个应用曾经使用过的 IP 地址,并且在下一次部署的时候预先使用处于回收状态的 IP。Pod IP Recycler 只会回收通过 RC 创建的 Pod 的 IP,通过其他 controller 或者直接创建的 Pod 的 IP 并不会记录,所以通过这种方式创建的 Pod 的 IP 并不会保持不变;同时 Pod IP Recycle 检测每个已回收 IP 对象的 TTL,目前设置的保留时间为一天。


这里对 kubelet 也需要进行改造,主要包括根据 Pod Spec 中指定 IP 进行相关的容器创建(docker run 加入 IP 指定)以及 Pod 删除时释放 IP 操作。


Pod 的创建在 PaaS 里主要有两种情形:


  • 应用的第一次部署及扩容,这种情况主要是从 IP pool 中随机分配;

  • 应用的重新部署:在重新部署时,已经释放的 IP 已根据 RC 全名存放于 IP Recycle 列表中,这里优先从回收列表中获取 IP,从而达到 IP 固定的效果。


另外为了防止 IP 固定方案中可能出现的问题,在 Kubernetes 中加入了额外的 REST API:包括对已分配 IP 的查询,手动分配/释放 IP。


容器 IP 固定方案已测试评估中,运行基本上没问题,但稳定性有待提升。主要表现在有时不能在预期时间内停止旧 Pod,从而无法释放 IP 造成无法复用(初步原因是由于 Docker 偶尔的卡顿造成无法在规定时间内停止容器),可以手动去修复。但从长期考虑,IP 固定方案还需要加强稳定性并根据具体需求进行优化。


总结:目前已有多种支持 Kubernetes 的网络方案,比如 Flannel、Calico、华为的 Canal、Weave Net 等。因为它们都实现了 CNI 规范,用户无论选择哪种方案,得到的网络模型都一样,即每个 Pod 都有独立的 IP,可以直接通信。区别在于不同方案的底层实现不同,有的采用基于 VXLAN 的 Overlay 实现,有的则是 Underlay,性能上有区别,再有就是是否支持 Network Policy 了。


2020-04-15 23:051158

评论

发布
暂无评论
发现更多内容

工作多年后我更明白了UT的重要性

好好学习,天天向上

银行业只是开始,60个可以被区块链改变的行业

CECBC

数字技术

FISCO BCOS 开发环境节点搭建 | 联盟链开发(一)

李大狗

区块链 联盟链 FISCO BCOS 狗哥

探索 Snabbdom 模块系统原理

pingan8787

JavaScript Vue Web Vue 3 Snabbdom

OpenCV 写图像也有讲究,取经之路第 5 天

梦想橡皮擦

28天写作 3月日更

架构师训练营 4 期 第12周

引花眠

架构师训练营 4 期

Python PyAutoGUI 库

HoneyMoose

uni-app跨端开发H5、小程序、IOS、Android(四):了解uni-app项目结构

黑马腾云

html5 微信小程序 uni-app android iOS Developer

JVM - 类加载器

insight

3月日更

在离开新手村后,你该如何的走出呢?打造属于你的快与慢的能力。

叶小鍵

为何数字人民币要采用“小额匿名、大额可溯”的设计?

CECBC

数字货币

(继续码字) 因果有顺序吗?是一种必要充分条件吗?

mtfelix

28天写作 bewriting 胡思乱想

【LeetCode】矩阵置零Java题解

Albert

算法 LeetCode 28天写作 3月日更

Vue3源码 | createApp都干了什么?

梁龙先森

源码分析 大前端 Vue3

架构 idea

型火🔥

架构 原则 架构之道

科技强国的使命召唤中,百度AI埋下三根未来“引线”

脑极体

Docker 教程(三):Docker 命令

看山

Docker

MongoDB中的null类型查询

Kylin

mongodb 3月日更 21天挑战 数据库查询 NoSql查询语法

控制台的安装与使用 | 联盟链开发(二)

李大狗

联盟链 FISCO BCOS 狗哥

2021十大区块链领域即将起飞

CECBC

区块链 投资

hive数据倾斜解决办法

五分钟学大数据

大数据 hive 28天写作 3月日更

数据仓库设计

大数据技术指南

大数据 28天写作 3月日更

新年上班第一天生产环境分布式文件系统崩了!!

冰河

高可用 分布式存储 fastdfs 可扩展 无限扩容

大数据中流量分析常见分类

大数据技术指南

大数据 28天写作 3月日更

Java8中的 Stream 那么彪悍,你知道它的原理是什么吗?

Java小咖秀

Java 面试 stream java8 开发

Go Channel源码分析

非晓为骁

源码分析 channel Go 语言

产品训练营第八章作业

Arnold

Seldon使用(一):简介及入门

托内多

tensorflow kubeflow Kubernetes PyTorch seldon

领域驱动设计101 - 通用语言

luojiahu

领域驱动设计 DDD

Spark详细剖析

五分钟学大数据

大数据 spark 28天写作 3月日更

2.3 Go语言从入门到精通:数据类型

xcbeyond

3月日更 Go 语言

Kubernetes的网络模型如何实现?这里有4种解决方案!_文化 & 方法_Rancher_InfoQ精选文章