Docker (CNM 网络)传统网络模型在应用至日趋势复杂的实际业务场景时必将导致复杂性的几何级数上升,因此Kubernetes 设计了一种网络模型。

  • 他要求所有容器都能够通过一个扁平的网络平面直接进行通信(在同一个IP网络中),无论他们是否允许与集群中的同一节点。
  • 不过,在Kubernetes 集群中,IP地址分配是以Pod对象为单位,而非容器,在同一个Pod内的所有容器共享同一个网络名称空间。

Docker 网络模型主要有三种:Bridge(桥接)、Host(主机)、Container (容器)

  • **Bridge**容器使用桥接模式,对于每个网络接口,容器引擎都会为每个容器都创建一个虚拟以太网设备,一个配置为容器的接口设备,另一个则在节点主机上接入指定的虚拟网桥设备(默认Docker0)
  • **Host**此类容器使用宿主机的网络,它们共享使用Docker 主机的网络以及接口
  • **Container**封闭容器,没有对外的通信的网络接口,而是仅具有I/O接口

Kubernetes 网络插件 (Flannel) 需要在集群上单独部署。

网络模型

网络模型主要解决四类通信需求:

  • Container to Container;容器之间通讯,Pod对象内的各容器共享同一网络名称空间,它通常由构建Pod对象的基础架构容器所提供,彼此之间通过LO接口完成交互
  • Pod to Pod;Pod间通讯;每个Pod对象拥有一个集群全局唯一的地址,并可以直接用于与其他Pod进行通讯,此类通信模型中的通信需求也是Kubernetes的个网络插件需要着力解决的问题,他们的实现由叠加网络模型和路由网络模型等。
  • Service to Pod;Service与Pod间通讯,Service 资源也成为集群网络(Cluster Network),每个Service 对象在此网络中均拥有一个ClusterIP 的固定地址。根据代理模式的不同将其定义为相应节点上的Iptables规则或者ipvs规则,借此完成从Service 的Cluster-IP 与 Pod-IP 之间的报文转发。
  • External to Service ;集群外部的到Pod对象之间的通信,将集群流量引入到节点端口(NodePort)和主机网络(hostNetwork),以及工作于集群级别的nodePort或LoadBalancer 类型的Service 对象,请求流量首先到达负载均衡器,由其调度至某一个工作节点之上,而后在由工作节点的Netfilter组件上的规则调度置某个目标Pod对象。

Pod网络的交互方式

每个Pod对象的基础架构容器均使用一个独立的网络空间,并共享给同一个Pod内的其他容器使用。 每个名称空间均有其专用的独立网络协议栈及其相关的网络接口设备,一个网络接口设备仅属于一个网络名称空间。于是,运行多个Pod必然要求使用多个网络名称空间,也就需要用到多个网络接口设备。 其中一个通用的解决方案是:使用软件实现的伪网络接口及模拟线缆将其连接至物理口。

  • 虚拟网桥:创建一对虚拟以太网接口,一个接入容器内容,另一个留置于根名称空间内并借助于Linux 内核桥接或OpenVSwitch (OVS)关联置真实的物理接口
  • 多路复用:多路复用可以由一个中间网络设备组成,它暴露了多个虚拟接口,可使用数据包转发规则来控制每个数据包转换到的目标接口。
  • 硬件交换:市面上的NIC设备都支持单根I/O虚拟化,他是创建虚拟化设备的一种实现方式。

网络模型 / 网络策略 - 图1

无论哪一种方式应用在容器环境中,其实现过程都需要大量的操作步骤,不过目前Kubernetes 发布了CNI插件来编排网络,以实现Pod及集群网络管理功能的自动化。 需要修改网络配置的时候/etc/cni/net.d 目录中查找CNI JSON 配置文件,然后基于type属性到/opt/cni/bin/中查找相关的插件二进制文件

CNI 网络

Kubernetes 设计了网络模型,但将其实现交给了网络插件。于是,各种解决方案不断涌现,其中主流还是 Flannel网络插件。 CNI 本身只是一个规范,生产还需要特定的实现。目前CNI 插件分为三类:mainmetaipam

  • main 一类的插件主要在于实现某种特定的网络功能
  • meta 一类的插件自身并不提供任何网络功能而是调用其他插件,其中Flannel 就是。
  • ipam 一类的插件自身用于分配IP地址,而不是提供网络实现

Flannel 网络插件

由CoreOS开发的项目Flannel,可能是最直接和最受欢迎的CNI插件。 各Docker 主机在docker0 桥上默认使用同一个子网。

  • 因此不同节点的容器很可能会得到相同的地址,于是跨节点的容器会面临地址冲突的问题!

于是flannel 解决办法是,预留一个网络,例如 10.244.0.0/16,而后自动为每个节点的Docker 容器引擎分配一个子网,例如:10.244.1.0/24 并将其信息保存到etcd持久存储。

  • 如果人为设置多个节点上的docker0桥使用不同的子网也会导致缺乏路由信息无法准确送达。

对于这个问题flannel 有多种不同的处理方法,没一个处理方法就是一个网络模型 1) **VxLan**:Linux 内核3.7.0版本起支持的,flannel的此种后端意味着使用内核中的VxLan 模快封装报文 ,Flannel 默认推荐使用 2) **host-gw**:通过节点上创建到达目标容器地址的路由直接完成报文转发,因此这种方式要求本身都处 于同一个二层网络中,因此不适合大型网络规模,但是有着较好的网络性能。 3) **UDP**:类似VPN,使用UDP 报文封装完成好的隧道转发,其性能比较前两种方式要低很多。

配置参数

为了跟踪各个子网分配信息等,flannel使用etcd 来存储虚拟IP和主机IP之间的映射各个节点上运行的flanneId守护进程负责监视器etcd中的信息并完成报文路由; 默认情况下flannel的配置保存与etcd的建 /coreos.com/network/config之下,可以使用etcd 服务的客户端工具来设定或修改其可用的配置

  1. {
  2. # CIDR 格式的IPv4 网络
  3. "Network":"10.244.0.0/16",
  4. # Ipv4 网络基于指定的掩码切割
  5. "SubnetLen": "24",
  6. # flannel要使用的后端类型
  7. "Backend":{
  8. "Type": "VxLan",
  9. "port": 8472
  10. }
  11. }

VxLan 后端和direct routing

VxLan,全称是Vitual extensible Local Are Network (虚拟可扩展局域网),是VLAN扩展方案的草案,采用的是Mac in UDP 封装方式,是NVo3 (Network Virtualizationover Layer3)中的一种网络虚拟化技术,将虚拟网络的数据帧添加到VxLan首部后,封装在物理网络的UDP报文中,然后以传统的网络通信方式传送该UDP报文,待其到达主机之后,去掉物理层网络报文的头部信息以及VxLan首部,然后将报文交付给目的地终端。

VxLan 技术使得逻辑网络拓扑和物理网络拓扑实现了一定程度的解耦,解决了二层网络广播域分割的问题,提供了多租户的良好支持,,通过VxLan 进行分割,各个租户可以独立组网、通信。但是为了确保VxLan机制通信过程的正确性,涉及VxLAN 通信的IP报文一律不允许分片,这就要求物理网络的链路层中必须提供足够的大的MTU值,或者修改其MTU值以保证VxLAN 报文的顺利传输。

网络模型 / 网络策略 - 图2

传统的VxLan 后端使用隧道网络转发叠加网络的通信报文必回导致不少的流量开销,于是flannel 的VxLan 还支持DirectRouting 模式,他通过添加必要的路由信息使用节点的二层网络直接转送到Pod通信报文,仅在跨IP网络时,才启用传统的隧道方式转发通信流量。

  1. {
  2. "Network":"10.244.0.0/16",
  3. "SubnetLen": "24",
  4. "Backend":{
  5. "Type": "VxLan",
  6. # 启用DirectRouting 模式
  7. "Directrouting": true
  8. }
  9. }

网络模型 / 网络策略 - 图3

host-gw 后端模式

host-gw 后端通过添加必要的路由信息使用节点的二层网络直接发送Pod的通信报文,其工作方式类似于VxLan后端的direct routing 的功能,但不包括其VxLan 的隧道转发能力。

  1. {
  2. "Network":"10.244.0.0/16",
  3. "SubnetLen": "24",
  4. "Backend":{
  5. "Type": "host-gw"
  6. }
  7. }

通常两个容器地址能够通信,那么这两个容器肯定有至少一条可达的路由。 各个节点会生成类似 VxLan diect routing 一样的路由及iptables 规则以实现二层转发Pod 网络的通信报文,省去了隧道转发模式的额外开销;不过对于非同一个二层网络的报文的转发,host-gw 则无能为力

网络模型 / 网络策略 - 图4

网络策略

网络策略(Network Policy)是用于控制分组的Pod资源彼此之间如何进行通讯,以及分组的Pod资源如何与其他网络端点进行通信的规范。 另:Canal 代表了针对云原生应用程序的最佳策略网络解决方案,旨在让用户轻松地将Calico 和Flannel 网络部署在一起作为统一的网络解决方案,将Calico 的网络策略执行Flannel叠加以及非叠加网络连接选项的丰富功能相结合。

  • 配置网络策略

    报文的流入流出的核心组件是Pod资源,因此它们也是网络策功能生效的主要目标, 因此 NetworkPolicy对象也要使用标签选择器事先选择出一组Pod资源作为控制对象。 默认情况下,Pod 对象既可以接受来至任何来源的流量,也能能够向外发出期望的所有流量。当附加网络机制后,Pod 对象因NetworkPolicy 对象的选定额被隔离,spec.policyTypes指定生效的规则类型,却在networkpolicy.spec 字段中嵌套定义了没有任何规则的Ingress 或 Egress 字段时,则表示拒绝相关方向上的流量。

  • 管理入站流量

    以提供服务为主目标的Pod对象通常是请求流量的目标对象,但它们的服务未必应该为所有网络端点所访问。 使用 networkpolicy.spec中嵌套Ingress 字段用于定义入站流量规则;就特定的Pod集合来说,入栈的流量默认处于放行,除非在所有入站流量策略中,至少有一条规则能够明确匹配** 通常情况下默认策略应该设置为拒绝所有流量,仅放行允许的端点的入站流量。**

  • 管理出站流量

    但如果必要对其精细化管理,仅放行那些有对外请求需求的Pod对象的出站流量,则也可为名称空间设置“禁止所有” 默认策略,然后定义“允许” 策略。

  1. apiVersion: networking.k8s.io/v1
  2. kind: NetworkPolicy
  3. metadata:
  4. name: test-network-policy
  5. namespace: default
  6. spec:
  7. podSelector:
  8. matchLabels:
  9. role: db
  10. policyTypes:
  11. - Ingress
  12. - Egress
  13. ingress:
  14. # 入站配置
  15. - from:
  16. - ipBlock:
  17. cidr: 172.17.0.0/16
  18. except:
  19. - 172.17.1.0/24
  20. - namespaceSelector:
  21. matchLabels:
  22. project: myproject
  23. - podSelector:
  24. matchLabels:
  25. role: frontend
  26. ports:
  27. - protocol: TCP
  28. port: 6379
  29. egress:
  30. # 出站配置
  31. - to:
  32. - ipBlock:
  33. cidr: 10.0.0.0/24
  34. # 命名空间
  35. - namespaceSelect:
  36. - key: name
  37. operator: In
  38. values: ["default", "kube-system"]
  39. ports:
  40. - protocol: TCP
  41. port: 5978

Calico

Calico 是一个开源的虚拟化网络方案,用于为云原生应用实现互联网及策略控制。与Flannel 相比,Calico的一个显著优势是对网络策略(network policy)的支持,它允许用户动态自定义ACL 规则控制进出容器的数据报文,实现为Pod间的通信按需施加安全策略。 Calico 简单、高效、易扩展,没有使用额外的报文封装和解封装,简化了网络拓扑图,因此Calico 是高性能的,但是Calico 对公有云可能会对路由方案造成影响,对公有云不够友好,它会写入路由表,这样可能会影响到厂商现有网络

工作特性

Calico 利用Linux 内核在每一个计算机节点上实现了一个高效的vRouter (虚拟路由器)进行转发报文,而每个vRouter 都通过BGP 负责把自身所属的节点上运行的Pod 资源的IP地址信息基于节点的Agent 程序(Felix)直接又vRouter生成路由规则想整个Calico网络内进行传输。

  • 全互联模式(node-to-node mesh) 全互联模式,每一个BGP Speaker都需要和其他BGP Speaker建立BGP连接,这样BGP连接总数就是N^2,如果数量过大会消耗大量连接。如果集群数量超过100台官方不建议使用此种模式。
  • 路由反射模式(Router Reflection)(RR) RR模式 中会指定一个或多个BGP Speaker为RouterReflection,它与网络中其他Speaker建立连接,每个Speaker只要与Router Reflection建立BGP就可以获得全网的路由信息。在calico中可以通过Global Peer实现RR模式。

在小规模上部署可以直接互联,但在大规模网络还是建议使用BGP路由反射(route reflector) 来完成。

Calico 承载的各Pod 资源直接通过vRouter 经由基础网络进行互联,它非叠加、无隧道、不使用VRF表也不依赖NAT,因此每个工作负载都可以直接配置使用公网IP接入互联网。

核心组件

  • Felix:Calico的客户端,跑在每台node节点上,主要负责配置路由及ACLs等信息来确保各Pod之间的连通状态
  • Etcd:分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性;
  • BGPClient:主要负责把Felix写入kernel的路由信息分发到当前Calico网络,确保节点间通信的有效性;
  • BGPRoute Reflector(BIRD,BGP路由反射器):大规模部署时使用,通过一个或者多个BGPRoute Reflector来完成集中式的路由分发。

Calico网络模式

  • IPIP 模式:流量:tunl0设备封装数据,形成隧道承载流量;使用网络类型:适用于互相访问的Pod不在同一个网段中,跨网段访问的场景,外层封装的IP能够解决跨网段的路由问题;效率:流量需要tunl0设备封装,效率略低 ,PS:把 IP 层封装到IP 层的一个 tunnel。作用其实基本上就相当于一个基于IP层的网桥!一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来
  • BGP网络:流量:使用路由信息导向流量; 使用网络类型:适用于互相访问的Pod在同一个网段。效率:原生hostgw,效率高,PS:是互联网上一个核心的去中心化自治路由协议。BGP不使用传统的内部网关协议(IGP)的指标。

1) BGP(border gateway protocol)边界网关路由协议是在自治系统间自动交换无环路的路由信息,通过交换带有自治系统号序列属性的路径可达信息,来构造自治系统的拓扑图,从而消除路由环路并实施用户配置的路由策略。 2) BGP是基于策略的路由协议,其策略通过丰富的路径属性(attributes)进行控制。 3) BGP工作在应用层,在传输层采用可靠的TCP作为传输协议(BGP传输路由的邻居关系建立在可靠的TCP会话的基础之上)。在路径传输方式上,BGP类似于距离矢量路由协议。