k8s 网络模型解析

今天研究了一下k8s的网络模型,该解析基于flannel vxlan+ kubeproxy iptables 模式。

一.Docker

首先分析一下Docker层面的网络模型,我们知道容器是基于内核的namespace机制去实现资源的隔离的。network是众多namespace中的一个,那么如何保证一个节点上容器之间的通信呢?Docker的做法是通过虚拟网桥来桥接虚拟网卡。下面具体解释一下。

首先每一个容器在默认情况下都是在自己的network namespace里面的,也就是说默认情况下它只有一个自己独立的localhost网络(或者是什么网络设备也没有?TBD),无法与外部进行通信。为了解决这个问题,Docker创建了一对veth pair, 这个veth pair总是承兑出现,可以理解为一对端口,所有从一头进去的数据都会从另一头出来。然后docker 会把这对veth pair的一头加入到容器的namespace中,另一头桥接到一个虚拟网桥上, 这个虚拟网桥实际上就是宿主机上的docker0网卡,我们可以通过以下指令来观察:

[[email protected] storage]$ brctl show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.02422551422b    no        veth43dc241
                                       veth551eae5
                                       veth844b02c
                                              vethd06364a
                                              vethe95e44c

上图可以看到docker0上面桥接的各个容器的veth设备,这样容器内的通信就可以沿着vethA-1 -> vethA-2 -> docker0 -> vethB-2 -> vethB-1流动了

2. Flannel

Docker实现了同一节点上容器之间的通信,那么k8s作为一个容器编排平台,如何实现不同节点上容器的通信呢?这需要第三方插件的支持,目前有多种overlay network解决方案,这里介绍其中比较简单的一种, flannel。flannel目前支持三种工作模式:vxlan, udp, host-gw,其中udp和vxlan比较像,udp是flannel程序自己在用户态下将报文封装,而vxlan是内核对报文进行处理,因此udp会比较慢。所以udp不推荐在生产环境下使用,只是用于debug。而host-gw模式需要所有节点与其他任一节点间都有直接路由(具体可以查阅相关文章), 这里我们使用vxlan作为工作模式进行讲解。

在工作的时候,flannel会从k8s的etcd存储中同步数据,包括使用的工作模式和集群中其它节点的子网。例如,在我的机器上,其etcd中存储的数据为:

 1 [[email protected] xuexi]$ etcdctl ls /kube-fujitsu/network
 2 /kube-fujitsu/network/config
 3 /kube-fujitsu/network/subnets
 4
 5 [[email protected] xuexi]$ etcdctl get /kube-fujitsu/network/config
 6 {"Network":"172.30.0.0/16","SubnetLen":24,"Backend":{"Type":"vxlan"}}
 7
 8 [[email protected] xuexi]$ etcdctl ls /kube-fujitsu/network/subnets
 9 /kube-fujitsu/network/subnets/172.30.20.0-24
10 /kube-fujitsu/network/subnets/172.30.44.0-24
11 /kube-fujitsu/network/subnets/172.30.83.0-24
12
13 [[email protected] xuexi]$ etcdctl get /kube-fujitsu/network/subnets/172.30.83.0-24
14 {"PublicIP":"10.167.226.38","BackendType":"vxlan","BackendData":{"VtepMAC":"b6:c7:0f:7f:66:a7"}}

这里第6行中的172.30.0.0/16表示的是整个集群的子网段, 而8/9/10三行分别代表了三个节点,每创建一个新的节点,都会从172.30.0.0/16中再分配一个子网给它。各个节点上的flannel进程读取etcd中的这些配置,然后修改自己节点上的docker进程的启动参数,在其中添加一个--bip=172.30.20.1/24,这样该节点上docker启动的所有容器都会在这个子网段里。通过这些设定,保证了集群中所有的容器之间ip地址是不会重复的。

解决了容器ip地址重复的问题后,下面就是实现容器跨节点通信了。在vxlan模式下,flannel会在节点上创建一个虚拟网卡叫flannel.1,它的MAC地址就是上面输出中的VtepMAC。同样的节点的路由表也会被修改,如下图所示:

1 [[email protected] storage]$ route
2 Kernel IP routing table
3 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
4 //....more
5 172.30.20.0     0.0.0.0         255.255.255.0   U     0      0        0 docker0
6 172.30.44.0     172.30.44.0     255.255.255.0   UG    0      0        0 flannel.1
7 172.30.83.0     172.30.83.0     255.255.255.0   UG    0      0        0 flannel.1

这里可以看到,目的地址为172.30.20.0/24的都会被发到docker0,这其实就是本主机上的容器。而其他节点上的容器则会被路由到flannel.1网卡上进行处理。flannel将flannel.1网卡上收到的数据进行处理,加上flannel规定好的报文头,然后从绑定的网卡中发出去。这个封装好的报文是udp协议,目标地址是容器所在的节点的物理地址,并且其默认端口是8472(udp模式的默认端口是8285)。也就是说vxlan模式的底层实现也是用udp报文发送的,只是vxlan模式中报文封装是在内核态中完成,而udp模式中报文封装是在用户态完成。目标容器所在的主机上,flannel会监听8472端口,去掉报文的flannel头,然后传送给docker0网卡,docker0网卡收到的就是普通的容器通信的报文,不会感知到底层的这些处理。

3. kube-proxy

我们知道,k8s中有service的概念,它拥有自己的ip地址。那么对service的访问是如何分发给后端的pod呢。这些工作是由kube-proxy完成的,它有三种工作模式,userspace(older), iptables(faster),ipvs(experimental)。其中userspace是早期的模式,它本质上是利用kube-proxy做一个代理,所有对service的访问都会转发给kube-proxy组件,然后由它再分发请求到pod。显然这种模式对于一个大规模集群来说是一个速度瓶颈。iptables模式是通修改iptable来实现请求分发的。ipvs模式不太了解。

下面以一个例子来具体说明iptables模式。首先创建下面列出的deployment和service:

 1 apiVersion: apps/v1
 2 kind: Deployment
 3 metadata:
 4   name: nginx
 5   labels:
 6     name: nginx
 7 spec:
 8   selector:
 9     matchLabels:
10       name: nginx1
11   replicas: 3
12   template:
13     metadata:
14       labels:
15         name: nginx1
16     spec:
17       nodeName: meizu
18       containers:
19       - name: nginx
20         image: nginx
21         ports:
22         - containerPort: 80
23 ---
24 apiVersion: v1
25 kind: Service
26 metadata:
27   name: nginx
28   labels:
29     name: nginx1
30 spec:
31   ports:
32   - port: 4432
33     targetPort: 80
34   selector:
35     name: nginx1[[email protected] xuexi]$ kubectl get pod -o wide|grep nginxnginx-cb648c7f5-c8h26       1/1     Running   0          24m    172.30.20.7   meizu    <none>           <none>nginx-cb648c7f5-pptl9       1/1     Running   0          40m    172.30.20.6   meizu    <none>           <none>nginx-cb648c7f5-zbsvz       1/1     Running   0          24m    172.30.20.8   meizu    <none>           <none>

[[email protected] xuexi]$ kubectl get svc -o widenginx        ClusterIP   10.254.40.119   <none>        4432/TCP   38m    name=nginx1

这里创建一个service,在4432端口向外提供简单的nginx service。观察到这些资源被创建以后,kube-proxy会在节点上的iptables的NAT表中添加以下规则:

[[email protected] storage]$ sudo iptables-save|grep nginx
-A KUBE-SERVICES ! -s 10.254.0.0/16 -d 10.254.40.119/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 4432 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.254.40.119/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 4432 -j KUBE-SVC-4N57TFCL4MD7ZTDA
[[email protected] storage]$ sudo iptables-save|grep 0x4000/0x4000
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
-A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT

输出的第一行是做一个标记,意思是所有发往10.254.40.118:4432(nginx服务)的请求(除了source ip 为10.254.0.0/16的报文)都会被打上一个标记,这个报文被打上这个标记后会在filter表中进行后续处理。在filter表中会对打上标记的报文进行MASQUERADE处理,实际上就是SNAT,将报文的source ip地址转化为本地主机物理网卡的地址,然后再发出去,否则如果直接用容器的ip地址的话,物理网络很显然是不会认识这个地址的。

原文地址:https://www.cnblogs.com/elnino/p/11369760.html

时间: 2024-11-08 11:13:51

k8s 网络模型解析的相关文章

VGG卷积神经网络模型解析

VGG卷积神经网络模型解析 一:VGG介绍与模型结构 VGG全称是Visual Geometry Group属于牛津大学科学工程系,其发布了一些列以VGG开头的卷积网络模型,可以应用在人脸识别.图像分类等方面,分别从VGG16-VGG19.VGG研究卷积网络深度的初衷是想搞清楚卷积网络深度是如何影响大规模图像分类与识别的精度和准确率的,最初是VGG-16号称非常深的卷积网络全称为(GG-Very-Deep-16 CNN),VGG在加深网络层数同时为了避免参数过多,在所有层都采用3x3的小卷积核,

k8s网络模型从 Calico切换为Canal踩的坑

问题描述 在跟着<每天五分钟玩转kubernets>这本书学习到K8S的网络章节时,实验中部署canal网络以演示Network Policy.因为最开始搭建k8s集群是部署的Calico网络(Calico也支持Network Policy,但是为了和教程保持一致,还是切换了),所以这里重新初始化了master,切换网络. 按照书上指示,操作了下面的步骤:1.首先在k8s集群所有节点执行kubeadm reset命令销毁当前集群2.在k8s的master上执行命令重新初始化了master: k

k8s实战读书笔记

一.概述 kubernetes中Service是真实应用的抽象,将用来代理Pod,对外提供固定IP作为访问入口,这样通过访问Service便能访问到相应的Pod,而对访问者来说只需知道Service的访问地址,而不需要感知Pod的变化: Service是通过Label来关联Pod的,在Service的定义中,设置 .spec.selector为name=redis-master,将关联上Pod: #kubectl get service redis-master NAME  CLUSTER_IP

《两地书》--Kubernetes(K8s)基础知识(docker容器技术)

大家都知道历史上有段佳话叫“司马相如和卓文君”.“皑如山上雪,皎若云间月”.卓文君这么美,却也抵不过多情女儿薄情郎. 司马相如因一首<子虚赋>得汉武帝赏识,飞黄腾达之后便要与卓文君“故来相决绝”,寄来给家乡留守的妻子一封<两地书>,上面只有一行数字:“一二三四五六七八九十百千万.”意义是:无亿,我已经无意于你啦. 卓文君看了这封信也不示弱,回了一首<怨郎诗>,司马相如看了发现虽然我是靠写诗吃饭的.要说写诗还是我媳妇厉害,于是亲自将卓文君迎回长安. 卓文君其实是个二婚.头

细致解析:kubernets整体架构

一.Kubernetes 是 Google 团队发起并维护的基于 Docker 的开源容器集群管理系统,它不仅支持常见的云平台,而且支持内部数据中心. 建于 Docker 之上的 Kubernetes 可以构建一个容器的调度服务,其目的是让用户透过 Kubernetes 集群来进行云端容器集群的管理,而无需用户进行复杂的设置工作.系统会自动选取合适的工作节点来执行具体的容器集群调度处理工作.其核心概念是 Container Pod.一个 Pod 由一组工作于同一物理工作节点的容器构成.这些组容器

十七,k8s集群指标API及自定义API

目录 资源指标: Metrics-Server 资源指标: Metric-Server介绍 Metric-Server部署 下载yaml文件 因为有墙, 所以提前下载image镜像, 当然也可以手动修改yaml相关文件 修改文件, 不然报错 创建Metric-Server 自定义资源指标: Prometheus k8s-prometheus-adapter 项目 Prometheus 在k8s集群中部署Prometheus github地址 需要部署的服务清单 安装部署所有服务及插件 部署kub

kubernetes 和 mesos + marathon的对比

Kubernetes概述 根据Kubernetes网站的说法,“Kubernetes是一个自动化,容器化应用程序部署扩展和管理的开放源代码系统.”Kubernetes由Google根据他们在生产中运行容器的经验使用称为Borg的内部集群管理系统(有时简称Omega). Kubernetes的体系结构依赖于这种经验,如下所示: 从上图可以看出,有一些与Kubernetes集群相关的组件.主节点将容器工作负载放置在工作节点.其他组件包括: etcd:该组件存储配置数据,可以通过简单的HTTP或JSO

技术升级成为Linux运维人前途的魔障,是跟进还是选择被淘汰?

技术迭代升级是做IT人最苦恼的难题,随着社会互联网应用的普及,企业追求高的运行效率和性价比,以往一个小的Linux运维项目动辄10多人,现在流程和过程自动化以后,像类似唯品会一样的大型电商公司才不过20人的Linux运维团队. "以前会个基本的Linux操作和一些常见的安全部署处理就能拿个8K以上的薪资,现在的面试者一出来就会各种的高阶能力,例如Docker.Tomcat.KVM等,如果不是因为企业发展还不错,站住了现在的位置,可能会面临失业."10年就工作的张先生说到. 在IT行业里

kubernetes 基础概念学习

kubernetes基础概念1)master/node的几个守护进程master :API Server(提供了k8s各类资源对象(Pod,RC,service)的增,删,改,查及HTTP REST接口)???????????????Scheduler(负责Pod调度,通过调度算法为待调度Pod列表的每个Pod从Node列表中选择一个最适合的Node,并将信息写入etcd中.kubelet通过API Server监听到kubernetes Scheduler产生的Pod绑定信息,然后获取对应的P