NetworkPolicy
一、基础网路
Kubernetes网络模型设计的一个基础原则是:每个Pod都拥有一个独立的IP地址,并假定所有Pod都在一个可以直接连通的、扁平的网络空间中。所以不管它们是否运行在同一个Node(宿主机)中,都要求它们可以直接通过对方的IP进行访问。设计这个原则的原因是,用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑如何将容器端口映射到主机端口等问题。
Linux在网络栈中引入了网络命名空间,这些独立的协议栈被隔离到不同的命名空间中。处于不同命名空间中的网络栈是完全隔离的,彼此之间无法通信。通过对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境。Docker正是利用了网络的命名空间特性,实现了不同容器之间的网络隔离。
Linux系统包含一个完整的路由功能。当IP层在处理数据发送或者转发时,会使用路由表来决定发往哪里。在通常情况下,如果主机与目的主机直接相连,那么主机可以直接发送IP报文到目的主机,这个过程比较简单。例如,通过点对点的链接或网络共享,如果主机与目的主机没有直接相连,那么主机会将IP报文发送给默认的路由器,然后由路由器来决定往哪里发送IP报文。
路由功能由IP层维护的一张路由表来实现。当主机收到数据报文时,它用此表来决策接下来应该做什么操作。当从网络侧接收到数据报文时,IP层首先会检查报文的IP地址是否与主机自身的地址相同。如果数据报文中的IP地址是主机自身的地址,那么报文将被发送到传输层相应的协议中。如果报文中的IP地址不是主机自身的地址,并且主机配置了路由功能,那么报文将被转发,否则报文将被丢弃。
路由表中的数据一般是以条目形式存在的。一个典型的路由表条目通常包含以下主要的条目项。
(1)目的IP地址:此字段表示目标的IP地址。这个IP地址可以是某主机的地址,也可以是一个网络地址。如果这个条目包含的是一个主机地址,那么它的主机ID将被标记为非零;如果这个条目包含的是一个网络地址,那么它的主机ID将被标记为零。
(2)下一个路由器的IP地址:这里采用“下一个”的说法,是因为下一个路由器并不总是最终的目的路由器,它很可能是一个中间路由器。条目给出的下一个路由器的地址用来转发在相应接口接收到的IP数据报文。
(3)标志:这个字段提供了另一组重要信息,例如,目的IP地址是一个主机地址还是一个网络地址。此外,从标志中可以得知下一个路由器是一个真实路由器还是一个直接相连的接口。
(4)网络接口规范:为一些数据报文的网络接口规范,该规范将与报文一起被转发。
在通过路由表转发时,如果任何条目的第1个字段完全匹配目的IP地址(主机)或部分匹配条目的IP地址(网络),那么它将指示下一个路由器的IP地址。这是一个重要的信息,因为这些信息直接告诉主机(具备路由功能的)数据包应该被转发到哪个路由器。而条目中的所有其他字段将提供更多的辅助信息来为路由转发做决定。
查看路由表
[root@k8s-master01 config]#ip route show table local type local
local 10.1.2.21 dev ens160 proto kernel scope host src 10.1.2.21
local 10.96.0.1 dev kube-ipvs0 proto kernel scope host src 10.96.0.1
local 10.96.0.10 dev kube-ipvs0 proto kernel scope host src 10.96.0.10
local 10.96.4.191 dev kube-ipvs0 proto kernel scope host src 10.96.4.191
local 10.96.5.219 dev kube-ipvs0 proto kernel scope host src 10.96.5.219
local 10.96.8.233 dev kube-ipvs0 proto kernel scope host src 10.96.8.233
local 10.96.16.42 dev kube-ipvs0 proto kernel scope host src 10.96.16.42
local 10.96.20.101 dev kube-ipvs0 proto kernel scope host src 10.96.20.101
local 10.96.26.89 dev kube-ipvs0 proto kernel scope host src 10.96.26.89
local 10.96.26.90 dev kube-ipvs0 proto kernel scope host src 10.96.26.90
local 10.96.40.158 dev kube-ipvs0 proto kernel scope host src 10.96.40.158
local 10.96.41.143 dev kube-ipvs0 proto kernel scope host src 10.96.41.143
local 10.96.43.227 dev kube-ipvs0 proto kernel scope host src 10.96.43.227
local 10.96.44.6 dev kube-ipvs0 proto kernel scope host src 10.96.44.6
local 10.96.49.49 dev kube-ipvs0 proto kernel scope host src 10.96.49.49
local 10.96.51.158 dev kube-ipvs0 proto kernel scope host src 10.96.51.158
local 10.96.54.208 dev kube-ipvs0 proto kernel scope host src 10.96.54.208
local 10.96.57.40 dev kube-ipvs0 proto kernel scope host src 10.96.57.40
local 10.96.82.18 dev kube-ipvs0 proto kernel scope host src 10.96.82.18
local 10.96.86.174 dev kube-ipvs0 proto kernel scope host src 10.96.86.174
local 10.96.107.17 dev kube-ipvs0 proto kernel scope host src 10.96.107.17
local 10.96.107.142 dev kube-ipvs0 proto kernel scope host src 10.96.107.142
local 10.96.130.60 dev kube-ipvs0 proto kernel scope host src 10.96.130.60
local 10.96.142.27 dev kube-ipvs0 proto kernel scope host src 10.96.142.27
local 10.96.149.137 dev kube-ipvs0 proto kernel scope host src 10.96.149.137
local 10.96.164.40 dev kube-ipvs0 proto kernel scope host src 10.96.164.40
local 10.96.165.97 dev kube-ipvs0 proto kernel scope host src 10.96.165.97
local 10.96.167.19 dev kube-ipvs0 proto kernel scope host src 10.96.167.19
local 10.96.169.66 dev kube-ipvs0 proto kernel scope host src 10.96.169.66
local 10.96.193.178 dev kube-ipvs0 proto kernel scope host src 10.96.193.178
local 10.96.197.180 dev kube-ipvs0 proto kernel scope host src 10.96.197.180
local 10.96.213.58 dev kube-ipvs0 proto kernel scope host src 10.96.213.58
local 10.96.215.96 dev kube-ipvs0 proto kernel scope host src 10.96.215.96
local 10.96.226.93 dev kube-ipvs0 proto kernel scope host src 10.96.226.93
local 10.96.234.147 dev kube-ipvs0 proto kernel scope host src 10.96.234.147
local 10.96.247.97 dev kube-ipvs0 proto kernel scope host src 10.96.247.97
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
local 172.16.32.128 dev tunl0 proto kernel scope host src 172.16.32.128
local 172.17.0.1 dev docker0 proto kernel scope host src 172.17.0.1
local 192.168.122.1 dev virbr0 proto kernel scope host src 192.168.122.1
二、Docker网络
标准的Docker支持以下4类网络模式。
- ◎ host模式:使用–net=host指定。
- ◎ container模式:使用–net=container:NAME_or_ID指定。
- ◎ none模式:使用–net=none指定。
- ◎ bridge模式:使用–net=bridge指定,为默认设置。
在Kubernetes管理模式下通常只会使用bridge模式,所以本节只介绍Docker在bridge模式下是如何支持网络的。
在bridge模式下,Docker Daemon首次启动时会创建一个虚拟网桥,默认的名称是docker0,然后按照RPC1918的模型在私有网络空间中给这个网桥分配一个子网。针对由Docker创建的每一个容器,都会创建一个虚拟以太网设备(Veth设备对),其中一端关联到网桥上,另一端使用Linux的网络命名空间技术映射到容器内的eth0设备,然后在网桥的地址段内给eth0接口分配一个IP地址。
其中ip1是网桥的IP地址,Docker Daemon会在几个备选地址段里给它选一个地址,通常是以172开头的一个地址,这个地址和主机的IP地址是不重叠的。ip2是Docker在启动容器时在这个地址段选择的一个没有使用的IP地址。
启动后,Docker还将Veth设备对的名称映射到eth0网络接口。ip3就是主机的网卡地址。
在一般情况下,ip1、ip2和ip3是不同的IP段,所以在默认不做任何特殊配置的情况下,在外部是看不到ip1和ip2的。
三、Kubernetes网络
同一个Pod内的容器(Pod内的容器是不会跨宿主机的)共享同一个网络命名空间,共享同一个Linux协议栈。所以对于网络的各类操作,就和它们在同一台机器上一样,它们甚至可以用localhost地址访问彼此的端口。
1. 容器到容器通信
容器1和容器2共享一个网络的命名空间,共享一个命名空间的结果就是它们好像在一台机器上运行,它们打开的端口不会有冲突,可以直接使用Linux的本地IPC进行通信(例如消息队列或者管道)。其实,这和传统的一组普通程序运行的环境是完全一样的,传统程序不需要针对网络做特别的修改就可以移植,它们之间的相互访问只需使用localhost就可以。
2. Pod到Pod之间通信
每一个Pod都有一个真实的全局IP地址,同一个Node内的不同Pod之间可以直接采用对方Pod的IP地址通信,而且不需要采用其他发现机制,例如DNS、Consul或者etcd。
Pod容器既有可能在同一个Node上运行,也有可能在不同的Node上运行,所以通信也分为两类:同一个Node上Pod之间的通信和不同Node上Pod之间的通信。
1.同一个Node上Pod之间的通信
Pod1和Pod2都是通过Veth连接到同一个docker0网桥的,它们的IP地址IP1、IP2都是从docker0的网段上动态获取的,和网桥本身的IP3属于同一个网段。
另外,在Pod1、Pod2的Linux协议栈上,默认路由都是docker0的地址,也就是说所有非本地地址的网络数据,都会被默认发送到docker0网桥上,由docker0网桥直接中转。
综上所述,由于它们都关联在同一个docker0网桥上,地址段相同,所以它们之间是能直接通信的。
2.不同Node上Pod之间的通信
Pod中的数据在发出时,需要有一个机制能够知道对方Pod的IP地址挂在哪个具体的Node上。也就是说,先要找到Node对应宿主机的IP地址,将数据发送到这个宿主机的网卡,然后在宿主机上将相应的数据转发到具体的docker0上。一旦数据到达宿主机Node,那个Node内部的docker0便知道如何将数据发送到Pod了。
IP1对应的是Pod1,IP2对应的是Pod2,Pod1在访问Pod2时,首先要将数据从源Node的eth0发送出去,找到并到达Node2的eth0,即先是从IP3到IP4的传送,之后才是从IP4到IP2的传送。
四、Calico网络插件
Calico是一个基于BGP的纯三层的网络方案,与OpenStack、Kubernetes、AWS、GCE等云平台都能够良好地集成。Calico在每个计算节点都利用Linux Kernel实现了一个高效的vRouter来负责数据转发。
每个vRouter都通过BGP1协议把在本节点上运行的容器的路由信息向整个Calico网络广播,并自动设置到达其他节点的路由转发规则。Calico保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用数据中心的网络结构(L2或者L3),不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。
Calico的主要组件如下:
- ◎ Felix:Calico Agent,运行在每个Node上,负责为容器设置网络资源(IP地址、路由规则、iptables规则等),保证跨主机容器网络互通。
- ◎ etcd:Calico使用的后端存储。
- ◎ BGP Client:负责把Felix在各Node上设置的路由信息通过BGP广播到Calico网络。
- ◎ Route Reflector:通过一个或者多个BGP Route Reflector完成大规模集群的分级路由分发。
- ◎ CalicoCtl:Calico命令行管理工具。
查看已经部署的pod
[root@k8s-master01 config