Kubernetes Network
Kubernetes Network 基本概念和原理
一、单机容器网络
名词
- 网络栈:网络栈包括了网卡(
Network Interface
)、回环设备(Loopback Device
)、路由表(Routing Table
)和Iptables
规则,对于一个进程来说,这些要素,就构成了它发起请求和响应网络请求的基本环境。 - 网桥(
Bridge
):bridge
是一个虚拟网络设备,所以具有网络设备的特征,可以配置IP
、MAC
地址;Bridger
是一个虚拟交换机,具有和物理交换机类似的功能。它是工作在数据链路层的设备。 Veth Pair
: 虚拟网线,用来连接容器到网桥上的;它被创建出来以后,总是以两张虚拟网卡(Veth Peer
)的形式成对出现,并且,从其中一个网卡发出的数据包会自动出现在与之对应的网卡上,哪怕是这两张_*网卡_在不同的Network Namespace
中。ARP
: 是一个通过三层的IP
地址找到对应二层MAC
地址的协议。CAM表
:虚拟交换机(这里是网桥)通过MAC
地址学习维护的端口和MAC
地址的对应表。
Host网络
作为一个容器,在启动时可以通过指定-net=host
,使用宿主机的Network Namespace
。
$ docker run -d -net=host --name nginx-1 nginx
使用Host
网络的优点是网络性能较好,直接使用宿主机的网络栈,缺点是会引入共享网络资源的问题,比如端口冲突。所以,在多数情况下,我们都希望能使用自己Network Namespace里的网络栈,拥有属于自己的IP和端口。
如何通信
如上图,描述了单节点容器网络的通信流程,下面主要按C1->C2
的访问流程来详细描述交互流程:
# 先创建两个容器,用于模拟发起请求,启动两个centos容器,并在里面安装net-tools工具,才可以使用ifconfig命令
# 创建C1,并安装net-tools
$ docker run -d -it --name c1 centos /bin/bash
$ docker exec -it c1 bash
$ [root@60671509044e /]# yum install -y net-tools
# 创建C2,并安装net-tools
$ docker run -d -it --name c2 centos /bin/bash
$ docker exec -it c2 bash
$ [root@94a6c877b01a /]# yum install -y net-tools
- 容器
C1
和C2
启动之后,在容器中都有一条默认的路由规则,当前容器网段的所有请求都会走eth0
网卡设备。- C1
# 进入c1容器,查看ip以及路由表
$ docker exec -it c1 bash
# 查看IP
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.7 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:07 txqueuelen 0 (Ethernet)
RX packets 6698 bytes 9678058 (9.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3518 bytes 195061 (190.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 查看路由
$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default _gateway 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
C2
# 进入C2容器查看IP和路由表
$ docker exec -it c2 bash
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.8 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:08 txqueuelen 0 (Ethernet)
RX packets 6771 bytes 9681937 (9.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3227 bytes 179347 (175.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 查看路由
$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default _gateway 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
上述容器现实有自己的IP
以及MAC
地址,并且每个容器中都有默认路由_gateway
指向eth0
网卡;并且_gateway
有对应的MAC
地址已经存在于本地ARP
缓存中。
- 主机之间网络通信需要用到
MAC
地址,这是数据链路层识别主机的方式,C1
访问C2
的时候会先从本地ARP
缓存中查找是否有C2
容器对应的IP:172.17.0.3
的MAC
地址。如果没有就会发起ARP
协议查找MAC
地址。
# c1 -> c2 ,先发起ARP请求查找MAC地址,可以在容器中查看ARP缓存对应IP 的MAC
$ docker exec -it c1 bash
# 先查看本地的ARP缓存
$ [root@94a6c877b01a /]# arp
Address HWtype HWaddress Flags Mask Iface
_gateway ether 02:42:2e:8d:21:d6 C eth0
# 执行ping命令就会发起ARP寻址请求
$ ping 172.17.0.8
# 再查询本地arp缓存,发现已经有MAC地址存在了
$ [root@60671509044e /]# arp
Address HWtype HWaddress Flags Mask Iface
172.17.0.8 ether 02:42:ac:11:00:08 C eth0
_gateway ether 02:42:2e:8d:21:d6 C eth0
ARP
寻址流程:C1
容器发起ARP
请求,进过本地路由协议之后会把请求路由到网桥上,此时网桥(Bridge
)充当一个虚拟交换机,虚拟交换机会把ARP
广播到其它插入到网桥的所有容器,C2
收到ARP
协议之后会回复MAC
地址。
- 查找到
C2
的MAC
地址之后就可以发起通信。
二、跨主机容器通信
跨主机之间容器通信按是否依赖底层网络环境来划分主要分为
Overlay
和Underlay
两种网络结构,Overlay
网络要求只是主机之间网络可达即可,不要求主机之间同处二层域;Underlay
对底层的基础设施有要求,按照实现的方式对底层的网络基础设施有不同的要求,比如Flanan host-gw
组件要求主机之间同处二层域,也就是主机之间要连接到一个交换机上。
名词
Overlay Network
(覆盖网络): 在已有的宿主机网络之上,通过软件构建一个覆盖在宿主机网络之上的、可以把所有容器连通在一起的虚拟网络。Tun设备(Tunnel设备)
:在Linux
中,TUN
设备是一种工作在三层(Network Layer
)的虚拟网络设备;Tun
设备的功能就是在操作系统内核和用户应用程序之间传递IP
包,VXLAN
: 虚拟可扩展局域网(Virtual Extensible LAN
),是LINUX
内核支持的一种网络虚拟化技术,VXLAN
完全在内核态实现网络数据包的封装和解封装。VTEP
:虚拟隧道端点设备,它既有IP
,也有MAC
地址。BGP
: 边界网关协议(Border Gateway Protocol
),它是一个Linux
内核原生就支持的、专门用在大规模数据中心里维护不同的自治系统之间路由信息的、无中心的路由协议。
跨主机通信
跨主机之间的容器通信,通过采用Overlay Network
来实现跨主机之间的容器通信,Overlay Network
的实现有多种方式。
Overlay 模式
1、三层Flannel UDP
Flannel UDP
模式是Flannel
最开始提供的一种最简单且 最易实现的容器跨主网络方案,但是因为性能最差,所以后来被弃用。但是对于理解Overlay
的实现方式还是很有参考意义的。
我们以一个例子来讲述这个网络访问的流程,在这个流程中,有两台宿主机,四个容器,我们需要通过Container-1
容器请求Container-4
。
Container-1
容器向Container-4
容器发起请求,Docker0
是位于Root Network Namespace
的,通过veth peer
一头连着容器的Network Namespace
一头连着位于Root Netwrok Namespace
的Docker0
虚拟网络设备。
- 容器
100.96.1.2
访问100.96.2.2
,由于目的地址不在Docker0
网桥的网段内(通过ARP
请求一次就知道目标容器不在此网桥上),所以这个IP
会执行Container-1
的默认路由规则中,容器中的默认路由规则就是如下的default via 172.17.0.1 dev eth0
。对应到上图的步骤1。
# 容器中默认设置的的路由规则,
[root@94a6c877b01a /]# ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
# 下一跳是172.17.0.1且从eth0设备上出去,通过查看docker的网络,172.17.0.1就是bridge设备的网关IP
lengrongfu@MacintoshdeMacBook-Pro ~ % docker network ls
NETWORK ID NAME DRIVER SCOPE
e522990979b3 bridge bridge local
# 查看网络
lengrongfu@MacintoshdeMacBook-Pro ~ % docker inspect network e522990979b3
[
{
"Name": "bridge",
"Id": "e522990979b365e9df4d967c3600483e598e530361deb28513b6e75b8b66bedf",
"Created": "2021-04-12T12:11:57.321486866Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"94a6c877b01ac3a1638f1c5cde87e7c58be9ce0aafd4a78efcb96528ab00ed94": {
"Name": "c2",
"EndpointID": "a5c12fb3800991228f8dc3a2a8de1d6f4865439701a83558e4430c2aebf783a8",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
- 进入到
Docker0
网桥之后就按照主机上的路由取决于后续如何走。如下就是主机的路由表,访问目标IP
为100.96.2.2
的设备会命中第二条匹配规则,意思是访问100.96.0.0/16
网段的数据去flannel0
设备,并且愿IP
为100.96.1.0
。对应到上图的步骤2。
# Node1路由表
$ ip route
1 Default via 10.168.0.1 dev eth0
2 100.96.0.0/16 dev flannel0 proto kernel scope link src 100.96.1.0
3 100.96.1.0/24 dev docker0 proto kernel scope link src 100.96.1.1
4 10.168.0.0/24 dev eth0 proto kernel scope link src 10.168.0.2
Flannel0设备
- 上述说了
Flannel0