Kubernetes 的网络模型
Container Network Interface (CNI) 容器网络接口,由 Google 和 CoreOS 主导。是由 CoreOS 提出的一个容器网络规范。已采纳规范的包括 Apache Mesos,Cloud Foundry,Kubernetes,Kurma 和 RKT。
K8s 网络模型设计的级别要求是:
- 一个 Pod 一个 IP。
- 每个 Pod 独立 IP, Pod 内所有容器共享网络 (同一个 IP)。
- 所有容器都可以与其他容器通信。
- 所有结点都可以与其他容器通信。
简而言之,所有 IP 都是可以通信的。
所有容器之间无需 NAT 就可以直接互相访问;所有 Node 和所有容器之间无需 NAT 就可以直接互相访;容器自己看到的 IP 跟其他容器看到的一样。
K8S 网络规范
CNI 规定了一个容器 Runtime 和网络插件之间的简单的契约。这个契约通过 JSON 的语法定义了 CNI 插件所需要提供的输入和输出。
CNI 插件提供两个功能:
- 一个用来将网络接口加入到指定网络。
- 另一个用来将其移除。
这两个接口分别在容器被创建和销毁的时候被调用。容器 Runtime 首先需要获得一个网络命名空间以及一个容器 ID,然后连同一些 CNI 配置参数传给网络驱动。
接着网络驱动会将该容器连接到网络并将分配的 IP 地址以 JSON 的格式返回给容器 Runtime。
K8S 网络插件要求
K8S 对网络插件的要求总的来讲主要有两个最基本的,分别是:
- 要能够为每一个 Node 上的 Pod 分配互相不冲突的 IP 地址。
- 要所有 Pod 之间能够互相访问。
K8S 网络实现方案
K8S网络实现方案有如下几种:
隧道方案
隧道方案在 IaaS 层的网络中应用也比较多,将 Pod 分布在一个大二层的网络规模下。网络拓扑简单,但随着节点规模的增长复杂度会提升。
代表方案:
- Weave:UDP 广播,本机建立新的 BR,通过 PCAP 互通。
- Open vSwitch:基于 VxLan 和 GRE 协议,但是性能方面损失比较严重。
- Flannel:UDP 广播,VxLan。
- Racher:IPsec。
路由方案
路由方案一般是从 3 层或者 2 层实现隔离和跨主机容器互通的,出了问题也很容易排查。
代表方案:
- Calico:基于 BGP 协议的路由方案,支持很细致的 ACL 控制,对混合云亲和度比较高。
- Macvlan:从逻辑和 Kernel 层来看隔离性和性能优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。
K8S Pod 的网络创建流程
K8S Pod 的网络创建流程如下:
- 每个 Pod 除了创建时指定的容器外,都有一个 Kubelet 启动时指定的基础容器。
- Kubelet 创建基础容器,生成 Network Namespace。
- Kubelet 调用网络 CNIdriver,根据配置调用具体的 CNI 插件。
- CNI 插件给基础容器配置网络。
- Pod 中其他的容器共享基础容器的网络。
Pod 中的网络
Pod 是 K8S 的最小工作单元。每个 Pod 包含一个或多个容器。K8S 管理的也是 Pod 而不是直接管理容器。Pod 中的容器会作为一个整体被 Master 调度到一个 Node 上运行。
Pod 的设计理念是支持多个容器在一个 Pod 中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。
一个 Pod 中可以包含多个容器,而一个 Pod 只有一个 IP 地址。那么多个容器之间互相访问和访问外网是如何使用这一个 IP 地址呢?
答案是:多个容器共享同一个底层的网络命名空间 Net (网络设备、网络栈、端口等)。
下面以一个小例子说明,创建一个 Pod 包含两个容器,yaml 文件如下:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: Pod-two-container
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: busybox
image: busybox
command:
- "/bin/sh"
- "-c"
- "while true;do echo hello;sleep 1;done"
- name: nginx
image: nginx
EOF