本文由 CNCF + Alibaba 云原生技术公开课 整理而来
Kubernetes 基本网络模型
Kubernetes 的容器网络模型,就是Kubernetes 对一个容器网络是否合格做出了限制。可以把它归结为约法三章和四大目标:
约法三章:在评价容器网络或者设计容器网络时,它的准入条件。它需要满足哪三个条件才能认为它是一个合格的网络方案
四大目标:在设计网络拓扑、设计网络的具体功能实现的时候,要去想清楚,能不能达成连通性等这几大指标
- 约法三章:
第一条:任意两个 Pod 之间其实是可以直接通信的,无需经过显式地使用 NAT 来接收数据和地址的转换;
第二条:Node 与 Pod 之间是可以直接通信的,无需使用明显的地址转换;
第三条:Pod 看到自己的 IP 跟别人看见它所用的IP是一样的,中间不能经过转换。
- 四大目标:
在设计一个 Kubernetes 的系统为外部提供服务的时候,要从网络的角度想清楚,外部如何一步一步连接到容器内部的应用?
外部和 Kubernetes 里面的 Service 之间是怎么通信的?外部用户怎么用到 Service?
Service 如何与它后端的 Pod 通讯?
Pod 和 Pod 之间调用是怎么做到通信的?
Pod 内部的容器与容器之间如何通信?
最终要达到目标,就是外部可以连接到最里面,对容器提供服务。
- 基础约束:
对于基本约束,因为容器的网络发展复杂性就在于它其实是寄生在 Host 网络之上的。从这个角度讲,可以把容器网络方案大体分为 Underlay/Overlay
两大派别:
Underlay
的标准是它与 Host 网络是同层的,从外在可见的一个特征就是它是不是使用了 Host 网络同样的网段、输入输出基础设备、容器的 IP 地址是不是需要与 Host 网络取得协同(来自同一个中心分配或统一划分)。这就是 Underlay
;
Overlay
不一样的地方就在于它并不需要从 Host 网络的 IPM 的管理的组件去申请IP,一般来说,它只需要跟 Host 网络不冲突,这个 IP 可以自由分配的。
Pod 容器网络中的核心就是 IP,IP 就是每个 Pod 对外通讯的地址基础,必须内外一致,符合 Kubernetes 的模型特征。
Network Namespace
Network Namespace 是实现网络虚拟化的内核基础,创建了隔离的网络空间:
独立的附属网络设备
独立的协议栈,IP 地址和路由表
iptables 规则
ipvs 等
狭义上来说,runC
容器技术是不依赖于任何硬件的,它的执行基础就是它的内核里面,进程的内核代表就是 task,它如果不需要隔离,那么用的是主机的空间( namespace),并不需要特别设置的空间隔离数据结构( nsproxy-namespace proxy)。相反,如果一个独立的网络 proxy 或者 mount proxy,里面就要填上真正的私有数据。
一个隔离的网络空间,它会拥有自己的网卡或者网络设备。网卡可能是虚拟的,也可能是物理网卡,它会拥有自己的 IP 地址、IP 表和路由表、拥有自己的协议栈状态。这里面特指就是 TCP/IP 协议栈,它会有自己的 status,会有自己的 iptables、ipvs。
从整个感官上来讲,这就相当于拥有了一个完全独立的网络,它与主机网络是隔离的。当然协议栈的代码还是公用的,只是数据结构并不相同。
每个 Pod 都有着独立的网络空间,Pod Net Container
会共享这个网络空间。一般 Kubernetes 会推荐选用 Loopback 接口,在 Pod Net Container
之间进行通信,而所有的 Container
通过 Pod
的 IP 对外提供服务。另外对于宿主机上的 Root Network Namespace
,可以把它看做一个特殊的网络空间,只不过它的 pid 是1。
主流网络方案
- 容器网络实现方案:
容器网络方案可能是 Kubernetes 里最为百花齐放的一个领域,它有着各种各样的实现。容器网络的复杂性,其实在于它需要跟底层 Iass 层的网络做协调、需要在性能跟 IP 分配的灵活性上做一些选择,这个方案是多种多样的。
Flannel 最为普遍的实现,提供多种网络 backend 实现,覆盖多种场景
Calico 采用 BGP 提供网络直连,功能丰富,对底层网络有要求
Canal Flannel for network + Calico for firewalling
Cilium 基于 eBPF 和 XDP 的高性能 Overlay 网络方案
Kube-router 采用 BGP 提供网络直连,集成基于 LVS 的负载均衡能力
Romana 采用 BGP 或 OSPF 提供网络直连
WeaveNet 采用 UDP 封装实现 L2 Overlay,支持用户态(慢、可加密)/内核态(快、不可加密)两种实现
Flannel 是一个比较大一统的方案,它提供了多种的网络 backend。不同的 backend 实现了不同的拓扑,它可以覆盖多种场景;
Calico 主要是采用了策略路由,节点之间采用 BGP 的协议,去进行路由的同步。它的特点是功能比较丰富,尤其是对 Network Point 支持比较好,Calico 对底层网络一般是要求 mac 地址能够直通,不能跨二层域;
最后是 WeaveNet,如果大家在使用中需要对数据做一些加密,可以选择用 WeaveNet,它的动态方案可以实现比较好的加密。
- Flannel 方案:
Flannel 是目前使用最为普遍的方案,它首先要解决的是 Container
的包如何到达 Host,这里采用的是加一个 Bridge 的方式。数据包如何离开 Host,是采用那种封装方式,还是不需要封装,都是可以选择的。
通过将 backend 机制独立,它目前已经支持多种数据路径,也可以适用于 Underlay/Overlay
等多种场景,主要的 backend 有 3 种:
1. 用户态 udp(纯用户态实现)
2. 内核 Vxlan(性能好),需要内核支持 Vxlan 的特性功能
3. 如果集群规模不大且处于同一个二层域,也可以选择 host-gw 方式
NetworkPolicy
- 基本概念:
NetworkPolicy
提供了基于策略的网络控制,用于隔离应用并减少攻击面。它使用标签选择器模拟传统的分段网络,并通过策略控制它们之间的流量以及来自外部的流量。
它采用各种选择器(Label
或 Namespace
),找到一组 Pod
,或者找到相当于通讯的两端,然后通过流的特征描述来决定它们之间是不是可以连通,可以理解为一个白名单的机制。
在使用 NetworkPolicy
之前,需要注意:
ApiServer 开启 extensions/v1beta1/networkpolicies
网络插件要支持 Network Policy,如 Calico、Romana、Weave Net 和 trireme 等
- 配置实例:
NetworkPolicy
的功能就是通过使用标签选择器(包括 namespaceSelector
和 podSelector
)来控制 Pod
之间的流量。
在设计一个 NetworkPolicy
时需要决定三件事:
控制对象:通过 spec 字段下 podSelector、namespaceSelector等条件筛选
流方向:Ingress(入 Pod 流量)+ from,Egress(出 Pod 流量)+ to
流特征:对端(podSelector、namespaceSelector),IP段(ipBlock),协议(protocol),端口(port)
test-network-policy NetworkPolicy
yaml 文件示例:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchlabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchlabels:
project: myproject
- podSelector:
matchlabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
文件解析:
apiVersion: networking.k8s.io/v1 表示 NetworkPolicy 当前所属的组是 networking.k8s.io,版本是 v1
kind 表示 Kubernetes 资源类型是 NetworkPolicy
metadata 表示 NetworkPolicy 的元数据,元数据通常包含 name、namespace、labels、annotations 等
spec 表示 NetworkPolicy 的期望状态,.spec.podSelector 表示 NetworkPolicy 期望匹配的 Pod;.spec.policyTypes 表示 NetworkPolicy 的策略类型;
.spec.ingress 表示匹配 Pod 入流量;.spec.egress 表示 表示匹配 Pod 出流量