k8s容器互联flannel vxlan通信原理

目录
  • k8s容器互联-flannel vxlan 原理篇
  • vxlan 模式通信原理
    • flannel的xvlan模式是如何办到的呢?
    • 集群网络模型
    • 查看worker2网络设备类型
    • 查看集群pod 信息
    • worker1节点的接收过程
  • 再看flannel xvlan模式

k8s容器互联-flannel vxlan 原理篇

容器系列文章

容器系列视频

vxlan 模式通信原理

flannel 在为不同主机的pod分配ip地址的时候,会在一个大的网段范围内分配ip地址,而同一台主机上的pod,则是在大的网段下延伸出一个较小的子网,同一台主机上的ip地址则是在较小的子网范围内去进行分配。

例如k8s启动flannel插件时,会通过flannel的配置文件指定大的网段的范围和flannel启动方式,我们选用的是vxlan模式

  net-conf.json: |
    {
      "Network": "10.10.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

这样整个集群的ip地址就是在10.10.0.0/16 网段去进行分配。 而各个主机上的ip地址范围 则是在例如10.10.1.0/24 ,10.10.2.0/24这样的网段去进行分配。

跨主机通信的目的,就是让主机A上的网段10.10.1.0/24 内分配的ip能够ping通主机B上的 10.10.2.0/24 网段分配的ip。

flannel的xvlan模式是如何办到的呢?

为了更好的理解vxlan的模式,我搭建了一个真实的3节点集群环境,然后实际的去主机上分析vxlan工作模式

集群网络模型

集群有3个节点:

master 集群的控制节点,ip地址是 192.168.2.17;

worker1 工作节点 ip地址是 192.168.2.16;

worker2 工作节点 ip 地址是 192.168.2.15 ;

由于工作节点才承担具体的pod承载认为,所以我们只看工作节点即可。

这里先放一张集群网络模型的图,接下来的分析都将会根据这个图一步步分析网络包时如何从worker2 的pod到达到worker1的pod的。

查看worker2网络设备类型

查看网络接口有哪些

parallels@worker2:~/Desktop$ ifconfig
cni0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.10.2.1  netmask 255.255.255.0  broadcast 10.10.2.255
       ...
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:41:ce:a9:49  txqueuelen 0  (Ethernet)
        ...
enp0s5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.2.15  netmask 255.255.255.0  broadcast 192.168.2.255
        ...
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.10.2.0  netmask 255.255.255.255  broadcast 0.0.0.0
        inet6 fe80::647c:5aff:fe24:c42e  prefixlen 64  scopeid 0x20<link>
        ether 66:7c:5a:24:c4:2e  txqueuelen 0  (Ethernet)
        ...
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        ...
veth9c0a9a53: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet6 fe80::fc7d:fdff:fe6f:a32e  prefixlen 64  scopeid 0x20<link>
        ether fe:7d:fd:6f:a3:2e  txqueuelen 0  (Ethernet)
        ...
vethd6f08999: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet6 fe80::68b2:41ff:fee2:9074  prefixlen 64  scopeid 0x20<link>
        ether 6a:b2:41:e2:90:74  txqueuelen 0  (Ethernet)
        ...

k8s 在主上创建一个cni0和flannel.1的虚拟网络设备,cni0是网桥类型的设备,flannel.1是vxlan类型的设备 (准确的说是vtep设备,在vxlan模式下,我们将这个封包解包的设备叫做vtep设备VXLAN Tunnel Endpoints)。

记下这里worker2节点上cni0的ip地址10.10.2.1 ,flannel.1的ip地址 10.10.2.0

parallels@worker2:~/Desktop$ ethtool -i flannel.1
driver: vxlan
...
parallels@worker2:~/Desktop$ ethtool -i cni0
driver: bridge
...

先看下网桥的作用(vxlan设备作用稍后进行分析) 网桥拥有交换机的作用。

我们知道,在同一台主机上,不同pod的网络命名空间是不同的,在linux上有一种veth的虚拟网络设备,它是成对出现的,所以也被叫做veth pair,可以连接不同命名空间。

从veth一端发出去的包能够被另外一端接收到,通过veth pair能够连通两个命名空间。

但是如果一台主机上,有许多pod,要想让那么多pod都连通的话,就得两两建立veth pair设备,这样的排列组合数量随着pod的增加会变得相当大。

而网桥的出现能够让这个网络模型变成 veth pair的一端连通着pod的网络命名空间,一端是连接在网桥上,让网桥充当交换机的作用,同一台主机的不同pod的数据包都经过网桥去进行转发。

交换机是工作在网络的第二层,所以只会将数据包解析到数据帧的格式,只认mac地址,如果是广播帧,转发给所有接入网桥的设备,如果是单播帧,那么就会发往特定的端口。

但是网桥作为交换机与之不同的一点是,网桥具有将转发数据包到主机的三层网络协议栈的功能,如果发往网桥的数据包的mac地址就是网桥自身mac地址的话,那么网桥就会认为数据包是要发往数据的数据包,然后去对其进行转发。

查看集群pod 信息

再结合 pod 看看pod内部的网络数据包是如何输出到网桥上的。我在集群内部启动了一个3副本的busybox镜像的 pod。

来看看pod分布的工作节点以及其ip地址

(base) ➜  ~ kubectl get pods -o wide
NAME                       READY   STATUS    RESTARTS        AGE     IP          NODE      NOMINATED NODE   READINESS GATES
busybox-8647b8666c-74nmg   1/1     Running   0               3h19m   10.10.1.3   worker1   <none>           <none>
busybox-8647b8666c-bwgh9   1/1     Running   1 (4h29m ago)   12d     10.10.2.4   worker2   <none>           <none>
busybox-8647b8666c-qwzrh   1/1     Running   1 (4h29m ago)   4h57m   10.10.2.5   worker2   <none>           <none>

我们的目的就是让worker2节点上ip为10.10.2.4 的pod能ping通 worker1节点上ip为10.10.1.3的pod

进入worker2节点上 ip为10.10.2.4 的pod内部看看路由信息。

/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.10.2.1       0.0.0.0         UG    0      0        0 eth0
10.10.0.0       10.10.2.1       255.255.0.0     UG    0      0        0 eth0
10.10.2.0       0.0.0.0         255.255.255.0   U     0      0        0 eth0

还记得刚刚说的worker2节点上的cni0网桥的ip是10.10.2.1 吗?

通过路由信息,可以看到10.10.2.1正是pod的网关,所以如果在pod内部 ping worker1上的pod ip 10.10.1.3 ,就会匹配上第二条路由信息。

那么worker2 的pod发出去的数据包就指定到达10.10.2.1这个ip上,所以mac地址就是10.10.2.1对应的mac地址,即cni0的mac地址。

正是由于这个原因,触发了cni0网桥的转发到主机上的三层网络协议栈的这个机制,而到达worker2主机后,通过ip要看具体转发到哪张网卡是看主机的路由信息的,所以,先看下worker2的路由信息。

parallels@worker2:~/Desktop$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    100    0        0 enp0s5
10.10.0.0       10.10.0.0       255.255.255.0   UG    0      0        0 flannel.1
10.10.1.0       10.10.1.0       255.255.255.0   UG    0      0        0 flannel.1
10.10.2.0       0.0.0.0         255.255.255.0   U     0      0        0 cni0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.2.0     0.0.0.0         255.255.255.0   U     100    0        0 enp0s5
192.168.2.1     0.0.0.0         255.255.255.255 UH    100    0        0 enp0s5

我们数据包目的地是worker1上的pod ,ip是10.10.1.3 ,通过路由信息,看到属于10.10.1.0/24这个网段的数据包都会经过 flannel.1发出,网关是10.10.1.0 ,这个ip也就是对端vtep设备的ip地址

数据包就这样从worker2的pod来到了worker2节点上的flannel.1 这个网卡上。

flannel.1会对数据包进行一些加工,加工时需要加上对端vtep的mac地址,由于flannel.1 通过路由信息已经知道对端vtep的ip地址,通过查询本地arp缓存表,得到目的vtep的mac地址。

parallels@worker2:~/Desktop$ ip neigh show dev flannel.1
10.10.1.0 lladdr 72:5a:79:44:22:7b PERMANENT
10.10.0.0 lladdr 62:03:91:cb:cc:36 PERMANENT

k8s是通过flanneld(在flannel插件工作模式下,每个节点上都有一个flanneld的后台进程,对节点上的一些网络信息进行配置)在worker2的arp缓存中写入了mac地址,且永不过期。

同时还会加上vxlan头部信息,在头部信息中表明了这是一个vxlan帧,这样worker1节点收到数据包时,知道这是一个vxlan帧后,会将这个包去进行解包操作,同时头部信息中也包含一个vni的信息,只有vni相同的网络设备才有解包的资格。

这样封装以后,还需要将这个包发往对端vtep所在的主机节点,怎么发送呢?

worker2的flannel.1用udp格式的数据包再包裹一下vxlan帧,封装成udp时,需要知道对端的ip地址。

这里封装成udp包的时候,是如何知道目的节点主机的ip的呢。 flannel.1 通过查询本机的一个叫做fdb的转发数据库获取目的节点主机的ip。

parallels@worker2:~/Desktop$ bridge fdb show flannel.1 | grep 72:5a:79:44:22:7b
72:5a:79:44:22:7b dev flannel.1 dst 192.168.2.16 self permanent

注意这些配置信息是在woker1节点启动后,就会在worker2节点自动加上的,而完成配置信息的动作是由各个主机上的flanneld进程完成的

知道了udp的目的ip后,就是一个正常数据包在宿主机上的封包,发送流程了。

这样,数据包就到达了worker1。

worker1节点的接收过程

worker1 的内核协议栈收到数据包以后,发现有vxlan header以及vni标记是1,就将这个vxlan包发给本机的vni标记也为1的flannel.1设备。

然后flannel.1进行解包,取出数据包的目的ip是10.10.1.3,然后查看worer1本机路由信息。

arallels@worker1:~/Desktop$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    100    0        0 enp0s5
10.10.0.0       10.10.0.0       255.255.255.0   UG    0      0        0 flannel.1
10.10.1.0       0.0.0.0         255.255.255.0   U     0      0        0 cni0
10.10.2.0       10.10.2.0       255.255.255.0   UG    0      0        0 flannel.1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.2.0     0.0.0.0         255.255.255.0   U     100    0        0 enp0s5
192.168.2.1     0.0.0.0         255.255.255.255 UH    100    0        0 enp0s5
parallels@worker1:~/Desktop$

发现发往10.10.1.0/24这个网段的包要经过cni0网桥,所以flannel.1将解包后的数据包转发给了cni0网桥。

接下来就是cni0网桥在一个10.10.1.0/24 子网内发送目的ip为 10.10.1.3 的流程了。

cni0网桥先通过10.10.1.3查找本地mac地址,如果有则发往mac地址对应的端口,端口连通的另一端是veth设备也是worker1上的pod的网卡。

如果没有10.10.1.3的mac地址,则先通过arp协议,在一个局域网内获得arp响应包后,再发送数据包到对应端口连通的pod veth网卡上。

至此,worker1成功收到了worker2发送的数据包了。

再看flannel xvlan模式

本质上是通过flannel.1这个vxlan设备对主机发出去的数据包进行udp封装,然后发往经过物理网卡发往对端。

再进一步思考下,udp是可以丢包的,那么经过udp去封装数据包 的网络传输是可靠的吗?

答案是不需要可靠,整个flannel的转发模型,可以看出flannel完成的是网络模型的第三层次ip层的互通, 这里udp封装的ip包实际上是充当了第二层链路层的工作了,传输的可靠性是靠传输层实现的,传输层的靠是在对应pod所在命名空间中的tcp 的重传保证的。

以上就是k8s容器互联flannel vxlan通信原理的详细内容,更多关于k8s容器互联flannel vxlan的资料请关注我们其它相关文章!

(0)

相关推荐

  • k8s Ingress实现流量路由规则控制的定义格式类型

    目录 前言 什么是 Ingress Ingress 的定义格式 Ingress 的类型有哪几种? 1. Simple fanout 2. Name-based virtual hosting 3. Path-based routing 该如何实现更新 Ingress Ingress Controller Ingress Class 总结 前言 在 Kubernetes 中,Ingress 是一个非常重要的概念.它可以将外部流量路由到 Kubernetes 集群内的不同服务. Ingress 可以

  • k8s Service 实现服务发现和负载均衡

    目录 前言 Service 介绍 Service 的四种类型及使用方式 Service 的定义和使用 通过命令创建服务 查看创建的服务情况 不指定 Selectors 的服务 Headless 服务 Service 工作原理及原理图 Ingress 讲解 集群外部如何访问服务 总结 前言 本文将介绍 Kubernetes 的资源对象 Service,内容包括 Service 介绍.Service 的四种类型及使用方式.不指定 Selectors 的服务.Headless 服务.Service 工

  • k8s Job 执行一次性以及批处理任务使用场景案例

    目录 前言 Job 是什么 Job 的一些使用场景 Job 控制器 Job Spec 格式定义 Job pod 自动清理 暂停和重启 Job 案例讲解 使用 Job 的注意事项 总结 前言 Job 类型是 Kubernetes 资源对象之一,用于执行一次性任务或批处理作业. 本文将介绍 Kubernetes 的 Job 与相关概念,帮助理解和使用 Kubernetes 中的 Job. Job 是什么 Job 是一种 Kubernetes 资源对象,用于执行一次性任务或批处理作业. Job 可以控

  • 带你学会k8s 更高级的对象Deployment

    目录 Deployment 引入 Deployment & RC 对比 Deployment 创建 Deployment 滚动升级 Deployment 回滚 Deployment 扩容 总结 Deployment 引入 前面我们学习了 RC 和 RS 两种资源对象,它们的功能基本上是差不多的,唯一的区别就是 RS 支持集合的 selector. 另外,前面我们也了解了如何用 RC/RS 资源对象来控制 Pod 副本的数量,如何实现了滚动升级 Pod 的功能.现在回过头来看,似乎这些操作都比较完

  • kubeadm init快速搭建k8s源码解析

    目录 引言 下面的代码就都是为 init 命令绑定和添加一些标志 以方法 AddInitConfigFlags 为例 kubeadm init --help 指令 引言 我们都知道,从头搭建k8s集群是个非常棘手的事情,所以在更多的情况下大家通常会选择通过 kubeadm 工具来搭建 k8s 集群.当我们执行 kubeadm init 命令后就可以进行 k8s 的快速搭建 根据k8s的官方文档以及源码,我们可以对整个 init 命令的工作原理做个了解,官方文档地址:kubernetes.io/z

  • Kubernetes(K8S)容器集群管理环境完整部署详细教程-上篇

    Kubernetes(通常称为"K8S")是Google开源的容器集群管理系统.其设计目标是在主机集群之间提供一个能够自动化部署.可拓展.应用容器可运营的平台.Kubernetes通常结合docker容器工具工作,并且整合多个运行着docker容器的主机集群,Kubernetes不仅仅支持Docker,还支持Rocket,这是另一种容器技术.Kubernetes是一个用于容器集群的自动化部署.扩容以及运维的开源平台. 本文系列: Kubernetes(K8S)容器集群管理环境完整部署详

  • Docker学习笔记之Weave实现跨主机容器互联

    Docker的原生网络支持非常有限,且没有跨主机的集群网络方案.目前实现Docker网络的开源方案有Weave.Kubernetes.Flannel.Pipework以及SocketPlane等,其中Weave被评价为目前最靠谱的,那么这里就对Weave的基本原理及使用方法做个总结. 简介 Weave是由Zett.io公司开发的,它能够创建一个虚拟网络,用于连接部署在多台主机上的Docker容器,这样容器就像被接入了同一个网络交换机,那些使用网络的应用程序不必去配置端口映射和链接等信息.外部设备

  • Docker link实现容器互联的方式

    目录 1.1.容器间通过IP进行网络访问 1.2.容器间通过容器名或容器id进行网络访问 1.1.容器间通过IP进行网络访问 新建两个容器tomcat01和tomcat02 docker run -d -P --name tomcat01 tomcat docker run -d -P --name tomcat02 tomcat 使用 ifconfig 命令查看toncat01的网卡信息: 可以看到,tomcat01的IP地址为 172.17.0.2 再查看toncat02的网卡信息: 可以看

  • Kubernetes(K8S)容器集群管理环境完整部署详细教程-中篇

    本文系列: Kubernetes(K8S)容器集群管理环境完整部署详细教程-上篇 Kubernetes(K8S)容器集群管理环境完整部署详细教程-中篇 Kubernetes(K8S)容器集群管理环境完整部署详细教程-下篇 接着Kubernetes(K8S)容器集群管理环境完整部署详细教程-上篇继续往下部署: 八.部署master节点 master节点的kube-apiserver.kube-scheduler 和 kube-controller-manager 均以多实例模式运行:kube-sc

  • HTTPS 通信原理及详细介绍

    HTTPS 通信原理 Https是基于安全目的的Http通道,其安全基础由SSL层来保证.最初由netscape公司研发,主要提供了通讯双方的身份认证和加密通信方法.现在广泛应用于互联网上安全敏感通讯. 我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取.所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议. HTTPS简介 HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块.服务端和客户端的信息传输都会通过T

  • Kubernetes(K8S)容器集群管理环境完整部署详细教程-下篇

    本文系列: Kubernetes(K8S)容器集群管理环境完整部署详细教程-上篇 Kubernetes(K8S)容器集群管理环境完整部署详细教程-中篇 Kubernetes(K8S)容器集群管理环境完整部署详细教程-下篇 在前一篇文章中详细介绍了Kubernetes(K8S)容器集群管理环境完整部署详细教程-中篇,这里继续记录下Kubernetes集群插件等部署过程: 十一.Kubernetes集群插件 插件是Kubernetes集群的附件组件,丰富和完善了集群的功能,这里分别介绍的插件有cor

  • docker --link容器互联的实现

    目录 容器互联 实验:tomcat连接mysql 创建启动mysql容器 创建启动tomcat容器--link连接mysql容器 –link可以通过容器名互相通信,容器间共享环境变量. –link主要用来解决两个容器通过ip地址连接时容器ip地址会变的问题. 容器互联 先创建启动mysql容器 docker run -dti --name db --restart=always -e MYSQL_ROOT_PASSWORD=redhat -e MYSQL_DATABASE=blog  mysql

  • 详解Docker 端口映射与容器互联

    1.端口映射实现访问容器 1.从外部访问容器应用 在启动容器的时候,如果不指定对应的参数,在容器外部是无法通过网络来访问容器内部的网络应用和服务的. 当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-p或-P参数来指定端口映射.当使用-P(大写P)标记时,Docker会随机映射一个端口到内部容器开放的网络端口(端口范围在Linux系统使用的端口之外,一般都过万): [root@docker ~]# docker run -d --name nginx_1 -P nginx:latest

  • Java等待唤醒机制线程通信原理解析

    这篇文章主要介绍了Java等待唤醒机制线程通信原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同.比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题. 为什么要处理线程间通信: 多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个

  • Python基础之Socket通信原理

    上图是socket网络编程的流程图 至于数据在网络中是怎么走的,咱先不说,那个太底层了,咱今天见就说如何将数据从咱的屏幕上放到网络流中去. 这可不是键盘敲敲,回车一按的事情,在这背后,那也是百转千回. 打开一个网络接口:套接字 Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯. Python 中,我们用 socket()函数来创建套接字,语法格式如下: import socket # 居然

随机推荐