14 K8S 网络
https://kubernetes.io/zh/docs/concepts/cluster-administration/networking/
在 K8S 中网络非常安全,因为涉及到 pod 的各种通讯
容器网络的目的:
1.实现同一个 pod 中的不同容器通信(LNMP),一个 pod 中的容器共用底层的网络组件
2.实现 pod 与 pod 同主机与跨主机的容器通信(微服务)
3.pod 和服务之间的通信( nginx 通过调用 tomcat )
4.pod 与 k8s 之外的网络通信
外部到 pod (客户 端的请求),用户的请求先到负载均衡器,负载均衡器在转发至 node 节点,node 节点在转发至 svc , svc 在转发至 pod ,中间经过多层转发,最主要的就是在 node 节点这块如何将请求转发至 svc,这是通过 K8S 环境以外进来的
pod 到外部(响应报文)
14.1 Kubernetes 网络模型
每一个 Pod
都有它自己的IP地址,这就意味着你不需要显式地在每个 Pod
之间创建链接, 你几乎不需要处理容器端口到主机端口之间的映射。 这将创建一个干净的、向后兼容的模型,在这个模型里,从端口分配、命名、服务发现、 负载均衡、应用配置和迁移的角度来看,Pod
可以被视作虚拟机或者物理主机。
Kubernetes 对所有网络设施的实施,都需要满足以下的基本要求(除非有设置一些特定的网络分段策略):
- 节点上的 Pod 可以不通过 NAT 和其他任何节点上的 Pod 通信
- 节点上的代理(比如:系统守护进程、kubelet)可以和节点上的所有Pod通信
overlay:
不同主机的容器间通信,容器需要在本地创建一个二层的虚拟网桥,让后网桥将请求报文进行封装,最后将封装好后发送至 vtype ,然后 vtype 本身是一个网络设备用于创建隧道,并且在每个主机上都有这么一个虚拟网卡,每个主机的报文都会进入到这个隧道上,在这个隧道上进行封装和解封装,隧道封装一次将报文发送至物理机,然后物理机在封装一次。
在隧道中封装的是容器的源 mac 和源 ip 封装好了之后将报文交给了物理网卡,物理网卡在原有的基础上在封装一次,这次封装的就是物理机的源 mac 和 IP ,这个时候在发送至交换机,而对于交换机来说能够看到的只是物理层面的 ip 和 mac 地址,然后通过拆分最后找到了目的 mac 和 ip 地址,然后将报文发送至目的物理机。
这时候目的物理机在进行报文的拆分,就会获取到目的容器地址和 ip
这样的好处就是可以实现跨网段,这个报文可以在不同的网段进行转发,他的通信是靠三层路由来打通的,不会受 mac 地址限制,但是可能会有损耗因为需要给他进行封装多层
路由:
将封装设备去点,在宿主机上直接通过路由选址,就是直接创建容器,这个容器直接调用物理网卡,并不需要在宿主机上进行封装了,到了物理网卡然后发现这是要去那个网段就直接丢到网桥,网桥再将报文直接转给容器,这样的好处就是不需要虚拟设备的封装。
虽然少了一层封装性能有所提升,但是问题在于不能实现跨网段,因为这个地方是通过二层设备来转发并没有直连设备。交换机只能够识别到 mac 地址
解决方法就是在交换机上添加对应的容器网段,从而实现直连
Underlay:
直接通过底层网络打通,强力依赖于底层网络,容器的网段直接和宿主机在同一网段,不在由 K8S 给容器分配地址,我们可以理解为直接将地址桥接至宿主机上,然后在由宿主机直接将报文交给交换机,可以通过 macvlan 来实现
这样的话一个网口有多个子接口,每个子接口有多个地址和 mac 地址,对交换机来讲他就是一个独立的地址,类似于虚拟化的桥接
这样的好处在于通信模式比较简单,不用再多次封装,而实直接将报文通过宿主机转发给交换机,性能很强但是管理起来相对麻烦。因为每个容器都需要一个独立的 ip 地址,所有对应的地址池都非常多,而且会有大量的广播报文。
总结:
从性能角度来看:underlay 是最强、接着是路由、overlay 最次
兼容性角度来看:overlay 是最强、路由第二、underlay 最次
14.2 网络通信方式
14.2.1 二层通信 underlay
基于目标 mac 地址通信,不可夸局域网通信,通常是由交换机实现报文转发。
macvlan 模式如下:
private mode: # 使用较少
private 模式下,同一父接口下的子接口之间彼此隔离,不能通信,从外部也无法访问。
vepa(Virtual Ethernet Port Aggregator,虚拟以太网端口聚合器) mode: # 使用较少
vepa 模式下,子接口之间的通信流量需要导到外部支持 802.1Qbg/VPEA 功能的交换机上(可以是物理的或者虚拟的), 经由外部交换机转发,再绕回来。
bridge mode: # 使用较多
bridge 模式下,模拟的是 Linux bridge 的功能,但比 bridge 要好的一点是每个接口的
MAC 地址是已知的,不用学习,所以这种模式下,子接口之间就是直接可以通信的。
passthru mode(直通模式): # 使用较少
passthru 模式,只允许单个子接口连接父接口。
source mode: # 使用较少
这种模式,只接收源 mac 为指定的mac 地址的报文。
上面几种模式如下图:
bridge:模式下所有容器间能够直接通信
private:容器间不能直接通信,并且外部的报文无法进入,从而导致外部无法访问
vepa:需要交换机转发一次才能实现通信
passthru:只能够实现一个容器的通信
14.2.2 三层通信
基于目标 IP 通信,也叫做 IP 交换技术,解决了夸局域网、跨网络通信,通常是由路由器、防火墙、三层交换机等。
如上图中有两个路由器,然后在路由器下面就是接了好多宿主机,并且在宿主机上创建了多个容器,而多个容器之间就会生成隧道设备。
tunnel0 设备就是有 calico 生成的,容器的通信先发送给 tunnel0 设备,再由 tunnel0 发送至物理网卡,最后物理网卡在发送给路由器。路由器接收到了之后拆开报文看到需要跨网段就直接给对应的目标地址发送过去了。
这时候另外一个路由器接收到了拆开并找到对应的目的地址,就转发给了对应地址的容器如上图的 10.92.203.2 或 10.92.203.3 地址。
14.2.3 网桥(bridge)
安装完 docker 之后会默认生成一个 docker 的网桥设备,网桥设备通过 mac 地址转发报文到各个容器,如果容器要访问当前宿主机意外的容器或者网络,则会使用宿主机的路由功能进行源地址转换。
14.2.4 vlan
VLAN(Virtual Local Area Network)即虚拟局域网,是将一个物理(交换机)的网络在逻辑上划分成多个广播域的通信技术(可以理解为划分多个网段),VLAN 内的主机间可以直接通信,而 VLAN 网络外的主机需要通过三层网络设备转发才可以通信,因此一个 vlan 可以将服务器的广播报文限制在一个VLAN 内,从而降低单个网络环境中的广播报文,vlan 采用 12 位标识 vlan ID,即一个交换机设备最多为 2^12=4096 个 vlan。
14.2.5 Overlay 网络简介
叠加网络或者覆盖网络,在物理网络的基础之上叠加实现新的虚拟网络,即可使网络的中的 容器可以相互跨主机的通信:
14.2.5.1 overlay 网络实现方式
VxLAN:
VxLAN 全称是 Visual eXtensible Local Area Network(虚拟扩展本地局域网),主要由 Cisco 推出, vxlan 是一个 VLAN 的扩展协议, 是由 IETF 定义的 NVO3 ( Network Virtualization over Layer 3)标准技术之一,VXLAN 的特点是将 L2 的以太帧封装到 UDP 报文(即 L2 over L4)中,并在 L3 网络中传输,即使用 MAC in UDP 的方法对报文进行重新封装, VxLAN 本质上是一种 overlay 的隧道封装技术,它将 L2 的以太网帧封装成 L4 的 UDP 数据报,然后在 L3 的网络中传输,效果就像 L2 的以太网帧在一个广播域中传输一样,实际上 L2 的以太网帧跨越了 L3 网络传输,但是缺不受 L3 网络的限制,vxlan 采用24 位标识 vlan ID 号,因此可以支持 2^24=16777216 个vlan,其可扩展性比 vlan 强大的多,可以支持大规模数据中心的网络需求。
因为 vxlan 端口为 8472 封装好了之后通过 8472 进行接收
VTEP(VXLAN Tunnel Endpoint vxlan 隧道端点),VTEP 是VXLAN 网络的边缘设备,是 VXLAN 隧道的起点和终点,VXLAN 对用户原始数据帧的封装和解封装均在 VTEP 上进行,用于VXLAN 报文的封装和解封装,VTEP 与物理网络相连,分配的地址为物理网IP 地址,VXLAN 报文中源IP 地址为本节点的 VTEP 地址,VXLAN 报文中目的 IP 地址为对端节点的 VTEP 地址,一对 VTEP 地址就对应着一个 VXLAN 隧道,服务器上的虚拟交换机(隧道 flannel.1 就是VTEP),比如一个虚拟机网络中的多个 vxlan 就需要多个VTEP 对不同网络的报文进行封装与解封装。
VNI(VXLAN Network Identifier):VXLAN 网络标识 VNI 类似VLAN ID,用于区分VXLAN 段, 不同VXLAN 段的虚拟机不能直接二层相互通信,一个VNI 表示一个租户,即使多个终端用户属于同一个VNI,也表示一个租户。
14.2.6 underlay 简介
Underlay 网络就是传统 IT 基础设施网络,由交换机和路由器等设备组成,借助以太网协议、路由协议和 VLAN 协议等驱动,它还是 Overlay 网络的底层网络,为 Overlay 网络提供数据通信服务。容器网络中的 Underlay 网络是指借助驱动程序将宿主机的底层网络接口直接暴露给容器使用的一种网络构建技术,较为常见的解决方案有 MAC VLAN、IP VLAN 和直接路由等。
Underlay 依赖于网络网络进行跨主机通信。
14.2.6.1 bridge 与 macvlan 模式
Bridge:桥接模式
MAC VLAN:支持在同一个以太网接口上虚拟出多个网络接口(子接口),每个虚拟接口都拥有唯一的MAC 地址并可配置网卡子接口IP。
14.3 flannel
由 CoreOS 开源的针对 k8s 的网络服务,其目的为解决 k8s 集群中各主机上的 pod 相互通信的问题,其借助于 etcd 维护网络 IP 地址分配,并为每一个 node 服务 器分配一个不同的 IP 地址段。
Flannel 网络模型(后端),Flannel 目前有三种方式实现 UDP/VXLAN/host-gw:
- UDP:早期版本的F lannel 使用UDP封装完成报文的跨越主机转发,其安全性及性能略有不足。
- VXLAN:Linux内核在在 2012 年底的 v3.7. 0 之后加入了 VXLAN 协议支持,因此新版本的Flannel 也有 UDP 转换为 VXLAN , VXLAN 本质上是一-种 tunnel (隧道)协议,用来基于3层网络实现虚拟的 2 层网络,目前 flannel 的网络模型已经是基于 VXLAN 的叠加(覆盖)网络,目前推荐使用 vxlan 作为其网络模型。
- Host-gw:也就是 Host GateWay , 通过在 node 节点上创建到达各目标容器地址的路由表而完成报文的转发,因此这种方式要求各 node 节点本身必须处于同一个局域网(二层网络)中,因此不适用于网络变动频繁或比较大型的网络环境,但是其性能较好。
flannel 组件解释:
Cni0:网桥设备,每创建一个 pod 都会创建一对 veth pair, 其中一端是 pod 中的 eth0 ,另一端是 Cni0 网桥中的端口 (网卡),Pod 中从网卡 eth0 发出的流量都会发送到 Cni0 网桥设备的端口(网卡)上,Cni0 设备获得的 ip 地址是该节点分配到的网段的第一个地址。
Flannel.1: overlay网络的设备, 用来进行vxlan报文的处理(封包和解包), 不同node之间的pod数据流量都从overlay设备以隧道的形式发送到对端。
14.4 calico
calico官网: https://www.tigera.io/project-calico/
Calico 是一个纯三层的网络解决方案,为容器提供多 node 间的访问通信, calico 将每个 node 节点都当做为一个路由器(router)来使用通过宿主机来做一些目的地址得匹配,各节点通过 BGP(Border Gateway Protocol) 边界网关协议学习并在 node 节点生成路由规则,从而将不同 node 节点上的pod连接起来进行通信。
calico 简介:
网络通过第 3 层路由技术(如静态路由或 BGP 路由分配)或第 2 层地址学习来感知工作负载 IP 地址。因此,它们可以将未封装的流量路由到作为最终目的地的端点的正确主机。但是,并非所有网络都能够路由工作负载IP地址。例如公共云环境、跨VPC子网边界的 ANS,以及无法通过 BGP、Calico 对应到 underlay 网络或无法轻松配置静态路由的其他场最,这就是为什么 Calico 支持封装,因此您可以在工作负载之间发送流量,而无需底层网络知道工作负载IP 地址
calico 封装类型:
Calico 支持两种类型的封装: VXLAN 和 IP-in-IP, VXLAN 在 IP 中没有 IP 的某些环境中受支持(例如Azure) ,VXLAN 的每数据包开销稍高,因为报头较大。但除非您运行的是网络密集型工作负载,否则您通常不会注意到这种差异,这两种封装之间的另一个小差异是 Calico 的 VXLAN 实现不使用BGP,Calico的IP-In-IP是在Calico节点之间使用BGP协议实现跨子网。
BGP 是一个去中心化的协议,它通过自动学习和维护路由表实现网络的可用性,但是并不是所有的网络都支持BGP,另外为了跨网络实现更大规模的网络管理,calico 还支持 IP-in-IP 的叠加模型,简称 IPIP, IPIP 可以实现跨不同网段建立路由通信,但是会存在安全性问题,其在内核内置,可以通过 Calico 的配置文件设置是否启用IPIP ,在公司内部如果 k8s 的 node 节点没有跨越网段建议关闭 IPIP。
BGP 和 IPIP 的区别:
IPIP 是一种将各 Node 的路由之间做一个 tunnel, 再把两个网络连接起来的模式。启用 IPIP 模式时,Calico 将在各 Node 上创建一个名为"tunl0"的虚拟网络接口。
BGP 模式则直接使用物理机作为虚拟路由路(vRouter) , 不再创建额外的tunnel。
calico 核心组件:
Felix:
calico 的 agent, 运行在每一台 node 节点上,其主要是维护路由规则、汇报当前节点状态以确保 pod 的夸主机通信。
BGP Client:
每台 node 都运行,其主要负责监听 node 节点上由 felix 生成的路由信息,然后通过 BGP 协议广播至其他剩余的 node 节点,从而相互学习路由实现 pod 通信。
Route Reflector:
集中式的路由反射器,calico v3.3 开始支持,当 Calico BGP 客户端将路由从其 FIB(Forward InformationdataBase,转发信息库)通告到 Route Reflector时, Route Reflector 会将这些路由通告给部署集群中的其他节点,Route Reflector 专门用于管理 BGP 网络路由规则,不会产生 pod 数据通信。
注: calico 默认工作模式是 BGP 的 node-to-node mesh,如果要使用 Route Reflector 需要进行相关配置。
https://docs . projectcalico. org/v3. 4/usage/ routereflector
https://docs. projectcalico.org/v3.2/usage/ routereflector/calico-routereflector
14.4.1 查看 pod 路由走向
验证开启 ipip 和 关闭 ipip 的 K8S 集群验证
calico ipip 模式工作原理:
所谓ipip,也就是IP in IP,即在IP报文的基础上,又封装了一个IP头,和overlay网络相似。
如下图:
如果说 node1 上的 pod 想要访问 node2 上的 pod,那么在 node1 的路由中肯定有去往 node2 的路由表才行,也就是说 node1 会将请求报文发送至 node2 ,当目的主机 node2 拿到报文之后就进行拆封装,拆封发现这个是去往 pod2 的请求报文,最后就会将该报文发送至 pod2 ,并且这里通过 tunl0 的网络模式(ipip)能够实现跨主机访问
14.4.1.1 开启或关闭 ipip
默认情况下 calico 会开启 ipip 隧道模式,开启 ipip 之后会看到在宿主机上面就有对应的 tunl0 网卡,这个就是所谓的隧道负责容器间的通信、会在宿主机上进行报文封装从而实现能够跨网段通信
在创建 calico 的 pod 的时候如需关闭 ipip 模式只需将 always 改为 off
[10:40:15 root@k8s-master ~]#vim calico-etcd.yaml
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
value: "Always" # 如果说将 always 改为 off 就关闭了 ipip 模式
# 如果关闭了 ipip 模式则我们的 pod 就不能实现跨网段通信,关闭之后就会在宿主机上生成对应的 tunl0 网卡
关闭 ipip 之后就会使用 bgp 网络模式,也就是不能跨子网的网络模式
14.4.1.2 验证 ipip 隧道封装
1.查看路由
calico 在 node 上也会维护大量路由规则如下命令
[09:56:49 root@k8s-node2 ~]#route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.0.2 0.0.0.0 UG 0 0 0 eth0
10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
10.10.113.128 10.0.0.130 255.255.255.192 UG 0 0 0 tunl0
10.10.169.128 0.0.0.0 255.255.255.192 U 0 0 0 *
10.10.169.182 0.0.0.0 255.255.255.255 UH 0 0 0 cali6382e723d9e
10.10.169.187 0.0.0.0 255.255.255.255 UH 0 0 0 calic5cef89a6b9
10.10.169.190 0.0.0.0 255.255.255.255 UH 0 0 0 calicfccad17a33
10.10.235.192 10.0.0.131 255.255.255.192 UG 0 0 0 tunl0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
# tunl0 的网卡就是跨主机通讯的路由规则
# 对应的 gateway 就是 node ip ,也就是对应的路由下一跳,host上也多了两条通往node的路由记录
# 但是在上面 255.255.255.192 这个子网就是给对应的 pod 进行使用,如果说后期子网不够 ETCD 就会重新分配
2.查看网卡信息
而且 calico 会在对应 pod 的 node 上生成大量网卡
[09:58:58 root@k8s-node2 ~]#ip a | grep cali
5: calic5cef89a6b9@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
6: cali6382e723d9e@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
7: calicfccad17a33@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default
3.创建pod
# 创建 busybox pod
[10:49:30 root@k8s-master ~]# cat<<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.34
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
4.查看该 pod 详情
# 可以看到当前 pod 分配到了 node 节点上,并且 pod 地址为 10.10.113.175
[10:50:17 root@k8s-master ~]#kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox 1/1 Running 0 56s 10.10.113.175 k8s-node <none> <none>
5.查看对应的 node 路由
# 到 K8S-node 节点上查看路由信息,就会找到一条对应的 路由
[10:52:44 root@k8s-node ~]#route -n | grep 10.10.113.175
Destination Gateway Genmask Flags Metric Ref Use Iface
10.10.113.175 0.0.0.0 255.255.255.255 UH 0 0 0 cali12d4a061371
6.查看不同网段的 pod 信息
# 可以看到 busybox 网段为 10.10.113 而 kube-scheduler-k8s-master 网段为 10.0.0.131
[10:57:17 root@k8s-master ~]#kubectl get pod -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
default busybox 1/1 Running 0 7m50s 10.10.113.175 k8s-node
kube-system kube-scheduler-k8s-master 1/1 Running 34 7d 10.0.0.131 k8s-master
7.进入到 busybox pod 中通过 tarceroute 命令解析 kube-scheduler-k8s-master 的 ip
# 通过 tarceroute 命令解析到 不同网段的 pod
/# traceroute to 10.10.169.182 (10.10.169.182), 30 hops max, 46 byte packets
1 10.0.0.130 (10.0.0.130) 0.014 ms 0.008 ms 0.005 ms
2 10.10.169.128 (10.10.169.128) 0.463 ms 0.517 ms 0.645 ms # 通过在路由表中的 10.10.169.128 tunl0 隧道封装
3 10-10-169-182.metrics-server.kube-system.svc.linux.local (10.10.169.182) 0.563 ms 0.841 ms 1.605 ms # 再到对应的 pod 中
14.4.2 ipip 和 BGP 的区别
ipip 由于需要跨子网所以会被封装一层网络隧道,而 BGP 只能够在同一网段下进行通信
ipip 优点:能够跨越子网,使用场景不受限制
ipip缺点:性能不如 BGP
BGP优点:性能比 IPIP 模式强劲
BGP缺点:由于不能够跨子网所有使用场景受限制