K8S学习笔记之Flannel解读
0x00 概述
我们知道docker官方并没有提供多主机的容器通信方案,单机网络的模式主要有host,container,brige,none。none这种模式,顾名思义就是docker本身不去管理网络模式,交由其他管理和分配,比如cni。Flannel是一个专为kubernetes定制的三层网络解决方案,主要用于解决容器的跨主机通信问题。
首先,flannel利用Kubernetes API或者etcd用于存储整个集群的网络配置,其中最主要的内容为设置集群的网络地址空间。例如,设定整个集群内所有容器的IP都取自网段“10.1.0.0/16”。
接着,flannel在每个主机中运行flanneld作为agent,它会为所在主机从集群的网络地址空间中,获取一个小的网段subnet,本主机内所有容器的IP地址都将从中分配。
然后,flanneld再将本主机获取的subnet以及用于主机间通信的Public IP,同样通过kubernetes API或者etcd存储起来。
最后,flannel利用各种backend ,例如udp,vxlan,host-gw等等,跨主机转发容器间的网络流量,完成容器间的跨主机通信。
0x01 Flannel实现原理
Flannel为每个主机提供独立的子网,整个集群的网络信息存储在etcd上。对于跨主机的转发,目标容器的IP地址,需要从etcd获取。
先上图,比较直观:

步骤:
- IP数据报被封装并通过容器的eth0发送。
- Container1的eth0通过veth对与Docker0交互并将数据包发送到Docker0。然后Docker0转发包。
- Docker0确定Container3的IP地址,通过查询本地路由表到外部容器,并将数据包发送到虚拟NIC Flannel0。
- Flannel0收到的数据包被转发到Flanneld进程。 Flanneld进程封装了数据包通过查询etcd维护的路由表并发送数据包通过主机的eth0。
- 数据包确定网络中的目标主机主机。
- 目的主机的Flanneld进程监听8285端口,负责解封包。
- 解封装的数据包将转发到虚拟NICFlannel0。
- Flannel0查询路由表,解封包,并将数据包发送到Docker0。
- Docker0确定目标容器并发送包到目标容器。
在常用的vxlan模式中,涉及到上面步骤提到的封包和拆包,这也是Flannel网络传输效率相对低的原因。

下面重点说一下host-gw模式。
hostgw是最简单的backend,它的原理非常简单,直接添加路由,将目的主机当做网关,直接路由原始封包。
例如,我们从etcd中监听到一个EventAdded事件subnet为10.1.15.0/24被分配给主机Public IP 192.168.0.100,hostgw要做的工作就是在本主机上添加一条目的地址为10.1.15.0/24,网关地址为192.168.0.100,输出设备为上文中选择的集群间交互的网卡即可。对于EventRemoved事件,只需删除对应的路由。
因为没有了封包和拆包,host-gw的性能是最好的。

不过host-gw 要求主机网络二层直接互联。所以每个节点上有n-1个路由,而n个节点一共有n(n-1)/2个路由以保证flannel的flat网络能力。
为什么host-gw 要求主机网络二层直接互联?
首先通过抓包分析,抓包结果如下图:

可以看出host-gw在传输层走的是tcp。然后在网络层的源IP和目的IP均是容器的IP,虚拟IP。这就决定了二层互联,因为只有交换机是不关注源IP和目的IP。假如两台主机在两个lan中,二层不通,三层通,那么就需要路由器,而路由器是无法识别容器的这些ip。当然也可以配置路由规则,但是显然没有这么做的。
Openshift默认也是使用Flannel host-gw容器网络方案,其官网也清晰的画出了host-gw的data flow diagram。

0x02 示例配置和启动参数
示例配置:
{
"Network": "10.0.0.0/8",
"SubnetLen": 20,
"SubnetMin": "10.10.0.0",
"SubnetMax": "10.99.0.0",
"Backend": {
"Type": "udp",
"Port": 7890
}
}
启动参数:
--public-ip="": IP accessible by other nodes for inter-host communication. Defaults to the IP of the interface being used for communication.
--etcd-endpoints=http://127.0.0.1:4001: a comma-delimited list of etcd endpoints.
--etcd-prefix=/coreos.com/network: etcd prefix.
--etcd-keyfile="": SSL key file used to secure etcd communication.
--etcd-certfile="": SSL certification file used to secure etcd communication.
--etcd-cafile="": SSL Certificate Authority file used to secure etcd communication.
--kube-subnet-mgr: Contact the Kubernetes API for subnet assignment instead of etcd.
--iface="": interface to use (IP or name) for inter-host communication. Defaults to the interface for the default route on the machine. This can be specified multiple times to check each option in order. Returns the first match found.
--iface-regex="": regex expression to match the first interface to use (IP or name) for inter-host communication. If unspecified, will default to the interface for the default route on the machine. This can be specified multiple times to check each regex in order. Returns the first match found. This option is superseded by the iface option and will only be used if nothing matches any option specified in the iface options.
--iptables-resync=5: resync period for iptables rules, in seconds. Defaults to 5 seconds, if you see a large amount of contention for the iptables lock increasing this will probably help.
--subnet-file=/run/flannel/subnet.env: filename where env variables (subnet and MTU values) will be written to.
--subnet-lease-renew-margin=60: subnet lease renewal margin, in minutes.
--ip-masq=false: setup IP masquerade for traffic destined for outside the flannel network. Flannel assumes that the default policy is ACCEPT in the NAT POSTROUTING chain.
-v=0: log level for V logs. Set to 1 to see messages related to data path.
--healthz-ip="0.0.0.0": The IP address for healthz server to listen (default "0.0.0.0")
--healthz-port=0: The port for healthz server to listen(0 to disable)
--version: print version and exit
参考
K8S学习笔记之Flannel解读的更多相关文章
- 【K8s学习笔记】K8s是如何部署应用的?
本文内容 本文致力于介绍K8s一些基础概念与串联部署应用的主体流程,使用Minikube实操 基础架构概念回顾 温故而知新,上一节[K8S学习笔记]初识K8S 及架构组件 我们学习了K8s的发展历史. ...
- Docker&K8S学习笔记(一)—— Docker安装
最近一年在工作上经常使用Docker与K8S,除了利用其打镜像,部署服务外,还基于Docker与K8S开发了一套CICD流水线平台,为了加深相关知识点的理解,所以从今天开始会定期更新学习笔记,本套学习 ...
- k8s学习笔记
9.deployment:声明式的升级应用 9.1.使用RC实现滚动升级 #kubectl rolling-update kubia-v1 kubia-v2 --image=luksa/kubia:v ...
- K8S学习笔记之二进制的方式创建一个Kubernetes集群
0x00 单节点搭建和简述 minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环境. 官方地址: ...
- 【k8s学习笔记】使用 kubeadm 部署 v1.18.5 版本 Kubernetes集群
说明 本文系搭建kubernetes v1.18.5 集群笔记,使用三台虚拟机作为 CentOS 测试机,安装kubeadm.kubelet.kubectl均使用yum安装,网络组件选用的是 flan ...
- Docker 与 K8S学习笔记(二十三)—— Kubernetes集群搭建
小伙伴们,好久不见,这几个月实在太忙,所以一直没有更新,今天刚好有空,咱们继续k8s的学习,由于我们后面需要深入学习Pod的调度,所以我们原先使用MiniKube搭建的实验环境就不能满足我们的需求了, ...
- K8S学习笔记之二进制部署Kubernetes v1.13.4 高可用集群
0x00 概述 本次采用二进制文件方式部署,本文过程写成了更详细更多可选方案的ansible部署方案 https://github.com/zhangguanzhang/Kubernetes-ansi ...
- k8s学习笔记之二:使用kubeadm安装k8s集群
一.集群环境信息及安装前准备 部署前操作(集群内所有主机): .关闭防火墙,关闭selinux(生产环境按需关闭或打开) .同步服务器时间,选择公网ntpd服务器或者自建ntpd服务器 .关闭swap ...
- k8s 学习笔记 etcd
1. Etcd Etcd是Kubernetes集群中的一个十分重要的组件,用于保存集群所有的网络配置和对象的状态信息.在后面具体的安装环境中,我们安装的etcd的版本是v3.1.5,整个kuberne ...
随机推荐
- zyb的面试(广工14届比赛)
这道题目在上半年ZOJ模拟上年青岛赛区ACM题的时候就已经出现了.当时我不会写,本来想着赛后补题的最后因为懒惰又没补. 现在这道题又出现了.这是上天对我的惩罚啊!!! 所以这次铁了心也要补这题.然后我 ...
- sql server 函数的自定义
创建用户定义函数.这是一个已保存 Transact-SQL 或公共语言运行时 (CLR) 例程,该例程可返回一个值.用户定义函数不能用于执行修改数据库状态的操作.与系统函数一样,用户定义函数可从查询中 ...
- Github Issues
快捷键r
- C++编译变更stlport到使用g++的stl经验总结
. 花了几天时间,需要把经验给记下来. 1. 需要支持C++11的编译器,最方便的方式就是 yum -y install devtoolset-6 在/usr/local/bin中增加gcc6.sh ...
- 北京时间转为时间搓 标准时间转为UTC
int standard_to_stamp(char *str_time) { struct tm stm; int iY, iM, iD, iH, iMin, ...
- VScode编辑器个性化配置
一.设置方法 “文件” - > “首选项” -> "设置" 二.字体大小和缩进 "editor.tabSize": 2, "editor. ...
- css属性 background
background 在一个声明中设置所有的背景属性. background-attachment 设置背景图像是否固定或者随着页面的其余部分滚动. background-color 设置元素的背景颜 ...
- jQuery-数据管理-删除事件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JavaScript 创建和浅析自定义对象
在Js中,除了Array.Date.Number等内置对象外,开发者可以通过Js代码创建自己的对象. 目录 1. 对象特性:描述对象的特性 2. 创建对象方式:对象直接量.new 构造函数.Objec ...
- js控制元素隐藏和显示
原生: 方法一: document.getElementById("idname").style.visibility="hidden"; document.g ...