Kubernetes容器网络模型解析

云原生(Cloud Native)可以认为是一套技术体系或生态,它包含2大部分:云(Cloud)和原生(Native)。云(Cloud)表示应用程序位于云中,而不是传统的数据中心;原生(Native)表示应用程序从设计之初即考虑到云的环境,原生为云而设计,在云上以最佳状态运行,充分利用和发挥云平台的弹性和分布式优势。

Kubernetes容器网络模型解析

云原生的代表技术体系包括容器(Container)、服务网格(Service Mesh)、微服务(Microservice)、不可变基础设施和声明式API。本文主要基于容器技术,解析在容器编排生态K8S中的网络流量模型,让大家能够更深刻了解容器技术在云原生生态中的应用与落地。

Kubernetes基于扁平地址空间,非NAT的网络结构,无需在主机和容器之间映射端口。此网络模型的主要特点是消除了在主机和容器之间映射端口的需求。我们先看下其总体架构拓扑模型:

Kubernetes容器网络模型解析

在容器网络中主要涉及以下几个地址:

  • Node Ip:即物理机地址。
  • Pod Ip:Kubernetes的最小部署单元是Pod,一个Pod 可能包含一个或多个容器,简单来讲容器没有自己单独的地址,他们共享Pod 的地址和端口区间。
  • ClusterIp:Service的Ip地址,外部网络无法Ping通改地址,因为它是虚拟IP地址,没有网络设备为这个地址负责,内部实现是使用Iptables规则重新定向到其本地端口,再均衡到后端Pod;只有Kubernetes集群内部访问使用。
  • Public Ip :Service对象在Cluster IP range池中分配到的IP只能在内部访问,适合作为一个应用程序内部的层次。如果这个Service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP。

容器网络流量模型

1、POD内容器间通信

Pod中的容器可以通过“localhost”来互相通信,他们使用同一个网络命名空间,对容器自身来说,hostname就是其Pod的名称。Pod中的所有容器共享同一个IP地址和端口空间,你需要为每个需要接收连接的容器分配不同的端口。也就是说,Pod中的应用需要自己协调端口的使用。

内部实现机制:同Pod内的容器实际共享同一个Namespace,因此使用相同的Ip和Port空间,该Namespace 是由一个叫Pause的小容器来实现,每当一个Pod被创建,那么首先创建一个pause容器,之后这个Pod里面的其他容器通过共享这个pause容器的网络栈,实现外部Pod进行通信,因此对于同Pod里面的所有容器来说,他们看到的网络视图是一样的,我们在容器中看的地址,也就是Pod地址实际是Pause容器的IP地址。总体模型如下:

Kubernetes容器网络模型解析

2、同主机POD间通信

每个节点上的每个Pod都有自己的Namespace,同主机上的Pod之间怎么通信呢?我们可以在两个Pod之间建立Vet Pair进行通信,但如果有多个容器,两两建立Veth 就会非常麻烦,假如有N 个Pod ,那么我们需要创建n(n-1)/2个Veth Pair,扩展性非常差,如果我们可以将这些Veth Pair 连接到一个集中的转发点,由它来统一转发就就会非常便捷,这个集中转发点就是我们常说的Bridge,如下所示

Kubernetes容器网络模型解析

3、跨主机POD间通信

对于网络上两个端点之间的互通目前主要有两种方案:一种是基于Underlay 直接互通,此模式需要双方有彼此的路由信息并且该路由信息在underlay的路径上存在。一种是基于Overlay 方案,通过隧道实现互通。Underlay 层面保证主机可达即可,代表网络方案有 Calico(Direct模式)和Macvlan,后者有Overlay,OVS,Flannel和Weave。本篇仅针对Flannel 和Calico 插件进行简要介绍。

Flannel插件

Flannel是由CoreOS开发的项目,是容器编排系统中最成熟的网络结构示例之一,旨在实现更好的容器间和主机间网络。

与其他方案相比,Flannel相对容易安装和配置。它被打包为单个二进制文件Flanneld,许多常见的Kubernetes集群部署工具和许多Kubernetes发行版都可以默认安装Flannel。Flannel可以使用Kubernetes集群的现有Etcd集群来使用API存储其状态信息,因此不需要专用的数据存储。其工作流程图如下:

Kubernetes容器网络模型解析

基本流程为:

1、地址分配

Flanneld 第一次启动时,从 etcd 获取配置的 Pod 网段信息,为本节点分配一个未使用的地址段,然后创建 flannedl.1 网络接口(也可能是其它名称,如 flannel1 等),flannel 将分配给自己的 Pod 网段信息写入 /run/flannel/docker 文件(不同k8s版本文件名存在差异),docker 后续使用这个文件中的环境变量设置 docker0 网桥,从而使这个地址段为本节点的所有。

2、路由下发

每台主机上,Flannel 运行一个Daemon 进程叫flanneld,它可以在内核中创建路由表。

3、数据面封装

Flannel 知道外层封装地址后,对报文进行封装,源采用自己的物理Ip 地址,目的采用对端的,Vxlan 外层的Udp Port 8472(如果是UDP封装使用8285作为默认目的端口,下文会提到),对端只需监控Port 即可,当改端口收到报文后将报文送到Flannedld 进程,进程将报文送到Flanned 接口接封装,然后查询本地路由表获取目的地址。

Flannel功能内部支持三种不同后端实现,分别是:

  • Host-gw:需要两台host 在同一网段,不支持跨网,因此不适合大规模部署。
  • UDP:不建议使用,除非内核不支持Vxlan 或者Debugg时候使用,已废弃。
  • Vxlan : Vxlan 封装,Flannel 使用Vxlan 技术为各节点创建一个可以互通的 Pod 网络,使用的端口为 Udp 8472(需要开放该端口,如公有云 AWS 等)。

Calico插件

Calico支持3种路由模式:

  • Direct: 路由转发,报文不做封装。
  • Ip-In-Ip:Calico 默认的路由模式,数据面采用Ip封装。
  • Vxlan:vxlan 封装。

本文主要介绍Direct模式,采用软路由建立BGP 宣告容器网段,使得全网所有的Node和网络设备都有到彼此的路由的信息,然后直接通过underlay 转发。Calico实现的总体结构如下:

Kubernetes容器网络模型解析

数据通信的流程为:数据包先从veth设备对另一口发出,到达宿主机上的Cali开头的虚拟网卡上,到达这一头也就到达了宿主机上的网络协议栈,然后查询路由表转发;因为本机通过Bird 和RR 建立Bgp 邻居关系,会将本地的容器地址发送到RR 从而反射到网络其它节点,同样,其它节点的网络地址也会传送到本地,然后由Felix 进程进行管理并下发到路由表中,报文匹配路由规则后正常进行转发即可。至于更为复杂的Iptables规则,因篇幅有限,本次暂不做解析。

4、集群内Service Cluster IP和外部访问

Serice 和外部通信场景实现涉及较多iptables 转发原理,简单介绍如下:

Pod与service通信:Pod间可以直接通过IP地址通信,前提是Pod知道对方的IP。在 Kubernetes集群中,Pod可能会频繁地销毁和创建,也就是说Pod的IP 不是固定的。为了解决这个问题,Service提供了访问Pod的抽象层。无论后端的Pod如何变化,Service都作为稳定的前端对外提供服务。同时,Service还提供了高可用和负载均衡功能,Service负责将请求转 给正确的Pod。

外部通信:无论是Pod的IP还是Service的Cluster IP,它们只能在Kubernetes集群中可见,对集群之外的世界,这些IP都是私有的Kubernetes提供了两种方式让外界能够与Pod通信:

NodePort:Service通过Cluster节点的静态端口对外提供服务,外部可以通过:访问Service。

LoadBalancer:Service利用Cloud Provider提供的Load Balancer对外提供服务,Cloud Provider负责将Load Balancer 的流量导向Service。

未经允许不得转载:VPS服务器 » Kubernetes容器网络模型解析

分享到: 生成海报