网络模型和网络策略

6 篇文章 1 订阅
3 篇文章 2 订阅

pod网络并非kubernetes系统内置的功能,而是有第三方项目以CNI插件方式来完成。进一步来说,除了pod网络管理,有相当一部分CNI网络插件还实现了网络策略,这些插件赋予管理员和用户通过自定义NetworkPolicy资源来管控pod通信能力

容器网络模型

Network、IPC和UTS名称空间隔离技术是容器能否使用独立网络栈的根本,“网络栈”包括了网卡(network interface)、回环设备(loopback device)、路由表(routing table)和iptables规则。对于一个进程来说,这些要素其实构成了其发起和响应网络请求的基本环境。而操作系统的网络设备虚拟化技术是打通各容器间通信并构建起多样化网络拓扑的至关重要因素,在linux系统上,这类的虚拟化设备类型有VETH、Bridge、VLAN、MACVLAN、IPVLAN、MACTV、和TAP/IPVTAP等。这些网络虚拟化相关技术是支撑容器与容器编排系统网络的基础。

可以把每个容器看做一台主机,他们都有一套独立的“网络栈”。如果想时间两台主机之间的通信,最直接的办法就是用一根网线把他们连接起来;而如果想实现多台主机之间的通信,就需要用网线把他们连接到一台交换机上。

Bridge是指linux内核支持的虚拟网桥设备,它模拟的是物理网桥设备,工作于数据链路层,根据习得的MAC地址表向设备端口转发数据帧。虚拟以太网接口设备对(veth pair)是连接虚拟网桥和容器的网络媒介:一端插入到容器的网络栈中,表现为通信接口(例如eth0),另一端则于宿主机上关联虚拟网桥并被降级为当前网桥的“从设备”,失去调用网络协议栈处理数据包的资格,从而表现为桥设备的一个接口
在这里插入图片描述

linux网桥提供的是宿主机内部网络,同一主机上的各容器可基于网桥和ARP协议完成本地通信。而在宿主机上,网桥表现为一个网络接口并可拥有IP地址。于是有宿主机发出的网络包可通过此桥接接口送往连接至同一个桥上的其他容器,如上图所示。这些容器通常需要某种地址分配组件自动配置一个相关网络。
但此私有网络中的容器却无法直接与宿主机之外的其他主机或容器进行通信,通常作为请求方,这些容器需要由宿主机上的iptables借助SNAT机制实现报文转发,而作为服务方时,它们的服务需要宿主机借助于iptables的DNAT规则进行服务暴露。因而,总结起来,配置容器使用Bridge网络的步骤大体有以下几个:

  1. 若补不存在,则需要向在宿主机上添加一个虚拟网桥
  2. 为每个容器配置一个独占的网络名称空间
#查询名称空间
[root@244-master-83 ]# ln -s /var/run/docker/netns  /var/run/netns 
[root@244-master-83 ]# ip netns list
RTNETLINK answers: Invalid argument
RTNETLINK answers: Invalid argument
RTNETLINK answers: Invalid argument
RTNETLINK answers: Invalid argument
RTNETLINK answers: Invalid argument
a47169a2f2ec
RTNETLINK answers: Invalid argument
1038387f7bab
RTNETLINK answers: Invalid argument
4ba484157927
RTNETLINK answers: Invalid argument
fe4d51dd66e8
RTNETLINK answers: Invalid argument
b4df31a131ed
RTNETLINK answers: Invalid argument
a6cac8d04bde
0e808309e387 (id: 25)
343c20af3d16 (id: 26)
a985624429bc (id: 20)
4b9daa8247ba (id: 14)
a8f7f8a9b01d (id: 21)
78f006606e92 (id: 24)
812cb5d80adc (id: 23)
b86ac085b07c (id: 22)
ea2da144ce1a (id: 18)
96fc1dc40ffb (id: 19)
a3ad72c1cd52 (id: 15)
287a6228c7fc (id: 16)
81b17a74a214 (id: 17)
1449d48b5f0c (id: 12)
626d6e1b80d1 (id: 13)
276c6689eb5d (id: 11)
06e9ea7d4ffc (id: 10)
d6281ce2f002 (id: 7)
772eeae4e488 (id: 8)
38cc315f71c8 (id: 9)
51d549a70d4f (id: 4)
default
c00297063c35 (id: 2)
872b030c4246 (id: 6)
0bccd8a61c4e (id: 5)
61ff627ccb6e (id: 3)
e707947f096e (id: 1)
a8563cd93b65 (id: 0)
#要获取Docker容器的PID,可以运行:
docker inspect --format '{{.State.Pid}}' <container_name_or_Id>
#要在容器的网络名称空间内获取命令:
nsenter -t <contanier_pid> -n <command>
#查看容器名称空间
 ls /proc/<contanier_pid>/ns -la
  1. 生成一堆对虚拟以太网接口(如veth pair),将一端插入容器网络名称空间,一端关联至宿主机上的网桥
  2. 为容器分配IP地址,并按需生成必要的NAT
    尽管Bridge模型下各容器使用独立且隔离的网络名称空间,且彼此间能够互联互通,但跨主机的容器通信时,请求报文会首先有源宿主机进行一次SNAT(源地址转换)处理,而后由目标宿主机进行一次DNAT(目标地主转换)处理方可送到目标容器,这种发展的NAT机制将会使得网络通信管理的复杂度随容器规模增呈几何倍数上升,而且基于iptables实现的NAT规则,先限制了解决方案的规模和性能。
    kubernetes系统依然面临着类似的问题,只不过,跨节点的容器通信问题编程了更抽象的pod资源问题。我们知道,kubernetes将具有亲密关系的容器整合成pod作为基础单元并设计了专用网络模型来支撑kubernetes组件间及其他应用程序的通信。这种网络模型基于扁平网络结构,无需将主机端口映射到容器端口便能完成分布式环境中的容器间通信,并负责解决4类通信需求:同一pod 内容器间通信、pod间通信、service到pod间的通信以及集群外部与service之间的通信。
    在这里插入图片描述

一、pod内容器间通信

pod是kubernetes调度的原子单元,其内部的各容器必须运行在同一个节点之上。一个pod资源内的各容器共享同一个网络名称空间,它通常由构建pod对象的基础架构容器parse所提供。因而,同一个pod内运行的多个容器通过lo接口即可在本地内核协议栈上完成交互,如下图中的pod中container1和container2之间的通信,这类事同一主机上的多个进程间的本地通信。
在这里插入图片描述
下面以一个小例子说明,创建一个 Pod 包含两个容器,yaml 文件如下:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: Pod-two-container
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: busybox
        image: busybox
        command:
        - "/bin/sh"
        - "-c"
        - "while true;do echo hello;sleep 1;done"
      - name: nginx
        image: nginx

在这里插入图片描述

创建 1 个 Pod 中包含 2 个 Container,实际会创建 3 个 Container。多出的一个是“Pause”容器。

该 Container 是 Pod 的基础容器,为其他容器提供网络功能。
在这里插入图片描述

查看 Pause 容器的基础信息:
在这里插入图片描述

使用命令 docker inspect 容器 _ID 查看 Nginx 详细信息,其网络命令空间使用了 Pause 容器的命名空间,同样还有进程间通信的命名空间。
在这里插入图片描述

再查看 Busybox,可以发现其网络命令空间使用了 Pause 容器的命名空间,进程通信的命名空间也是 Pause 容器的命名空间。
在这里插入图片描述

实现方式:Nginx 和 Busybox 之所以能够和 Pause 的命名空间连通是因为 Docker 有一个特性:能够在创建时使用指定 Docker 的网络命名空间。

在 Docker 的官网上有一段描述:

https://docs.docker.com/engine/reference/run/

在这里插入图片描述

所以如果要手动完成一个上面的 Pod,可以先创建 Pause,再创建 Nginx 和 Busybox,同时将网络指定为 Pause 的网络命名空间即可。

docker run --name pause mirrorgooglecontainers/pause-amd64:3.1
docker run --name=nginx --network=container:pause  nginx 
docker run --name=busybox --network=container:pause  busybox

上述步骤由 K8S 帮助我们完成,所以 Pod 命名空间应该是这样的:
在这里插入图片描述

二、分布式pod间通信

各pod对象需要运行在同一个平面网络中,每个pod对象拥有一个虚拟网络接口和集群全局唯一的地址,该ip地址可用于直接与其他pod进行通信。另外运行pod的各节点也会通过桥接设备等持有此平面网络中的一个ip地址,如下图中的cni0接口,这意味着node到pod间的通信也可直接在此网络进行通信。因此,pod间的通信或pod到node间的通信类似于同一IP网络中的主机间进行通信。
在这里插入图片描述
kubernetes设计了pod通信模型,但是吧相关功能及编排机制的实现通过kubenet或cni插件api开放给第三方来实现。这些第三方插件要负责为各pod设置虚拟网络接口、分配IP地址并将其接入到容器网络中等各种任务,以实现pod间的直接通信。

三、service与pod间的通信

service资源的专用网络也称为集群网络,需要在启动kube-apiserver时由–service-cluster-ip-range指定,例如默认的10.96.0.0/12,每个service对象在此网络中拥有一个称为Cluster-IP的固定地址。

[root@244-master-83 manifests]# grep --service-cluster-ip-range kube-apiserver.yaml
    - --service-cluster-ip-range=10.96.0.0/12

管理员或用户对service对象的创建或更改操作,会由api server存储完成后触发各节点上的kube-proxy,并根据代理模式的不同将该service对象定义为相应节点上的iptables规则或ipvs规则,pod或接节点客户端对service对象的ip地址的访问请求将由这些iptables或ipvs规则进行调度和转发,从而完成pod与service之间的通信。

iptables 代理模式

这种模式,kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端组合。
在这里插入图片描述

IPVS 代理模式

在 ipvs 模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端Pod之一。

IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

IPVS 提供了更多选项来平衡后端 Pod 的流量。 这些是:

rr:轮替(Round-Robin)
lc:最少链接(Least Connection),即打开链接数量最少者优先
dh:目标地址哈希(Destination Hashing)
sh:源地址哈希(Source Hashing)
sed:最短预期延迟(Shortest Expected Delay)
nq:从不排队(Never Queue)
说明:
要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。

当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。
在这里插入图片描述

四、集群外部与客户端通信

引入集群外部流量到达pod对象有4种方式,有两张是基于本地节点 的端口(hostPort)或根网络名称空间(hostNetwork),另外两种则是基于工作在集群级别的NodePort或LoadBalancer类型的Service对象。不过即便是4层代理的模式也要经由两级转发才能到达目标pod资源:请求流量首先到达外部负载均衡器,由其调度到某个工作节点之上,而后再由工作节点的netfilter(kube-proxy)组件上的规则(iptables或ipvs)调度至某个目标pod对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值