Service 是 Kubernetes 中重要的服务对象,Kubernetes 之所以需要 Service,有以下两方面的原因:
之前的文章介绍了Kubernetes里容器网络和CNI插件的主要工作原理。不过,除了这种隧道模式之外,还有一种纯三层(Pure Layer)的网络方案。其中的典型例子,莫过于 Flannel 的 host-gw 模式和 Calico 项目。
上一篇文章介绍了 Flannel 实现容器跨主机网络通信的两种实现方法—UDP和VXLAN ,它们都有着一个共性,那就是用户的容器都连接在 docker0 网桥上。而网络插件则在宿主机上创建了一个特殊的设备(UDP 模式创建的是 TUN 设备,VXLAN 模式创建的则是 VTEP 设备),docker0 与这个设备之间,通过 IP 转发(路由表)进行协作。然后,网络插件通过某种方法,把不同宿主机上的特殊设备连通,从而达到容器跨主机通信的目的。
实际上,上面这个流程,也正是 Kubernetes 对容器网络的主要处理方法。只不过,Kubernetes 是通过一个叫作 CNI 的接口,维护了一个单独的网桥来代替 docker0。这个网桥的名字就叫作:CNI 网桥,它在宿主机上的设备名称默认是:cni0。
在上一篇文章中,讲解了在单机环境下,Linux 容器网络的实现原理(网桥模式)。并且提到了,在 Docker 的默认配置下,不同宿主机上的容器通过 IP 地址进行互相访问是根本做不到的。
正是为了解决这个容器“跨主通信”的问题,社区里才出现了那么多的容器网络方案。而要理解容器“跨主通信”的原理,就一定要先从 Flannel 这个项目说起。
本文用来记录张磊《深入剖析Kubernetes》—— Kubernetes容器网络的学习笔记。
一个Linux容器能看见的“网络栈”是被隔离在它自己的Network Namespace当中的,而所谓“网络栈”,就包括了:网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。对于一个进程来说,这些要素,其实就构成了它发起和响应网络请求的基本环境。
容器可以声明直接使用宿主机的网络栈(-net=host),即不开启Network Namespace:
docker run -d -net=host --name nginx-host nginx
这样,容器启动后就直接监听的是宿主机的80端口。这种方式能为容器提供良好的网络性能,但也会引起共享网络资源的问题,比如端口冲突。所以,在大多数情况下,我们都希望容器进程能使用自己Network Namespace里的网络栈,即:拥有自己的IP地址和端口。
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v<lim {
return v
}
return lim
}