K8S网络原理

概念

Posted by Gavin on January 12, 2020

佳人彩云里

欲赠隔远天

前言

最近在使用K8S集群部署服务和项目时,发现集群网络问题很是复杂,因此想系统了解一下K8S的网络原理。实际使用时发现pod似乎是可以直接使用宿主机网络配置的,但是集群的设置又会影响到各pod,被搞的有些迷糊。

K8S网络模型

K8S集群网络模型的一个基础原则就是:每个pod都拥有一个独立的IP,并且假定所有pod都在同一个扁平的网络空间中,因此所有pod(不管在哪个物理节点上)都可以直接通过IP进行互相访问,因此用户不必额外考虑如何建立pod之间的连接,也不需要考虑将容器端口映射到主机。

K8S集群里,IP是以pod为单位分配的;而在pod中,内部所有容器共享一个网络堆栈(一个网络命名空间,包括IP地址、网络设备、配置等)。此模型叫作IP-per-Pod模型。在pod内部的容器看到的自己的IP和端口与外部所见一致,由此规避NAT进行内外部转换。同时,由于内部的容器共享同一个网络堆栈,因此它们可以通过localhost进行互相访问。

因此K8S网络的要求如下:

  • 所有容器可以不通过NAT进行互相访问
  • 所有节点也可以不通过NAT访问容器
  • 容器地址内外部所见一致

Linux网络基础

Docker技术依赖于Linux内核虚拟化技术,其网络的依赖于此。

  • 网络命名空间
    为了支持网络协议栈的多个实例,Linux在网络栈中引入命名空间,实现对不同协议栈的隔离,两个不同命名空间彼此无法通信,同时也可以拥有独立的路由表、防火墙、NAT等。
  • Veth设备对
    若要使不同的命名空间互相通信,则需要使用Veth设备对,打个比方,Veth设备对就像一根管子,联通两个不同的网络命名空间
  • 网桥
    网桥负责Linux端口之间的多对多通信
  • 路由
    负责转发

Docker网络实现

Docker网络支持4中模式:

  • host模式
  • container模式
  • none模式
  • bridge模式(K8S默认)

在bridge模式下,Docker Daemon第一次启动时会创建一个虚拟网桥docker0,并分配给其一个子网。针对每一个由docker创建的容器,都会创建一个虚拟Veth设备对,一端关联网桥,一端映射到容器内部的eth0设备上。

如上图所示,这么一来,同一节点上的容器之间就可相互通信,不同节点上的容器就得通过宿主机端口的映射才能通信了,哪怕其实它们的网路地址范围相同。

K8S网络实现

K8S面临以下几个场景:

  • 容器与容器之间直接通信

    共享同一网络栈,不需要多做修改,直接使用localhost进行通信
  • pod到pod之间通信
    • 同一node
      通过docker0网桥进行通信
    • 不同node
      需要一个机制发现目标pod在哪个node上,转发过去之后,在分发给对应的虚拟网桥,这就需要网络组件的帮助了
  • pod与service之间的通信
    通过给service分配内部IP和端口实现
  • 集群外部和内部组件通信
    将内部组件映射到物理机端口上