《Kubernetes权威指南》——网络原理

1 Kubernetes网络模型

基本原则:每一个Pod都拥有一个独立IP,并且假定全部Pod都在一个能够直接连通的、扁平的网络空间中。node

  • 基于基本原则,用户不须要额外考虑如何创建Pod之间的链接,也不须要考虑容器端口映射到主机端口等问题
  • 同一个Pod内部的全部容器共享一个网络堆栈即网络命名空间,Pod内的全部容器的端口是共享的
  • Kubernetes对集群网络要求:
    • 全部容器均可以在不用NAT的方式下同别的容器通讯
    • 全部节点均可以在不用NAT的方式下同全部容器通讯,反之亦然
    • 容器的地址和别人看到的地址是同一个

2 Docker的网络基础

2.1 网络命名空间

  • Linux在网络栈中引入网络命名空间(Network Namespace)为了支持网络协议栈的多个实例,处于不一样命名空间的网络栈是彻底隔离的
  • Linux的网络命名空间内能够有本身独立的路由表及独立的Iptables/Netfilter设置来提供转发、NAT及IP包过滤等功能
  • 须要归入命名空间的元素有进程、套接字、网络设备等

2.1.1 网络命名空间的实现

  • linux实现网络命名空间的核心是让网络栈的全局变量变成一个Net Namespace变量的成员,而后协议栈的函数调用加入一个Namespace的参数
  • 网络空间链表链接全部网络空间,全部网络栈变量都放入到网络空间
  • 全部的网络设置都只能属于一个命名空间,一般物理设置只能关联到root这个命名空间
  • 网络命名空间表明是一个独立的协议栈,因此他们之间是相互隔离的彼此没法通讯协议栈内部看不到对方

2.1.2 网络命名空间的操做

使用iproute2系列配置工具中的ip命令操做linux

ip netns add <name>     #建立一个命名空间

ip netns exec <name> <command>  #在命名空间内执行命令

ip netns exec <name> bash   #执行多个命令先进入sh

2.2 Veth设备对

Veth设备都是成对出现的,能够实现不一样网络命名空间之间进行通讯算法

  • 在Veth设置的一端发送数据时它会将数据直接发送到另外一端,并触发另外一端的接收操做

2.2.1 Veth操做命令

ip link add veth0 type veth peer name veth1     #建立veth设备对

ip link show    #查看全部网络接口

ip link set veth1 netns netns1  #将veth1挂载到netns1命名空间下

ip link set dev veth1 up    #启动veth1设备

2.2.2 Veth设备对如何查看对端

使用ethtool工具查看docker

ip netns exec netns1 ethtool -S veth1   #查询netns1下的veth1的对端,看peer_ifindex

ip netns exec netns2 ip link    #查看peer_ifindex对应的值

2.3 网桥

  • 网桥是一个二层网络设备,能够解析收发报文,读取目标MAC地址信息和本身记录的MAC表结合,来决策报文转发端口
  • Linux中多网卡能够经过网桥提供这些设备之间相互转发数据
  • 网桥处理转发和丢弃报文外还能够将报文发送到上层(网络层)

2.3.1 Linux网桥的实现

  • Linux内核经过一个虚拟网桥设备(Net Device)来实现桥接,其能够绑定若干个以太网接口设备,从而将它们桥接起来
  • Net Device能够有一个IP

3 Docker的网络实现

docker的4类网络模式:后端

1. host
2. container
3. none
4. bridge,默认设置

只介绍bridge模式bash

  • Docker Daemon第一次启动时将建立一个虚拟网桥默认名为docker0,同时给其分配一个子网
  • 针对Docker中的容器都会建立一个Veth设备对,一端关联网桥一端使用Linux的网络命名空间映射到容器内的eth0设备,而后从网桥的地址段内给eth0分配一个IP
  • 为了让容器跨主机通讯就必须在主机的地址上分配端口,而后经过这个端口路由或代理到容器上

4 Kubernetes的网络实现

4.1 容器到容器的通讯

  • 同一个Pod内的容器共享同一个网络命名空间,直接使用localhost便可

4.2 Pod之间的通讯

  • 每一个Pod都有一个真实的全局IP,每一个Node内的不一样Pod之间能够直接采用对方Pod的Ip通讯

4.2.1 同一Node内Pod通讯

  • 同一Node内的Pod经过Veth设备对链接到同一个docker0网桥上,Pod的IP也都是该网桥分配的
  • Pod内的默认路由都是docker0的地址,全部数据都经过docker0转发

4.2.2 不一样Node的Pod通讯

  • Pod的地址是与docker0在同一个网段内,而docker0网段与宿主机网卡的IP网段彻底不一样,而通讯只能走宿主机的网卡,所以通讯必须经过宿主机IP来进行寻址和通讯
  • Kubernetes会记录全部正在运行Pod的IP分配信息,并将其写入etcd做为Service的Endpoint
  • 支持不一样Node之间Pod的通讯条件:
    • 整个Kubernetes集群中Pod的IP不能冲突
    • 能将Pod的IP与Node的IP关联起来,经过这个关联实现相互访问
  • 解决:
    • Kubernetes部署时多docker0的IP地址进行规划保证每一个Node上的docker0地址不冲突
    • 通讯时先找到Node的IP将数据发送到这个网卡上,而后让宿主机将相应数据转到具体docker0上

4.3 Pod到Service的通讯

  • k8s在建立服务时为服务分配一个虚拟IP,客户端经过该IP访问服务,服务则负责将请求转发到后端Pod上
  • Service是经过kube-proxy服务进程实现,该进程在每一个Node上均运行能够看做一个透明代理兼负载均衡器
  • 对每一个TCP类型Service,kube-proxy都会在本地Node上创建一个SocketServer来负责接受请求,而后均匀发送到后端Pod默认采用Round Robin负载均衡算法
  • Service的Cluster IP与NodePort等概念是kube-proxy经过Iptables的NAT转换实现,kube-proxy进程动态建立与Service相关的Iptables规则
  • kube-proxy经过查询和监听API Server中Service与Endpoints的变化来实现其主要功能,包括为新建立的Service打开一个本地代理对象,接收请求针对针对发生变化的Service列表,kube-proxy会逐个处理,处理流程:
    • 若是该Service没设置ClusterIP,则不作处理,不然获取该Service的全部端口定义列表
    • 逐个读取端口定义列表,根据端口名、Service名和Namespace对其进行修改
    • 更新负载均衡组件中对应Service的转发Service的转发地址列表
    • 对于已删除的Service则进行清理

5 开源的网络组件

  • Kubernetes的网络模型假定全部Pod都在一个能够直接连通的扁平网络空间,所以须要对网络进行设置
  • 目前常见的模型有Flunnel、Open vSwitch及直接路由的方式
相关文章
相关标签/搜索