前言

本篇是Kubernetes第十一篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战,此篇文章概念比较多,后续我会继续出一些网络相关实战以及原理探索篇。

Kubernetes系列文章:
  1. Kubernetes介绍
  2. Kubernetes环境搭建
  3. Kubernetes-kubectl介绍
  4. Kubernetes-Pod介绍(-)
  5. Kubernetes-Pod介绍(二)-生命周期
  6. Kubernetes-Pod介绍(三)-Pod调度
  7. Kubernetes-Pod介绍(四)-Deployment
  8. Kubernetes-Service介绍(一)-基本概念
  9. Kubernetes-Service介绍(二)-服务发现
  10. Kubernetes-Service介绍(三)-Ingress(含最新版安装踩坑实践)

Kubernetes网络设计

在实际生产中,我们面临多种多样的业务场景,导致业务之间的调用关系更加复杂化,从而对网络提出更高的要求,对于Kubernetes来说主要解决以下四个问题:

  1. Pod中容器与容器之间的通信问题;

  2. Pod与Pod之间的网络通信问题;

  3. Pod与Service之间的通信问题;

  4. 集群内部与外部的通信问题;

第三和第四点我们在前面的章节已经讲过,大家可以在Service章节具体回忆下,重点介绍下第一、二点;

容器与容器之间的通信问题

介绍Pod时候我们说过Pod内部的容器共享Pod的命名空间的,因此在同一个Pod内的容器之间对于网络的各类操作,就和它们在同一台机器上一样,可以用localhost地址访问彼此的端口。


img

Pod与Pod之间的网络通信问题

每个Pod都有自己单独的IP,两个Pod既有可能运行在同一个Node上,也有可能运行在不同的Node上,因此对于Pod之间的通信可以分为两类:

同一个Node内的Pod之间的通信

对于在同一台机器上的两个Pod来说,都是连接到同一个docker0网桥上,它们的IP地址IP1、IP2都是从docker0网段上动态获取的,它们和网桥本身的IP3是同一个网段的,Pod1和Pod2处于同一局域网内,它们之间可以通过docker0作为路由进行通信。


img
不同Node上的Pod之间的通信

在Kubernetes的网络世界中,Pod之间假设是通过访问对方的Pod IP进行通信的,而不同Node之间的通信只能通过Node的物理网卡进行,Pod的IP地址是由各Node上的docker0网桥动态分配的。我们想要实现跨Node的Pod之间的通信,至少需要满足下面两个条件:

  1. Kubernetes集群中对Pod的IP分配不能有冲突;
  2. Pod IP 和Node IP之间的映射关系,通过Node IP转发到Pod IP;

根据条件1的要求,Kubernetes会再部署的时候对docker0的IP地址进行规划,保证每个Node上的docker0地址都没有冲突,此外Kubernetes会记录所有正在运行的Pod的IP分配信息,并将这些信息保存到etcd中,这样我们就可以知道Pod IP和Node IP之间的映射关系。

根据条件2要求,Pod中的数据在发送出去的时候,需要一个机制能够知道对方Pod的IP地址挂载到那个具体的Node上,这样就可以将数据发送到对应的宿主机上,宿主机将响应的数据转发到具体的docker0上,当数据到达docker0以后,就会将对应的数据转发到对应的容器上了。


img

CNI

Kubernetes本身并不负责网络通信,Kubernetes提供了容器网络接口CNI,具体的网络通信交给CNI插件来负责,开源的CNI插件非常多,像Flannel、Calico等,各大云厂商也都自己定制的CNI。


img

为什么会有CNI

CNI是Container Network Interface的缩写,简答说就是容器解决网络问题,提供的一个标准的,通用的接口。现在有各种各样的容器平台:docker,kubernetes,mesos,我们也有各种各样的容器网络解决方案:flannel,calico,weave,并且还有各种新的解决方案在不断涌现。如果每出现一个新的解决方案,我们都需要对两者进行适配,那么由此带来的工作量必然是巨大的,而且也是重复和不必要的。事实上,我们只要提供一个标准的接口,更准确的说是一种协议,就能完美地解决上述问题。一旦有新的网络方案出现,只要它能满足这个标准的协议,那么它就能为同样满足该协议的所有容器平台提供网络功能,而CNI正是这个标准接口协议。

什么是CNI

CNI是一个接口协议,用于连接容器管理系统和网络插件。前者提供一个容器所在的network namespace(从网络的角度来看,network namespace和容器是完全等价的),后者负责将network interface插入该network namespace中(比如veth的一端),并且在宿主机做一些必要的配置(例如将veth的另一端加入bridge中),最后对namespace中的interface进行IP和路由的配置。那么CNI的工作其实主要是从容器管理系统处获取运行时信息,包括network namespace的路径,容器ID以及network interface name,再从容器网络的配置文件中加载网络配置信息,再将这些信息传递给对应的插件,由插件进行具体的网络配置工作,并将配置的结果再返回到容器管理系统中。


img

CNI仅关注在创建容器时分配网络资源,和在销毁容器时删除网络资源,这使得CNI规范非常轻巧、易于实现,得到了广泛的支持。在CNI模型中只涉及两个概念:容器和网络。

容器(Container):是拥有独立Linux网络命名空间的环境,例如使用Docker或rkt创建的容器。容器需要拥有自己的Linux网络命名空间,这是加入网络的必要条件。

网络(Network):表示可以互连的一组实体,这些实体拥有各自独立、唯一的IP地址,可以是容器、物理机或者其他网络设备(比如路由器)等。

对容器网络的设置和操作都通过插件(Plugin)进行具体实现,CNI插件包括两种类型:CNI Plugin和IPAM(IP Address Management)Plugin。CNI Plugin负责为容器配置网络资源,IPAM Plugin负责对容器的IP地址进行分配和管理。IPAM Plugin作为CNI Plugin的一部分,与CNIPlugin协同工作。

插件介绍

CNI Plugin插件

CNI Plugin包括3个基本接口的定义:添加(ADD)、删除(DELETE)、检查(CHECK)和版本查询(VERSION)。这些接口的具体实现要求插件提供一个可执行的程序,在容器网络添加或删除时进行调用,以完成具体的操作。

添加:将容器添加到某个网络。主要过程为在Container Runtime创建容器时,先创建好容器内的网络命名空间(Network Namespace),然后调用CNI插件为该netns进行网络配置,最后启动容器内的进程。添加接口的参数如下:

  • Version:CNI版本号;

  • ContainerID:容器ID;

  • Network Namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net;

  • Network configuration:网络配置JSON文档,用于描述容器待加入的网络;

  • Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制;

  • Name of the interface inside the container:容器内的网卡名,返回的信息如下:

  • Interfaces list:网卡列表,根据Plugin的实现,可能包括Sandbox Interface名称、主机Interface名称、每个Interface的地址等信息;

  • IPs assigned to the interface:IPv4或者IPv6地址、网关地址、路由信息等;

  • DNS information:DNS相关的信息;

删除:容器销毁时将容器从某个网络中删除。删除接口的参数如下:

  • Version:CNI版本号;

  • ContainerID:容器ID;

  • Network Namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net;

  • Network configuration:网络配置JSON文档,用于描述容器待加入的网络;

  • Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制;

  • Name of the interface inside the container:容器内的网卡名;

检查:检查容器网络是否正确设置。检查接口的参数如下:

  • Version:CNI版本号;

  • ContainerID:容器ID;

  • Network Namespace path:容器的网络命名空间路径,例如/proc/[pid]/ns/net;

  • Network configuration:网络配置JSON文档,用于描述容器待加入的网络;

  • Extra arguments:其他参数,提供基于容器的CNI插件简单配置机制;

  • Name of the interface inside the container:容器内的网卡名;

版本查询:查询网络插件支持的CNI规范版本号。无参数,返回值为网络插件支持的CNI规范版本号。

IPAM Plugin插件

为了减轻CNI Plugin对IP地址管理的负担,在CNI规范中设置了一个新的插件专门用于管理容器的IP地址(还包括网关、路由等信息),被称为IPAM Plugin。通常由CNI Plugin在运行时自动调用IPAM Plugin完成容器IP地址的分配。

IPAM Plugin负责为容器分配IP地址、网关、路由和DNS,典型的实现包括host-local和dhcp。与CNI Plugin类似,IPAM插件也通过可执行程序完成IP地址分配的具体操作。IPAM可执行程序也处理传递给CNI插件的环境变量和通过标准输入(stdin)传入的网络配置参数。

如果成功完成了容器IP地址的分配,则IPAM插件应该通过标准输出(stdout)返回JSON报文。包括ips、routes和dns三段内容:

  • ips段:分配给容器的IP地址(也可能包括网关);

  • routes段:路由规则记录;

  • dns段:DNS相关的信息;

Kubernetes网络插件

Kubernetes管理的是集群,Kubernetes中的网络要解决的核心问题就是每台主机的IP地址网段划分,以及单个容器的IP地址分配。需要做到以下几点:

  1. 保证每个Pod拥有一个集群内唯一的IP地址;

  2. 保证不同节点的IP地址划分不会重复;

  3. 保证跨节点的Pod可以互相通信;

  4. 保证不同节点的Pod可以与跨节点的主机互相通信;

Kubernetes目前支持两种网络插件的实现。

CNI插件:根据CNI规范实现其接口,以与插件提供者进行对接。

kubenet插件:使用bridge和host-local CNI插件实现一个基本的cbr0。

为了在Kubernetes集群中使用网络插件,需要在kubelet服务的启动参数上设置下面两个参数:

  • --network-plugin-dir:kubelet启动时扫描网络插件的目录。
  • --network-plugin:网络插件名称,对于CNI插件,设置为cni即可,无须关注--network-plugin-dir的路径。对于kubenet插件,设置为kubenet,目前仅实现了一个简单的cbr0 Linux网桥。

在设置--network-plugin="cni"时,kubelet还需设置下面两个参数。

  • --cni-conf-dir:CNI插件的配置文件目录,默认为/etc/cni/net.d。该目录下配置文件的内容需要符合CNI规范。
  • --cni-bin-dir:CNI插件的可执行文件目录,默认为/opt/cni/bin。

开源容器网络方案

Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平网络空间中。若需要实现这个网络假设,需要实现不同节点上的Docker容器之间的互相访问,然后运行Kubernetes。目前已经有多个开源组件支持容器网络模型。如Flannel、Open vSwitch、直接路由和Calico。

Flannel

Flannel是一种基于overlay网络的跨主机容器网络解决方案,即将TCP数据包封装在另一种网络包里面进行路由转发和通信,Flannel是CoreOS开发,Flannel之所以可以搭建Kubernetes依赖的底层网络,是因为它能实现以下两点:

  1. 它能协助Kubernetes,给每一个Node上的Docker容器都分配互相不冲突的IP地址;
  2. 它能在这些IP地址之间建立一个Overlay Network,通过这个网络将数据包原封不动地传递到目标容器内

image.png

Flannel首先创建了一个名为flannel0的网桥,而且这个网桥的一端连接docker0网桥,另一端连接一个叫作flanneld的服务进程。flanneld进程上连etcd,利用etcd来管理可分配的IP地址段资源,同时监控etcd中每个Pod的实际地址,并在内存中建立了一个Pod节点路由表;flanneld进程下连docker0和物理网络,使用内存中的Pod节点路由表,将docker0发给它的数据包包装起来,利用物理网络的连接将数据包投递到目标flanneld上,从而完成Pod到Pod之间的直接地址通信。

Flannel之间的底层通信协议的可选技术包括UDP、VxLan、AWS VPC等多种方式。通过源flanneld封包、目标flanneld解包,最终docker0收到的就是原始的数据,对容器应用来说是透明的,感觉不到中间Flannel的存在。

Flannel每次分配的地址段都在同一个公共区域获取,存储在集中的etcd上,从而实现不同Node上的Pod分配的IP不产生冲突。Flannel通过修改Docker的启动参数将分配给它的地址段传递进去。

通过如上方式,Flannel就控制了每个Node上的docker0地址段的地址,从而保障了所有Pod的IP地址在同一个水平网络中且不产生冲突。Flannel完美地实现了对Kubernetes网络的支持,但是它引入了多个网络组件,在网络通信时需要转到flannel0网络接口,再转到用户态的flanneld程序,到对端后还需要走这个过程的反过程,所以也会引入一些网络的时延损耗。另外,Flannel模型默认采用了UDP作为底层传输协议,UDP本身是非可靠协议,虽然两端的TCP实现了可靠传输,但在大流量、高并发的应用场景下还建议多次测试。

Calico

Calco组件简介

Calico是一个基于BGP的纯三层的网络方案,与OpenStack、Kubernetes、AWS、GCE等云平台都能够良好地集成。Calico在每个计算节点都利用Linux Kernel实现了一个高效的vRouter来负责数据转发。每个vRouter都通过BGP1协议把在本节点上运行的容器的路由信息向整个Calico网络广播,并自动设置到达其他节点的路由转发规则。

Calico保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用数据中心的网络结构(L2或者L3),不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。


img

Calico在小规模集群中可以直接互联,在大规模集群中可以通过额外的BGP route reflector来完成。Calico基于iptables还提供了丰富的网络策略,实现了Kubernetes的Network Policy策略,提供容器间网络可达性限制的功能。

Calico架构

image.png

Calico的主要组件:

Felix:Calico Agent,运行在每个Node上,负责为容器设置网络资源(IP地址、路由规则、iptables规则等),保证跨主机容器网络互通;

etcd:Calico使用的后端存储;

BGP Client:负责把Felix在各Node上设置的路由信息通过BGP协议广播到Calico网络;

Route Reflector:通过一个或者多个BGP Route Reflector来完成大规模集群的分级路由分发;

CalicoCtl:Calico命令行管理工具;

本文主要参考《Kubernetes权威指南实战》

结束

欢迎大家点点关注,点点赞!

Kubernetes-网络的更多相关文章

  1. Kubernetes 网络改进的三项实践分享

    自研CNI IPAM插件 解决K8s功能问题 首先,在功能方面,Kubernetes 网络模型由于IP不固定,无法对IP资源进行精细管控,无法使用基于IP的监控和基于IP的安全策略,此外,一些IP发现 ...

  2. [翻译] 一个kubernetes网络简明教程[Part 1]

    一个kubernetes网络简明教程[Part 1] 翻译: icebug 所有我学到的关于kubernetes网络的事情 你可能已经在kubernetes集群当中跑了一堆服务并且正在享受其带来的好处 ...

  3. Kubernetes网络的4种解决方案

    一.Kubernetes + Flannel Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中,这在GCE(Google Compute Engine)里面是现成的 ...

  4. Kubernetes网络方案的三大类别和六个场景

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 本文章根据网易云资深解决方案架构师 王必成在云原生用户大会上的分享整理. 今天我将分享个人对于网络方案的理解,以及网易云在交付 Kubernetes ...

  5. 深入解读docker网络与kubernetes网络

    前言:你是否学习使用k8s很久很久了可是对于网络这块仍旧似懂非懂呢? 您是否对网上一堆帖子有如下的抱怨: 打开多个博客,然后发现有区别么? 明显是直译过来的,越看越迷糊 “因为xxx,所以yyy”,. ...

  6. 99% 的人都不知道的 Kubernetes 网络疑难杂症排查方法

    原文链接:Kubernetes 网络疑难杂症排查分享 大家好,我是 roc,来自腾讯云容器服务 (TKE) 团队,经常帮助用户解决各种 K8S 的疑难杂症,积累了比较丰富的经验,本文分享几个比较复杂的 ...

  7. 从零开始入门 K8s | Kubernetes 网络概念及策略控制

    作者 | 阿里巴巴高级技术专家  叶磊 一.Kubernetes 基本网络模型 本文来介绍一下 Kubernetes 对网络模型的一些想法.大家知道 Kubernetes 对于网络具体实现方案,没有什 ...

  8. Kubernetes网络之Flannel工作原理

    目录 1.Docker网络模式 1.1 bridge网络的构建过程 1.2 外部访问 2.Kubernetes网络模式 2.1 同一个Pod中容器之间的通信 2.2 不同Pod中容器之间的通信 2.3 ...

  9. 超长干货丨Kubernetes网络快速入门完全指南

    Kubernetes网络一直是一个非常复杂的主题.本文将介绍Kubernetes实际如何创建网络以及如何为Kubernetes集群设置网络. 本文不包括如何设置Kubernetes集群.这篇文章中的所 ...

  10. DevOps专题|玩转Kubernetes网络

    Kubernetes无疑是当前最火热的容器编排工具,网络是kubernetes中非常重要的一环, 本文主要介绍一些相应的网络原理及术语,以及kubernetes中的网络方案和对比. Kubernete ...

随机推荐

  1. WEB安全指南

    说明:本文是Mozilla Web应用部署文档,对运维或者后端开发团队的部署行为进行指导.该部署安全规范内容充实,对于部署有很大意义.同时也涉及到了许多web前端应用安全的基本知识,如CSP, TOK ...

  2. 【数据结构与算法Python版学习笔记】算法分析

    什么是算法分析 算法是问题解决的通用的分步的指令的聚合 算法分析主要就是从计算资源的消耗的角度来评判和比较算法. 计算资源指标 存储空间或内存 执行时间 影响算法运行时间的其他因素 分为最好.最差和平 ...

  3. Netty学习笔记(1)NIO三大组件

    1. Channel channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前 ...

  4. 「笔记」$Min\_25$筛

    总之我也不知道这个奇怪的名字是怎么来的. \(Min\_25\)筛用来计算一类积性函数前缀和. 如果一个积性函数\(F(x)\)在质数单点是一个可以快速计算的关于此质数的多项式. 那么可以用\(Min ...

  5. Linux入门必须养成的七大习惯

    对于很多Linux初学者来说,在刚开始使用linux系统时会感到很多的不适.这里为大家整理了自己以前linux入门时别人告诉我的七个习惯.我相信如果你运用了这七个习惯,在你使用Linux时你会感觉更安 ...

  6. C++ string类型小结

    目录 构造函数 string.append() string.assign() string.at() string.back() string.begin() string.capasity() s ...

  7. hdu 5166 Missing number(。。。)

    题意: 有一个排列,但少了两个数.给你少了这两个数的排列.找出是哪两个数. 思路: 看代码,,, 代码: int a[1005]; int main(){ int T; cin>>T; w ...

  8. JAVA笔记7__接口应用/Object类/简单工厂模式/静态代理模式/适配器模式

    /** * 接口应用 */ public class Main { public static void main(String[] args) { Person p = new Person(&qu ...

  9. 第08课 OpenGL 混合

    混合: 在这一课里,我们在纹理的基础上加上了混合,它看起具有透明的效果,当然解释它不是那么容易,当希望你喜欢它. 简单的透明OpenGL中的绝大多数特效都与某些类型的(色彩)混合有关.混色的定义为,将 ...

  10. Typora 快捷方式

    1.标题编写 方法一:几个#号 代表几级标题  (共6级) 方法二:ctrl +1 .2.3.4.5.6 2.如何编写子标题 第一种:无序子标题(无序列表) *号  +  空格书写标题文本   (输入 ...