一. 实践说明

首先我们先创建一组资源,包括一个deployment和一个service

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
name: nginx
spec:
selector:
matchLabels:
name: nginx1
replicas: 1
template:
metadata:
labels:
name: nginx1
spec:
nodeName: meizu
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
name: nginx1
spec:
ports:
- port: 4432
targetPort: 80
selector:
name: nginx1

可以看到,我们在指定的node上面创建了一个nginx deployment,并且创建一个服务指向这个pod.然后我们再在其他节点上启动一个pod,在该pod中访问这个service.

src pod  ->  service   ->  backend  pod

172.30.83.9  ->  10.254.40.119:4432  ->  172.30.20.2:80

下面的所有操作都是nginx 服务所在的pod所运行的node上执行的

二. 物理网卡

1.监听nginx pod/src pod 地址

sudo tcpdump -i  enp4s0 ‘dst 172.30.20.9’

sudo tcpdump -i  enp4s0 'src 172.30.83.9'

都没有输出

2. 监听service 地址

sudo tcpdump  -i  enp4s0 ‘dst 10.254.40.119’

没有输出

3.src pod所在的node的物理地址是10.167.226.38,我们现在监听从这个节点发出的所有的到本地8472端口的udp报文,注意8472端口是flannel所监听的端口

sudo tcpdump  -i enp4s0 'src 10.167.226.38 and port 8472 and udp'
看到如下输出:

::22.220286 IP xiaomi. > meizu.otv: OTV, flags [I] (0x08), overlay , instance
IP 172.30.83.0. > 172.30.20.2.http: Flags [S], seq , win , options [mss ,sackOK,TS val ecr ,nop,wscale ], length
::22.221179 IP xiaomi. > meizu.otv: OTV, flags [I] (0x08), overlay , instance
IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::22.221383 IP xiaomi. > meizu.otv: OTV, flags [I] (0x08), overlay , instance
IP 172.30.83.0. > 172.30.20.2.http: Flags [P.], seq :, ack , win , options [nop,nop,TS val ecr ], length : HTTP: GET / HTTP/1.1
::22.221933 IP xiaomi. > meizu.otv: OTV, flags [I] (0x08), overlay , instance
IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::22.221949 IP xiaomi. > meizu.otv: OTV, flags [I] (0x08), overlay , instance
IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::22.222347 IP xiaomi. > meizu.otv: OTV, flags [I] (0x08), overlay , instance
IP 172.30.83.0. > 172.30.20.2.http: Flags [F.], seq , ack , win , options [nop,nop,TS val ecr ], length

我们可以看到在物理网卡上,报文的源地址是物理机的ip,目标地址是目标pod所在的物理机的ip。

报文体中定义的源地址是172.30.83.0,这是源pod所在主机的flannel.1网卡的地址,目标地址是172.30.20.2,这个地址是nginx pod所在的地址

4. 再看看tcp协议的输出

sudo tcpdump  -i enp4s0 'src 10.167.226.38 and port 8472 and tcp'

没有输出,由此可见,flannel之间的通信是通过udp完成的,而不是tcp。

总结:在物理网卡上,所有的通信都是通过源地址和目标地址所在的主机的物理地址进行通信的,这些报文封装了从管理源pod的docker网卡地址到目的nginx pod地址的flannel报文

三. Flannel 网卡

执行下面的指令,其中172.30.83.0是源pod所在的node的flannel网卡地址

[wlh@meizu ~]$ sudo tcpdump  -i flannel. 'host 172.30.83.0 and tcp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on flannel., link-type EN10MB (Ethernet), capture size bytes
::43.362239 IP 172.30.83.0. > 172.30.20.2.http: Flags [S], seq , win , options [mss ,sackOK,TS val ecr ,nop,wscale ], length
::43.363702 IP 172.30.20.2.http > 172.30.83.0.: Flags [S.], seq , ack , win , options [mss ,sackOK,TS val ecr ,nop,wscale ], length
::43.364106 IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::43.364180 IP 172.30.83.0. > 172.30.20.2.http: Flags [P.], seq :, ack , win , options [nop,nop,TS val ecr ], length : HTTP: GET / HTTP/1.1
::43.364218 IP 172.30.20.2.http > 172.30.83.0.: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::43.364482 IP 172.30.20.2.http > 172.30.83.0.: Flags [P.], seq :, ack , win , options [nop,nop,TS val ecr ], length : HTTP: HTTP/1.1 OK
::43.364608 IP 172.30.20.2.http > 172.30.83.0.: Flags [FP.], seq :, ack , win , options [nop,nop,TS val ecr ], length : HTTP
::43.364868 IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::43.364888 IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::43.365226 IP 172.30.83.0. > 172.30.20.2.http: Flags [F.], seq , ack , win , options [nop,nop,TS val ecr ], length
::43.365271 IP 172.30.20.2.http > 172.30.83.0.: Flags [.], ack , win , options [nop,nop,TS val ecr ], length

可以看到物理层的报文被解封装后提交给了flannel.1网卡,它处理的报文就是从源pod所在的node的flannel.1网卡地址到目标pod的地址的通信

四. Docker0网卡

其中172.30.83.0是源pod所在的主机的flannel.1网卡的地址

 [wlh@meizu ~]$ sudo tcpdump  -i docker0 'host 172.30.83.0 and tcp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size bytes
::00.681066 IP 172.30.83.0. > 172.30.20.2.http: Flags [S], seq , win , options [mss ,sackOK,TS val ecr ,nop,wscale ], length
::00.681110 IP 172.30.20.2.http > 172.30.83.0.: Flags [S.], seq , ack , win , options [mss ,sackOK,TS val ecr ,nop,wscale ], length
::00.681548 IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::00.681560 IP 172.30.83.0. > 172.30.20.2.http: Flags [P.], seq :, ack , win , options [nop,nop,TS val ecr ], length : HTTP: GET / HTTP/1.1
::00.681608 IP 172.30.20.2.http > 172.30.83.0.: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::00.681773 IP 172.30.20.2.http > 172.30.83.0.: Flags [P.], seq :, ack , win , options [nop,nop,TS val ecr ], length : HTTP: HTTP/1.1 OK
::00.681853 IP 172.30.20.2.http > 172.30.83.0.: Flags [FP.], seq :, ack , win , options [nop,nop,TS val ecr ], length : HTTP
::00.682018 IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::00.682031 IP 172.30.83.0. > 172.30.20.2.http: Flags [.], ack , win , options [nop,nop,TS val ecr ], length
::00.682504 IP 172.30.83.0. > 172.30.20.2.http: Flags [F.], seq , ack , win , options [nop,nop,TS val ecr ], length
::00.682523 IP 172.30.20.2.http > 172.30.83.0.: Flags [.], ack , win , options [nop,nop,TS val ecr ], length

我们可以看到这里的通信是以tcp协议进行并且所有的通信和flannel类似,也是在源主机的flannel网卡地址和目标pod地址之间进行的。

五 容器网卡

容器网卡的输出和前面的比较类似这里不再赘述。

六总结

下面总结一下整个过程

  1. 首先容器内的进程发送一个访问service的请求,这个被交给容器内网卡进行处理,容器内网卡将请求发送给veth pair的另一端。此时请求是从src pod ip-> service ip。
  2. 然后根据NAT表的设置, 目的地址被转化为backend pod 的ip,这个请求再传送给docker0网卡。此时请求是 src pod ip -> backend pod ip
  3. docker0 网卡收到请求后直接将请求发出去,请求根据路由表(route -n)被传送给flannel.1网卡。此时请求是flanne.1 ip -> backend pod ip
  4. flannel.1网卡将请求发送给flanneld进程进行处理,该进程读取etcd的配置,给请求封装上一个udp协议头,然后发出去, 该报文是 source node ip -> dst node ip
  5. 本地网卡收到这个请求后将报文从物理网络上发出去,到达远程主机。

flannel.1

k8s 网络模型解析之实践的更多相关文章

  1. k8s 网络模型解析之原理

    今天研究了一下k8s的网络模型,该解析基于flannel vxlan+ kubeproxy iptables 模式. 一.Docker 首先分析一下Docker层面的网络模型,我们知道容器是基于内核的 ...

  2. k8s 网络模型

    一.前言 k8s对Pods之间如何进行组网通信提出了要求,k8s对集群的网络有以下要求: 所有的Pods之间可以在不使用NAT网络地址转换的情况下相互通信 所有的Nodes之间可以在不使用NAT网络地 ...

  3. Tengine HTTPS原理解析、实践与调试【转】

    本文邀请阿里云CDN HTTPS技术专家金九,分享Tengine的一些HTTPS实践经验.内容主要有四个方面:HTTPS趋势.HTTPS基础.HTTPS实践.HTTPS调试. 一.HTTPS趋势 这一 ...

  4. k8s loadbalancer与ingress实践

    k8s可以通过三种方式将集群内服务暴露到外网,分别是NodePort.LoadBalancer.Ingress,其中NodePort作为基础通信形式我们在<k8s网络模型与集群通信>中进行 ...

  5. [转帖]我花了10个小时,写出了这篇K8S架构解析

    我花了10个小时,写出了这篇K8S架构解析 https://www.toutiao.com/i6759071724785893891/   每个微服务通过 Docker 进行发布,随着业务的发展,系统 ...

  6. k8s网络模型与集群通信

    在k8s中,我们的应用会以pod的形式被调度到各个node节点上,在设计集群如何处理容器之间的网络时是一个不小的挑战,今天我们会从pod(应用)通信来展开关于k8s网络的讨论. 小作文包含如下内容: ...

  7. 从零开始入门 K8s | etcd 性能优化实践

    作者 | 陈星宇(宇慕)  阿里云基础技术中台技术专家 本文整理自<CNCF x Alibaba 云原生技术公开课>第 17 讲. 导读:etcd 是容器云平台用于存储关键元信息的组件.阿 ...

  8. ELK:收集k8s容器日志最佳实践

    简介 关于日志收集这个主题,这已经是第三篇了,为什么一再研究这个课题,因为这个课题实在太重要,而当今优秀的开源解决方案还不是很明朗: 就docker微服务化而言,研发有需求标准输出,也有需求文件输出, ...

  9. 一文看懂 K8s 日志系统设计和实践

    上一篇中我们介绍了为什么需要一个日志系统.为什么云原生下的日志系统如此重要以及云原生下日志系统的建设难点,相信DevOps.SRE.运维等同学看了是深有体会的.本篇文章单刀直入,会直接跟大家分享一下如 ...

随机推荐

  1. php 把数字拆分成数组

    用str_split $a = 1234567890; //拆分数字为数组 var_dump( str_split($a, 1) ); 打印结果 : Array ( [0] =2 [1] =5 )

  2. Java实现复制文件或者文件夹

    拷贝一个文件的算法比较简单,当然,可以对它进行优化,比如使用缓冲流,提高读写数据的效率等. 话不多说直接上代码 import java.io.*; /** * 实现文件的拷贝 */ public cl ...

  3. python3 scrapy爬虫项目的诞生

    前提安装好scrapy模块最好 requests和bs4模块都安装好 可以概括为五个步骤 步骤一:新建一个项目 无论你用windows也好,linux也罢,在cmd或者终端 切换到目标文件夹,然后输入 ...

  4. 011_linuxC++之_继承的引入

    (一)面向对象程序设计中最重要的一个概念是继承.继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易.这样做,也达到了重用代码功能和提高执行时间的效果. (二)引入继承程序 # ...

  5. .net实现浏览器大文件分片上传

    以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传  ...

  6. Windows:获取本地时间

    造冰箱的大熊猫@cnblogs 2019/6/4 #include <windows.h> int func() { SYSTEMTIME systime; GetLocalTime ( ...

  7. dup2函数

    将当前系统中的进程信息打印到文件中 命令行:ps aux > out 将ps得到的信息重定向到out文件中 使用dup2文件在程序中完成. int dup2(int oldfd,int newf ...

  8. java将PDF的前几页拆出来组成新pdf

    /** * 截取pdfFile的第from页至第end页,组成一个新的文件名 * @param pdfFile 需要分割的PDF * @param savepath 新PDF * @param fro ...

  9. RHEL防火墙命令

    firewall-cmd --state 查看防火墙状态 firewall-cmd --reload #重启firewall systemctl stop firewalld.service #停止f ...

  10. Navicat 12 for MySQL最新版激活(注册机)(转)(亲测有效)

    Navicat 12 for MySQL最新版激活(注册机)(转)(亲测有效) 一.总结 一句话总结: 1.卸载自己机器上面的Navicat,安装下载的包里面的Navicat安装包,不然可能不行 2. ...