了解 k8s 网络基础知识

了解

Docker 网络模式

在使用 Docker run 创建 Docker 容器时,可以使用 --net 选项指定容器的网络模式,Docker 可以有4种网络模式。

  1. host 模式。--net=host 指定和宿主机共用一个 NetWork Namespace,容器中的网络环境(ip 地址、路由等)和宿主机的网络环境一致。
  2. none 模式。使用 --net=none 指定关闭网络功能。
  3. bridge 模式。--net=bridge 指定默认设置,容器使用独立的 Network Namespace,并连接到 Docker0 虚拟网桥,通过 iptables nat 表配置和宿主机进行通信。
  4. container 模式,--net=container:NAME_or_ID 指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡、配置IP,而是和一个指定的容器共享IP、端口范围等等。

Flannel 支持三种后端实现,分别是:VXLAN、host-gw、UDP。

理解容器 "跨主通信" 的原理,从 Flannel 插件讲起

第一种:UDP 模式

Flannel 的 UDP 模式,该模式是 Flannel 最原始使用解决容器跨主机网络的实现方法之一。

栗子:

  • 宿主机 Node 1 上有一个容器 container-1,它的 IP 地址是 100.96.1.2,对应的 docker0 网桥的地址是:100.96.1.1/24。
  • 宿主机 Node 2 上有一个容器 container-2,它的 IP 地址是 100.96.2.3,对应的 docker0 网桥的地址是:100.96.2.1/24。

现在的任务,就是让 container-1 访问 container-2。

flanneld 在收到 container-1 发给 container-2 的 IP 包之后,就会把这个 IP 包直接封装在一个 UDP 包里,然后发送给 Node 2。不难理解,这个 UDP 包的源地址,就是 flanneld 所在的 Node 1 的地址,而目的地址,则是 container-2 所在的宿主机 Node 2 的地址。

第二种:VXLAN 模式(虚拟可扩展局域网)

Agenda

k8s NetWork Components

  • Pod NetWorking within and between nodes
  • Service abstractions (service registraton & discovery)
  • DNS
  • Ingress (L7 HTTP routing)
  • NetWork Policies access control (Application "Firewall")

二层网络:假如两个 Pod 的IP 地址分为为 10.170.2.2 和 10.170.2.3 它们的网断都是相同的,叫 二层网络通信。

三层网络:两个 Pod 的IP 地址分为为 10.170.2.2 和 10.170.3.2 不同网断或者说跨网卡通信的叫三层

假设两个 Pod 的IP 地址分为为 10.170.2.2 和 10.170.3.2 ,网段不同但是属于一个网卡,怎么解决它们之间通信呢,可以使用 VXLAN 的解决方案,他可以在三层网络作二层传输。

k8s Network Model

  • All Pods can reach all other Pods, without NAT 。Implementaions :
    • Flat
    • Overlays(e.g:VXLAN)
    • Routing(e.g:BGP)
  • All Nodes can reach all other Nodes,without NAT
  • IPAM-IP Address Management

Services : Problem

services 将一组 Pod 抽象成一个 Service,后面做个负载均衡

让 Pod 能够 ping 外网解决 DNS

Ingress

和 Service 区别:

  • Service 是 4 层网络模型,只能提供到 (IP + 端口)OSI
  • Ingress 是 7 层网络模型,HTTP 代理和路由

/etc/cni/net.d 该目录是k8s使用那种网络插件

k8s CNI Introduction

k8s CNI Canal Lab Demo

K8s 与 Linux 网络

Linux Namespace 机制

Linux namespace 实现了 6 项资源隔离,基本上涵盖了一个小型操作系统的运行要素,包括主机名、用户权限、文件系统、网络、进程号、进程间通信。

namespace 系统调用参数 隔离内容 内核版本
UTS CLONE_NEWUTS 主机名和域名 2.6.19
IPC CLONE_NEWIPC 信号量、消息队列和共享内存 2.6.19
PID CLONE_NEWPID 进程编号 2.6.24
Network CLONE_NEWNET 网络设备、网络栈、端口等 2.6.29
Mount CLONE_NEWNS 挂载点(文件系统) 2.4.19
User CLONE_NEWUSER 用户和用户组 3.8

Docker 网络模式

在使用 Docker run 创建 Docker 容器时,可以使用 --net 选项指定容器的网络模式,Docker 可以有4种网络模式。

  1. host 模式。--net=host 指定和宿主机共用一个 NetWork Namespace,容器中的网络环境(ip 地址、路由等)和宿主机的网络环境一致。
  2. none 模式。使用 --net=none 指定关闭网络功能。
  3. bridge 模式。--net=bridge 指定默认设置,容器使用独立的 Network Namespace,并连接到 Docker0 虚拟网桥,通过 iptables nat 表配置和宿主机进行通信。
  4. container 模式,--net=container:NAME_or_ID 指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡、配置IP,而是和一个指定的容器共享IP、端口范围等等。

Overlay 网络

Overlay 网络时建立在实际物理网络(Underlay网络)之上的虚拟网络。underlay 网络和 设备都是真正存在的实体,而 Overlay网络时依赖 Underlay网络虚拟出来的。

比如两个设备之间通过TCP或UDP通信,那么这就是underlay网络。但在TCP或UDP协议上可以承载应用数据,如果应用数据承载了IP协议,那么这个 Overlay网络是三层网络;而如果应用数据承载了数据链路层协议,那么这个 overlay网络时二层网络。

这个装置如何实现呢?在Linux里有个隧道技术

  • linux tun:在三层网络之上构建三层网络,Overlay网络通信协议位于IP层及以上。(IP、tcp/udp、ftp/http)overlay网络中不支持arp协议。
  • linux vxlan:在三层网络(tcp/ip)之上构建二层网络。overlay 网络通信协议位于数据链路层及以上。overlay网络支持arp协议(Ethernetll,ip,tcp/udp,ftp/http等)

iptables

  • filter:过滤数据包,实现软件防火墙的功能
  • nat:网络地址转换(改变源IP、 目的IP、 源端口、目的端口)
  • mangle:修改数据包的服务类型、TTL、 并且可以配置路由实现Q0S内核模块
  • raw:决定数据包是否被状态跟踪机制处理

iptables链的匹配原则:

从序列号为1的开始匹配,直到匹配到第一条合适的规则并执行, 后续规则即使能够匹配也不再执行,所以将经常会被匹配到的规则放在表前面。

iptables 五链

容器技术之网络

容器隔离技术:

  • namespace,也即每个 namespace 中的应用看到的是不同的 IP 地址、用户空间、程号等。
  • cgroup,也即明明整台机器有很多的 CPU、内存,而一个应用只能用其中的一部分。

1、单机下,Linux 容器网络(网桥模式)

Docker 项目会默认在宿主机上创建一个名叫 docker0 的网桥,凡是连接在 docker0 网桥上的容器,就可以通过它来进行通信。可是,我们又该如何把这些容器"连接"到 docker0 网桥上呢?这时候,我们就需要使用一种名叫 Veth Pair 的虚拟设备了。

同一个宿主机上的不同容器通过 docker0 网桥进行通信的流程:

当你遇到容器连不通"外网"的时候,你都应该先试试 docker0 网桥能不能 ping 通,然后查看一下跟 docker0 和 Veth Pair 设备相关的 iptables 规则是不是有异常,往往就能够找到问题的答案了。

2、容器"跨主机通信"问题

如果在另外一台宿主机(比如:10.168.0.3)上,也有一个 Docker 容器。那么,我们的 在另一台宿主机上的容器之间又该如何访问它呢?

容器的"跨主通信"问题

在 Docker 的默认配置下,一台宿主机上的 docker0 网桥,和其他宿主机上的 docker0 网桥,没有任何关联,它们互相之间也没办法连通。所以,连接在这些网桥上的容器,自然也没办法进行通信了。

构建这种容器网络的核心在于:我们需要在已有的宿主机网络上,再通过软件构建一个覆盖在已有宿主机网络之上的、可以把所有容器连通在一起的虚拟网络。所以,这种技术就被称为:Overlay Network(覆盖网络)。

从 Flannel 说起,目前 Flannel 支持三种后端实现,分别是:VXLAN、host-gw、UDP;

2.1、Flannel UDP 模式

当 IP 包从容器经过 docker0 出现在宿主机,然后又根据路由表进入 flannel0 设备后,宿主机上的 flanneld 进程(Flannel 项目在每个宿主机上的主进程),就会收到这个 IP 包。然后,flanneld 看到了这个 IP 包的目的地址,是 100.96.2.3,就把它发送给了 Node 2 宿主机。

flanneld 又是如何知道这个 IP 地址对应的容器,是运行在 Node 2 上的呢?子网(Subnet)

事实上,在由 Flannel 管理的容器网络里,一台宿主机上的所有容器,都属于该宿主机被分配的一个"子网"。在我们的例子中:

  • Node 1 的子网是 100.96.1.0/24,container-1 的 IP 地址是 100.96.1.2;
  • Node 2 的子网是 100.96.2.0/24,container-2 的 IP 地址是 100.96.2.3。

所以,flanneld 进程在处理由 flannel0 传入的 IP 包时,就可以根据目的 IP 的地址(比如 100.96.2.3),匹配到对应的子网(比如 100.96.2.0/24),从 Etcd 中找到这个子网对应的宿主机的 IP 地址是 10.168.0.3

而接下来 flanneld 的工作就非常简单了:flanneld 会直接把这个 IP 包发送给它所管理的 TUN 设备,即 flannel0 设备。根据我前面讲解的 TUN 设备的原理,这正是一个从用户态向内核态的流动方向(Flannel 进程向 TUN 设备发送数据包),所以 Linux 内核网络栈就会负责处理这个 IP 包,具体的处理方法,就是通过本机的路由表来寻找这个 IP 包的下一步流向。

docker0 网桥会扮演二层交换机的角色,将数据包发送给正确的端口,进而通过 Veth Pair 设备进入到 container-2 的 Network Namespace 里。

2.2、Virtual Extensible LAN(虚拟可扩展局域网)

VXLAN 是 Linux 内核本身就支持的一种网络虚似化技术。所以说,VXLAN 可以完全在内核态实现上述封装和解封装的工作,从而通过与前面相似的"隧道"机制,构建出覆盖网络(Overlay Network)。

2.3、CNI 插件工作原理

CNI 插件的工作原理:

当 kubelet 组件需要创建 Pod 的时候,它第一个创建的一定是 Infra 容器。所以在这一步,dockershim 就会先调用 Docker API 创建并启动 Infra 容器,紧接着执行一个叫作 SetUpPod 的方法。这个方法的作用就是:为 CNI 插件准备参数,然后调用 CNI 插件为 Infra 容器配置网络。

容器与容器之间要"通",容器与宿主机之间也要"通"。并且,Kubernetes 要求这个"通",还必须是直接基于容器和宿主机的 IP 地址来进行的。

2.4、host-gw

工作原理:

假设现在,Node 1 上的 Infra-container-1,要访问 Node 2 上的 Infra-container-2。

当你设置 Flannel 使用 host-gw 模式之后,flanneld 会在宿主机上创建这样一条规则,以 Node 1 为例:

可以看到,host-gw 模式的工作原理,其实就是将每个 Flannel 子网(Flannel Subnet,比如:10.244.1.0/24)的"下一跳",设置成了该子网对应的宿主机的 IP 地址。

不难看出,host-gw 模式能够正常工作的核心,就在于 IP 包在封装成帧发送出去的时候,会使用路由表里的"下一跳"来设置目的 MAC 地址。这样,它就会经过二层网络到达目的宿主机。

Flannel host-gw 模式必须要求集群宿主机之间是二层连通的。

2.5、Calico 插件

实际上,Calico 项目提供的网络解决方案,与 Flannel 的 host-gw 模式,几乎是完全一样的。也就是说,Calico 也会在每台宿主机上,添加一个格式如下所示的路由规则:

复制代码
<目的容器IP地址段> via <网关的IP地址> dev eth0

其中,网关的 IP 地址,正是目的容器所在宿主机的 IP 地址。三层网络方案得以正常工作的核心,是为每个容器的 IP 地址,找到它所对应的、"下一跳"的网关。

不过,不同于 Flannel 通过 Etcd 和宿主机上的 flanneld 来维护路由信息的做法,Calico 项目使用了一个"BGP"来自动地在整个集群中分发路由信息。BGP 的全称是 Border Gateway Protocol,即:边界网关协议。

Calico 项目的架构就非常容易理解了。它由三个部分组成:

  • Calico 的 CNI 插件。这是 Calico 与 Kubernetes 对接的部分。
  • Felix。它是一个 DaemonSet,负责在宿主机上插入路由规则(即:写入 Linux 内核的 FIB 转发信息库),以及维护 Calico 所需的网络设备等工作。
  • BIRD。它就是 BGP 的客户端,专门负责在集群里分发路由规则信息。

3、Cilium

在 5.10 内核以后,Cilium 新增了 eBPF Host-Routing 功能,该功能更加速了 eBPF 数据面性能,新增了 bpf_redirect_peer 和 bpf_redirect_neigh 两个 redirect 方式,bpf_redirect_peer 可以理解成 bpf_redirect 的升级版,其将数据包直接送到 veth pair Pod 里面接口 eth0 上,而不经过宿主机的 lxc 接口,这样实现的好处是少进入一次 cpu backlog queue 队列,该特性引入后,路由模式下,Pod -> Pod 性能接近 Node -> Node 性能,同时 Cilium 数据面路径发生了较大的变化。

文档链接:https://www.yuque.com/wei.luo/cni/vwtmwz
文档地址:https://www.yuque.com/wei.luo/cni/qubifn
文档地址:20210903-eBPF XDP TC介绍

相关推荐
lichenyang4531 天前
Docker 学习笔记(四):Dockerfile,把项目打成自己的镜像
docker·容器
lichenyang4531 天前
Docker 学习笔记(三):Docker 网络、bridge、子网和容器互通
docker·容器
lichenyang4531 天前
Docker 学习笔记(二):docker run 的参数到底在控制什么?
docker·容器
运维开发故事4 天前
基于 Arthas 的多集群在线诊断系统设计与实现
kubernetes
Patrick_Wilson6 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
探索云原生6 天前
K8s 1.36 这个 GA 特性,把 initContainer 拉模型的 hack 干掉了
ai·云原生·kubernetes
云恒要逆袭6 天前
运行你的第一个Docker容器
后端·docker·容器
Java之美7 天前
一次k8s升级引发的DevicePlugin注册失败
云原生·kubernetes
程序员老赵8 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程