kubernetes网络通信原理

Kuberners的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中,这在GCE(Google Compute Engine) 里面是现成的网络模型,Kubernets假定这个网络已经存在。

而在私有云里搭建Kubernets集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不通节点上的Docker容器之间的互相访问先打通,然后运行kubernetes

一、Kubernetes网络模型

在Kubernetes网络中存在两种IP(Pod IP和Service Cluster IP),Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,Service Cluster IP它是一个虚拟IP,是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。下面讲讲Kubernetes Pod网络设计模型:

1、基本原则:

每个Pod都拥有一个独立的IP地址(IPper Pod),而且假定所有的pod都在一个可以直接连通的、扁平的网络空间中。

2、设计原因:

用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑将容器端口映射到主机端口等问题。

3、网络要求:

所有的容器都可以在不用NAT的方式下同别的容器通讯;所有节点都可在不用NAT的方式下同所有容器通讯;容器的地址和别人看到的地址是同一个地址。

二、Kubernetes网络基础

访问场景:

1、同一个Pod内的多个容器之间的访问

第一种通信     Pod内容器之间的通信   ,其中图中有三个网卡,  包括两个eth0 和一个 docker0,  第一个eth0是 用作于pod的虚拟网卡,  第二个eth0是物理机的真实网卡,Docker0就是 第一个eth0虚拟IP的 网关,    这容器1与容器2 访问的过程中,只需要eth0内部完成, 不涉及docker0 和 eth0   ,因为一个 Pod内部的所有容器通过 pause容器共享同一个网络命名空间,包括它们的 IP地址、网络设备、配置等都是共享的,所以它们之间的访问可以用localhost地址 + 容器端口就可以访问。和docker0 以及  物理网卡是没有交互的。

这里说一下pause容器,Kubernetes中,pause容器是pod中所有容器的父容器,运行了一个非常简单的进程,它不执行任何函数,本质上永远休眠。

首先,在 pod 中共享 Linux 名称空间。
其次,它将作为每个 pod PID 1 进程(根进程),并回收僵尸进程。
这是 pasuse 进程的一个原理。

 

那如果两个pod在同一个宿主机上 ,如何访问呢?

2、同一Node中Pod间通信:

这这张图上   node1上 运行了 pod1 pod2 ,  地址分别是IP1  IP2

同一NodePod的默认路由都是docker0的地址,由于它们关联在同一个docker0网桥上,IP1IP2都是从docker0网段上动态获取的,它们之间可以通过docker0作为路由量进行通信,

所以理所应当是能直接通信的。而且不需要使用DNSetcd这种其他的发现机制 去 辅助通信

 

 3、不同Node中Pod间通信:

基于以上两种网络访问场景,我们知道  Pod之间要想实现访问  必须是 通过Pod IP进行通信的,PodIP地址是由各Node上的docker0网桥动态分配的。

因为不同Node之间的通信只能通过Node的物理网卡进行。我们想要实现跨NodePod之间的通信,至少需要满足下面三个条件:

1、知道Pod IP Node IP之间的映射关系

2在整个集群中对PodIP分配不能出现冲突;

3pod发起的数据包一层一层的正确的转发最终到达目的pod IP

那这三个条件如何实现呢?

Kubernetes会记录所有正在运行的PodIP分配信息,并将这些信息保存到etcd中(作为ServiceEndpoint),这样我们就可以知道Pod
IP
Node IP之间的映射关系。

那既然etcd已经记录了IP地址的分配信息,那自然不会出现的重复现象了,我只会把没有分配过的地址给到新的podOK ,那第三条件,我们应该如何实现呢?

其实就是加了一层二次封装。后面我会以flanel插件为例详细为大家讲解 条件三的实现方式、

 

  4、Pod与Service之间的通信:

       

首先Client 管理员或用户 对Service对象的创建或更改操作,后提交到API Server存储、 完成后触发各节点上的kube-proxy

并根据代理模式的不同将其定义为相应节点上的iptables规则或ipvs规则,借此完成从ServicePod-IP之间的报文转发

 这里我们在生产环境中部署2副本的nginx deployment pod,

创建一个clusterip的service

 我们随便登陆一台node节点上查看ipvs规则,可以看到 10.244.184.123的80端口作为外部提供服务,使用轮训的负载均衡方式代理后端的 2个endpoint  10.244.1.9 和10.244.2.13的80端口

 K8S网络的访问 具体是怎么实现的呢?我接下来我们讲一下 CNI

三、网络插件CNI

1. Kubernetes 设计了网络模型,但将其实现交给了网络插件。于是,各种解决方案不断涌现。为了规范及兼容各种解决方案, CoreOS Google 联合制定了 CNI Container Network Interface )标准,旨在定义容器网络模型规范。
2. 它连接了两个组件:容器管理系统和网络插件。它们之间通过 JSON 格式的文件进行通信,以实现容器的网络功能。具体的工作均由插件来实现,包括创建容器 netns 、关联网络接口到对应的 netns 以及为网络接口分配 IP 等。
3. CNI 的基本思想是:容器运行时环境在创建容器时,先创建好网络名称空间( netns ),然后调用 CNI 插件为这个 netns 配置网络,而后再启动容器内的进程。
4. 常用插件
Flannel (简单、使用居多):基于 Vxlan 技术(叠加网络 + 二层隧道),不支持网络策略
Calico (较复杂,使用率少于 Flannel ):也可以支持隧道网络,但是是三层隧道( IPIP ),支持网络策略
Calico 项目既能够独立地为 Kubernetes 集群提供网络解决方案和网络策略,也能与 flannel 结合在一起,由 flannel 提供网络解决方案,而 Calico 此时仅用于提供网络策略,这时我们也可以将 Calico 称为 Canal

Flannel插件

Flannel是Centos团队针对Kubernets设计的一个网络规划服务,简单的说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群中唯一的虚拟IP地址,而且它还能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络将数据包原封不动的传到目标容器内

这里有两台物理机,一个是192.168.66.11 一个是12 ,那这里运行了4pod,一个是 app1  app2  app3  前端组件    backend作为后端,那他们的结构 就  前端提交请求

向后端获取数据,好,那就意味着 web app2 想要跟 backend 通训的时候,就需要跨主机了,

1、首先flanneld作为守护进程运行在每个Node节点之上,监听端口用于接受和转发数据包,那这个flanel进程一旦启动以后会开启一个Flannel0的网桥用于收集Docker0网桥转发的数据报文

1、当请求开始后,webapp2发送数据报文的源地址为10.1.15.2,目标地址为10.1.20.3,因为目标地址与源地址不是同一个网段,于是请求报文发往Docker0网桥

2Docker0上会有钩子函数把数据包抓到Flannel0网桥,并从etcd中获取路由表,判断数据包被发送往哪台目的机器。

3、到Flannel0网桥以后,因为flannel0是由Flanneld守护进程开启,所以数据报文被传到Flanneld后进行UDP协议封装、怎么封装呢?

有这么一个结构:

Mac地址部分,然后是下一层  源目IP,下一层是udp封装,也就意味着flanned它使用的是udp的数据报文去转发数据的!因为UDP协议不需要三次握手,更快。

下一层是内部ip,封装到这一层以后外面再加一层 数据包实体,数据包就被物理机转发到对端的物理机网卡,端口应该是flanneld的端口,所以会被flanned截获,

拆封完了以后  这个数据包线路和11宿主机的数据包线路反过来, 会转发到   flannel0   docker0  backend,并且 报文是二次解封的,docker0是看不到outerip层的数据,只能看到interip这一层信息,

所以它得到的 是 10.1.15.2的源IP发过来的 ,目标找的就是我自己    那这样的话 就可以完成了跨主机的pod访问。

其实这里的资源消耗还是比较高的,首先在flanned这里进行二次封装,解封装。这就是flanned的网络通信解决方案

Calico插件

Calico 是一套开源的网络及安全方案,用于容器和宿主机之前的网络连接,可以用在kubernetes、OpenShiftPaaS平台上。

实际上,Calico 项目提供的 BGP 网络解决方案,与 Flannel host-gw 模式几乎一样。

也就是说,Calico也是基于路由表实现容器数据包转发,但不同于Flannel使用flanneld进程来维护路由信息的做法,而Calico项目使用BGP协议来自动维护整个集群的路由信息

Calico网络模型主要工作组件:

1FelixFelix会监听ECTD中心的存储,从它获取事件,比如说用户在这台机器上加了一个IP,或者是创建了一个容器等。用户创建pod后,Felix负责将其网卡、IPMAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔离策略,Felix同样会将该策略创建到ACL中,以实现隔离。

也就是说 felix主要的功能有接口管理、路由规则、ACL规则和状态报告等

2etcd:分布式键值存储,主要负责数据一致性的数据库,存储集群中节点的所有路由信息。为保证数据的可靠和容错建议至少三个以上etcd节点

3BGP ClientBIRD):BIRD是一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,你们路由的时候得到这里来,从而实现网络互通。

4. BGP Route Reflector :使所有 BIRD 仅与特定 RR 节点互联并做路由同步,减少连接数  扩大集群规模。 

由于Calico是一种纯三层的实现,中间没有任何的NAToverlay,所以它的转发效率可能是所有方案中最高的,因为它的包直接走原生TCP/IP的协议栈。

提供了一整套的防火墙的规则,所以它可以通过IPTABLES的规则达到比较复杂的隔离逻辑。

Calico插件类型之IPIP模式

 


从字面来理解,就是把一个IP数据包又套在一个IP包里,即把 IP 层封装到 IP 层的一个 tunnel。它的作用其实基本上就相当于一个基于IP层的网桥!

一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来。

 Calico插件类型之BGP模式


边界网关协议(Border Gateway Protocol, BGP)是互联网上一个核心的去中心化自治路由协议。它通过维护IP路由表或‘前缀’表来实现自治系统(AS)之间的可达性

全互联模式(node-to-node mesh)

全互联模式,每一个BGP Speaker都需要和其他BGP Speaker建立BGP连接,这样BGP连接总数就是N^2,如果数量过大会消耗大量连接。如果集群数量超过100台官方不建议使用此种模式。

路由反射模式Router ReflectionRR

RR模式 中会指定一个或多个BGP SpeakerRouterReflection,它与网络中其他Speaker建立连接,每个Speaker只要与Router Reflection建立BGP就可以获得全网的路由信息。在calico中可以通过Global Peer实现RR模式。

四、网络策略

Network Policykubernetes中的一种资源类型,它从属于某个namespace

两个关键部分:

-POD选择器 

- 规则

网络策略包含两个关键部分,一是pod选择器,基于标签选择相同namespace下的pod,将其中定义的规则作用于选中的pod

另一个就是规则了,就是网络流量进出pod的规则,其采用的是白名单模式,符合规则的通过,不符合规则的拒绝。

Ingress (类似安全组的内外网入方向):能接受哪些客户端的访问( -from ports :自己端口)
egress (类似安全组的内外网出方向):能访问哪些目标( -to ports :目标端口)
每种方向的控制策略则包含“允许”和“禁止”两种。默认情况下, Pod 处于非隔离状态,它们的流量可以自由来去。

对象创建方法与其它如ReplicaSet相同。apiVersion、kind、metadata与其它类型对象含义相同

.spec.PodSelector 顾名思义,这个就是我要选择什么属性的pod

.spec.PolicyTypes Ingress是是入pod的规则,Egress是出pod的规则。

本字段可以看作是一个开关,如果其中包含Ingress,则Ingress部分定义的规则生效,如果是EgressEgress部分定义的规则生效,如果都包含则全部生效。如果没有指定的话,则默认Ingress生效。

例子中ingressegress都只包含一条规则,两者都是数组,可以包含多条规则。当包含多条时,条目之间的逻辑关系是“或”,只要匹配其中一条就可以。

那我们来看看这个最终达成的效果就是:

网段172.17.0.0/16】中 带有project: myproject标签的namesapce下的 带有 role: frontend标签的所有pod   可以正常访问default命名空间下所有带有role=db标签的pod6379端口,但172.17.1.0/24 不能访问

default命名空间下所有带有role=db标签的pod   可以正常访问 【10.0.0.0/24网段下的 所有pod5978端口

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值