1 kubernetes网络模型
原则:
每个pod都拥有独立的IP地址,所有pod可以连通。
一个pod内所有容器共享一个网络堆栈(即网络明明空间,
包括IP地址,网络设备等),同一个pod内的容器可以通过localhost连接对方的端口。
2 Docker网络基础
使用了:
网络命名空间,Veth设备对,网桥,路由等。
2.1 网络命名空间
作用:不同命名空间中的网络栈时完全隔离,用于实现不同容器之间网络的隔离。
实现:让全局变量成为一个网络命名空间变量的成员,协议栈的函数调用加入Namespace参数。
实现不同命名空间的网络相互通信:
通过Veth设备对,打通不同协议栈的壁垒,一端连接这个网络命名空间的协议栈,一端连接另一个网络命名空间的协议栈。
网络命名空间操作:
创建命名空间:
ip netns add <name>
在命名空间内执行命令:
ip netns exec <name> <commnd>
2.2 Veth设备对
作用:在不同的网络命名空间进行通信,连接两个网络命名空间,
Veth设备成对出现。
通过ethtool工具查看Veth对的对端在哪里。
Usage: ip link add [link DEV] [ name ] NAME
[ txqueuelen PACKETS ]
[ address LLADDR ]
[ broadcast LLADDR ]
[ mtu MTU ]
[ numtxqueues QUEUE_COUNT ]
[ numrxqueues QUEUE_COUNT ]
type TYPE [ ARGS ]
ip link只能看链路层的状态,看不到ip地址
# ip link add eth1 name Test type bridge :创建一个名字是Test的类型是bridge的eth1端口
2.3 网桥
作用: 是二层虚拟网络设备,把网络接口连接起来,使得网口之间报文能够互相转发。
原理: 解析报文,读取目标MAC地址信息,和自己记录的MAC表结合,决策转发目标网口。
网桥会学习源MAC地址,转发报闻,只需要向特定网口进行转发。
实现: 通过一个虚拟的网桥设备来实现桥接。这个虚拟设备可以绑定若干个以太网接口设备。
桥接只在数据链路层实现。
网桥常用命令:
新增网桥设备:
brctl addbr xxxxx
为网桥增加网口(即物理网卡)
brctl addif xxxxx ethx
无路网卡做为网口工作在链路层,不需要IP地址
ifconfig ethx 0.0.0.0
给网桥配置一个IP地址:
ifconfig brxxx xxx.xxx.xxx.xxx
这样网桥就有了IP地址,而连接到网桥的网卡就是纯链路层设备。
2.4 Iptabes/Netfilter
网络协议栈中有回调函数挂结点,可以对数据包进行操作,例如:
过滤,修改等。整个挂结点技术叫做Netfilter和Iptables。
Netfilter:
在内核中执行挂接规则。
Iptables:
在用户模式下运行的进程,维护内核中Netfilter的规则表。
挂结点规则:
=== 上层协议处理 ===
INPUT 路由
^
| OUTPUT
路由-> FORWARD-> |
^
|
PREROUTAING POSTROUTING
^
| |
=== 接口设备 ===
2.5 路由
作用: IP层数据转发时,会使用路由表决定转发到哪里。
实现: IP层维护一张路由表,用该表做决策。
路由表条目:
目的IP地址: 可以时某台主机地址,也可以时网络地址
下一个路由器的IP地址: 用来转发从相应接口接收到的IP数据报文。
标志: 目的IP地址是主机地址还是网络地址
网络接口规范: 数据报文的网络接口规范。
路由规则:
1条目的第一个字段匹配目的IP地址(主机)或部分匹配IP地址(网络),将指示下一个路由器的
IP地址。
2 没有匹配,就搜索匹配的网络ID,若找到,则数据报文会转发到指定的路由器上。
3 都不匹配,报文转发到默认路由器。
查看LOCAL表(包含本地设备地址,供linux协议栈识别本地地址,进行本地各个不同网络接口之间的数据转发)
ip route show table local type local
样例输出:
10.8.1.54 dev tun0 proto kernel scope host src 10.8.1.54
127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
172.17.0.1 dev docker0 proto kernel scope host src 172.17.0.1
172.19.0.1 dev br-042eb6f5d4dc proto kernel scope host src 172.19.0.1
192.168.0.199 dev wlp3s0 proto kernel scope host src 192.168.0.199
192.168.122.1 dev virbr0 proto kernel scope host src 192.168.122.1
MAIN表:用于各类网络IP地址的转发。
路由表的查看:
ip route list
样例输出:
10.8.1.54 dev tun0 proto kernel scope host src 10.8.1.54
127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
172.17.0.1 dev docker0 proto kernel scope host src 172.17.0.1
172.19.0.1 dev br-042eb6f5d4dc proto kernel scope host src 172.19.0.1
netstat -rn
样例输出:
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.0.100 0.0.0.0 UG 0 0 0 wlp3s0
10.8.0.0 10.8.1.53 255.255.0.0 UG 0 0 0 tun0
10.8.0.1 10.8.1.53 255.255.255.255 UGH 0 0 0 tun0
172.19.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-042eb6f5d4dc
解释:
标志U表示是可达路由;标志为G,说明这个网络接口连接的是网关,否则说明是直连主机
3 Docker的网络实现
bridge模式下:
Docker Daemon首次启动会创建一个虚拟的网桥,默认名字是docker0,给网桥分配一个子网。
Docker创建出来的每个容器,都会创建一个虚拟以太网设备(Veth设备对),其中一端关联到网桥上,另一端使用网络命名空间映射到容器的eth0设备,然后从网桥的地址段内给eth0接口分配一个IP地址。
3.1 Docker桥接网络模型
Node1
容器1,容器2
eth0 eth0 <==ip2
ethxx ethxx
docker0网桥 <==ip1
路由
eth0 <==ip3
解释:
ip1是网桥的ip地址,通常172开头,该地址和主机IP地址不重叠。
ip2是Docker在启动容器时,在这个地址段随机选择的没有使用的ip地址。
启动后,Docker将Veth对的名字映射到eth0网络接口。
ip3是主机的网卡地址。外部一般看不到ip1和ip2的。
作用: 同一台机器内容器之间可以相互通信,不同主机容器不能相互通信。
ip addr可以看到
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:e0:a8:f2:65 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
iptables -- 对表、链、规则进行配置
iptables-save -- dump 已配置的规则,可以用 > 重定向到一个文件中
iptables-restore -- 从之前导出的iptable规则配置文件加载规则。
iptables-save|grep docker0
样例输出如下:
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION -i br-042eb6f5d4dc -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-042eb6f5d4dc -j DROP
3.2 Docker网络局限
没有考虑多主机互联的网络解决方案。
4 kubernetes的网络实现
4.1 容器到容器的通信
同一个Pod内的容器共享一个网络命名空间,就像在同一台机器上一样,可以用localhost地址访问彼此端口。
优点: 简单,安全。
两个容器可以直接使用linux的本地IPC(进程间通信),例如消息队列或管道。
4.2 同一个node内的pod之间的通信
每个pod有真实的全局ip地址。
同一个Node内的Pod关系如下:
======= Node1 ========
Pod1 Pod2
容器1 容器2 容器1 容器2
共享网络空间 共享网络空间
eth0 ip1 eth0 ip2
ethxxx ethxxx
ip3
docker0网桥
路由
eth0
分析:
Pod1和Pod2都通过Veth连接在同一个docker0网桥上的,它们的IP地址
IP1,IP2都是从docker0的网段上动态获取的,和网前本身的IP3是同一个网段。
Pod1, Pod2的Linux协议栈上默认路由都是docker0的地址。
总结:
同一个Node上的pod都关联在同一个docker0网桥上,地址段相同,所以pod之间能够直接通信的。
4.3 不同Node上的Pod之间通信
docker0网段与宿主机网卡是不同的IP网段,不同Node之间的通信只能通过
宿主机的物理网卡进行。
k8s会记录正在运行的Pod的IP分配信息到etcd中(作为Service的Endpoint)。
这些私有IP信息对于Pod到Pod的通信是分重要。
支持不同Node上的Pod之间通信的条件:
1) 对k8s集群中Pod的ip分配规划不能冲突。
2) 将Pod的IP和所在Node的IP关联,通过这个关联让Pod可以互相访问。
解决方法:
1) 部署k8s,对docker0的IP地址规划,保证没有冲突
2) 知道对方Pod的IP地址挂在哪个具体的Node上,将数据发送到宿主机的
网卡上,然后在宿主机将相应的数据转到具体的docker0上。
eth0:光纤以太网口卡,Fiber Ethernet Adapter0。也就是物理网卡,
即实际的网络接口设备。
===Node1 ===Node2
Pod1 Pod2
容器1 容器2 容器1 容器2
共享网络空间 共享网络空间
eth0 ip1 eth0 ip2
ethxxx ethxxx
docker0网桥 docker0网桥
路由 路由
eth0 ip3 eth0 ip4
=======================>
5 Kubernetes网络策略
Network Policy对Pod之间的网络通信进行限制和准入控制,设置方式为
将Pod的Label作为查询条件,设置允许访问的Pod列表,查询条件可以作用域Pod
和Namespace级别。
1) 网络隔离
作用于Namespace级别的所有Pod。
6 开源的网络组件
定义所有Pod都可以直接连通。
6.1 Flannel
1) 给每个Node上的容器分配不冲突IP地址
2) 在IP地址间建立覆盖网络(Overlay Network),通过覆盖网络,将数据原封不动
地传递到目标容器内。
原理:
1)Flannel创建了一个名为flannel0地网桥,这个网桥地一端连接docker0网桥,另一端
连接一个去叫作flanneld的服务进程。
2) flanneld进程连接etcd,利用etcd来管理可分配的IP地址段资源,
同时监控etcd中每个pod的实际地址,并在内存中建立了一个Pod节点路由表;
3) 然后下连docker0和物理网络,使用内存中的Pod节点路由表,将docker0发给它
的数据包包装起来,利用物理网络的连接将数据包投递到目标flanneld上,从而
完成Pod到Pod之间的直接的地址通信。
Flannel底层通信协议:
可以使用UDP,只要能通到对端的Flannel就可以。
Flannel如何做到为不同Node上的Pod分配的IP不产生冲突:
Flannel使用了etcd存储,每次分配的地址段都在公共区域获取,就可以不冲突了。
Flannel分配好地址段后,通过修改Docker的启动参数将分配给它的地址段传递进去。
--bip=172.17.18.1/24
通过这些操作,Flannel控制了每个Node上的docker0地址段的地址,也就保障了所有
Pod的IP地址在同一个水平网络中且不产生冲突。
===CoreOS Machine ===CoreOS Machine
Pod1 Pod2 Pod1 Pod2
容器1,容器2 容器1,容器2 容器1,容器2 容器1,容器2
veth0 veth1 veth0 veth1
10.1.15.2/24 10.1.15.3/24 10.1.20.2/24 10.1.20.3/24
docker0 docker0
10.1.15.1/24 10.1.20.1/24
flannel0 flannel0
10.1.15.0/16 10.1.20.0/16
flanneld flanneld
eth0 eth0
192.168.0.100 192.168.0.200
========== packet =========
MAC OuterIP UDP InnerIP Payload
source:192/168.0.100 source:10.1.15.2
dest: 10.1.20.3
参考:
Kubernetes权威指南第2版
https://www.cnblogs.com/teezzy/p/9565122.html
https://baike.baidu.com/item/ipc/91622?fr=aladdin