本文主要从上一篇中的kubectl expose deploy nginx --port=80 --target-port=80 --type=NodePort
命令出发,来初步探索下K8S中的网络情况。
kubectl expose deploy
命令将控制器下Pod的服务按照后面的参数暴露出去,比如上面暴露的方式的NodePort
,就是创建了NodePort
类型的Service。
除了上面提到的几个参数之外,还有2个参数,分别是--port=80
和--target-port=80
,这两个参数的含义是什么呢?--port
指的是在Service所处的Cluster IP
网络中打开一个80端口,而--target-port
指的是在Pod所处的网络中打开一个80端口。
1. Node IP
节点IP,这个比较好理解,就是每个节点服务器物理网卡所在的IP。如下图,我的Node IP分别是192.169.116.100、101、102
。
当通过命令行创建NodePort类型的Service时,我们并不能指定在该层网络中所开启的端口,K8S会随机分配一个可用的端口,端口的范围是30000-32767,这个端口会在所有的节点机器上都会开启。
而通过配置文件创建NodePort类型的Service时,则可以指定NodePort,但不建议自己指定端口,因为很可能会造成与现有的端口冲突。
2. Cluster IP
集群IP,也称为虚拟IP。在创建Service的时候,Service会被分配一个Cluster IP,该IP在Service整个生命周期中不会更改。需要注意的是这个IP是不能被ping通的。
而上面命令中--port
所指定的端口就是在这个网络中开启的端口,我们可以通过将上面的--port=80
修改为--port=8080
重新创建服务,创建服务之后,我们可以通过kubectl get svc
查询当前存在的Service。
既然我们创建的nginx服务的Cluster IP
为10.110.95.210
,指定的集群端口为8080
,那么我们可以通过访问这个IP+端口访问我们的服务,如下访问成功。
3. Pod IP
Pod IP也就是每个Pod所在的IP地址,可以通过kubectl get pod -o wide
查询到。
在K8S中,所有Pod都存在于一个网络平面中,也就是说所有节点的Pod都处于一个网络中。在之前部署集群时,这个工作是通过Flannel
组件完成的。什么是Flannel,可以参阅kubernetes中 flannel网络组件。
而上述命令中的--target-port=80
所开启的端口就是在这个Pod IP上开启的。
之前由提到过,一个Pod中可以运行多个容器。在K8S中,一个Pod中的所有容器存在于同一个网络命名空间,也就是说所有的容器共有一个网络协议栈,其中也包括这个Pod IP,和端口资源。这个是通过docker中的–net=container
网络模式实现的。
container模式指定新创建的Docker容器和已经存在的一个容器共享一个网络命名空间,而不是和宿主机共享(即host模式)。新创建的Docker容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等
在k8s中每个Pod容器有一个pause容器有独立的网络命名空间,这个pause容器将在Pod创建的初期被创建出来,在Pod内启动其他Docker容器时候使用–net=container
就可以让当前Docker容器加入到Pod容器拥有的网络命名空间(pause容器)。
4. 当集群外客户端访问Nginx时发生了什么
OK,通过上面的讲述已基本了解K8S中大致分为三层网络,从外至内分别是Node IP
,Cluster IP
以及Pod IP
。当通过NodePort
方式创建Service后,客户端又是如何访问到我们部署的Nginx的呢。
- 在通过NodePort方式创建Service之后,每个node节点上K8S将会开启了一个分配的端口32146;
- 当用户通过Node IP:32146访问的时候,会匹配IPTABLES规则,最终访问到10.244.1.10:80端口。而10.244.1.10就是我们部署的nginx的Pod IP地址。