文章目录
-
- 1. K8S为何将Pod作为最小调度单元
- 2. Pod概念介绍
-
- 2-1.Pod控制器介绍
- 3. 网络通讯
-
- 3-1. 同一个Pod内的容器之间的通信
- 3-2. Pod之间的通信
-
- 3-2-1. 同一主机节点的pod之间的通信
- 3-2-2. 不同主机节点的pod之间的通信
- 3-3. Pod与Service之间的通信
-
- 3-4. Pod与外网之间的通信
- 3-5. 外网访问pod
文中有理解不到位的地方,恳请各位同行指正,感激不尽。
该系列blog内容主要参考b站尚硅谷k8s的教学视频。
参考:
K8S最小调度单位Pod详解
Pod概念及网络通讯方式
B站尚硅谷课程视频
LVS与iptables的部分介绍
1. K8S为何将Pod作为最小调度单元
在介绍Pod之前,思考,为什么需要Pod?K8S中为什么把Pod作为最小调度单元?
??采用标准化的容器解决方案,在一台物理机上运行容器,容器之间是独立存在的,拥有其独立的ip地址和端口,每一个容器相当于一个独立的进程;而业务通常来说需要多个进程之间的协同合作来支持,这些进程之间有很亲密的协作关系,Pod则相当于是进程组的概念,倘若对这个业务进行部署,以容器为基本单位的话就有可能将该业务下的若干容器部署到不同物理机上,此时就需要考虑不同物理机下的容器之间的通信,若以Pod为基本单位的话,则相当于直接部署一组协同合作的进程,无需考虑上述问题。
2. Pod概念介绍
??Pod相当于是一组容器,Pod中必定会存在一个Pause容器(只要有Pod,pause容器就一定会被启动),该Pod中的所有容器会共用这个pause容器的网络栈和存储卷 ,也就是说此时该pod中的其他容器没有独立的ip地址,这些容器之间直接通过localhost就可以互相访问,因此pod中的容器的端口不能重复。
通常将Pod分为自主式Pod和控制器管理的Pod,自主式Pod会指定调度到某个节点,如果节点挂掉了,那么Pod就无法自动恢复。接下来看下控制器管理的Pod,首先了解一下各类控制器的特点。
2-1.Pod控制器介绍
ReplicationController(RC):用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来代替;而如果异常多出来的容易也会自动回收。在新版本的k8s中建议使用ReplicaSet来代替它
ReplicaSet(RS):与ReplicationController没有什么本质区别,只是名字不一样,并且ReplicaSet支持集合式的selector(支持根据条件批量删除或创建)
Deployment:虽然ReplicaSet可以独立使用,但一般还是建议使用Deployment来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling-update滚动更新但Deployment支持)
??这里要注意,Deployment并不会直接创建Pod,而是通过创建RS,再由RS创建Pod,间接地实现创建pod的任务。如图,假设Deployment现在创建一个RS-01,然后RS-01又创建了三个pod,这三个pod暂且将其定义为v1版本。
??那么Deployment是如何实现滚动更新呢?倘若现在要将这些pod全部更新到v2版本,Deployment会这样做,先创建一个RS-02,然后在RS-02下创建一个v2版的pod,同时再删掉RS-01下的一个v1版的pod,依次类推,直到所有的pod全部更新为v2版,此时RS-01被停用,注意并没有将其删除,这位后续进行回滚作了铺垫。同理,如果想将v2版回滚到v1版,则执行上述的逆过程,先删除RS-02下的一个v2,同时RS-01下创建一个v1,直到所有的pod都回滚到v1版本
HPA(HorizontalPodAutoScale):Horizontal Pod AutoScaling 仅适用于Depolyment和ReplicaSet,在V1版本中仅支持根据Pod的CPU利用率扩缩容(即,当CPU利用率≥80%时,HPA会自动扩容pod,最大个数为10个,当利用率不足80时,则会进行缩容,最小个数为2个),在vlalpha版本中,支持根据内存和用户自定义的metric扩缩容
StatefullSet:StatefullSet是为了解决有状态服务的问题(对应Depolyment和ReplicaSets是为无状态服务而设计),其应用场景包括:
稳定的持久化储存,即Pod重新调度后还能访问到相同的持久化数据,基于PVC来实现
稳定的网络标志,即Pod重新调度其PodName和HostName不变,基于Headless Service(即没有Cluster IP 的 Service)来实现
有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候还要依据定义的顺序依次进行(即从0到N-1,在下一个Pod运行之前所有的Pod必须都是Running和Ready状态),基于init containers来实现
有序收缩,有序删除(从N-1到0)
何为有状态服务?何为无状态服务?
举例说明:老板接了一个项目,顺便给李阳画了一个饼。于是李阳就作为项目成员被老板拉进项目群聊中,李阳跟进该项目一段时间后,老板突然觉得李阳是不可多得之才,应该去吃一个更大的饼,于是把李阳踢出当前群聊,但是过了一段时间后,老板发现之前的饼有些许饼渣需要处理,此时又把李阳拉进群聊来跟进项目的后续内容,李阳心态崩了,由于中间的断层,此时已无法准确跟进该项目的内容,于是rm -rf /* 并仰天长叹:此之谓,有状态服务是也。
李阳一顿操作后,无缝衔接入职某电子厂,在某电子设备生产流水线上做一名拧螺丝工人,然而天有不测风云,一场突如起来的疫情让电子厂停工半年,半年后李阳重回工作岗位,依然熟练得让人心疼地在流水线上拧螺丝,不仅感叹道,此之谓,无状态服务是也。
DaemonSet:DaemonSet确保全部(或者一些)Node上运行一个Pod的副本。当有Node加入集群时,也会为它们新增一个Pod。当有Node从集群中移除时,这些Pod也会被回收。删除DaemonSet会删除它创建的所有Pod,典型用法:
运行集群存储daemon,例如在每个Node上运行glusterd、ceph
在每个Node上运行日志收集daemon,例如Logstash、Fluentd
在每个Node上运行监控daemon,例如Prometheus Node Exporter
Job、Cron Job(类似于Linux的at和crontab):Job负责批处理任务,即仅执行一次任务,它保证批处理任务的一个或多个Pod成功结束;Cron Job管理基于时间的Job,即
在给定时间点仅运行一次
周期性的给定时间点运行
3. 网络通讯
K8S的网络模型假定了所有Pod都可以在一个直接连通的扁平的网络空间中,GCE(Google Compute Engine)里面是一个现成的网络模型,k8s假定其已经存在,但是如果在私有云中搭建k8s集群,就无法假定该集群存在,就需要开发人员自行实现该网络假设,将不同节点上的容器之间的互相访问打通,然后运行k8s。(摘自B站尚硅谷教学课件)
3-1. 同一个Pod内的容器之间的通信
??直接通过localhost就可以进行通信,之前有提到过,同一个pod内的容器之间共享一个pause容器,也就共用其网络栈,只需端口号即可实现容器之间的访问
3-2. Pod之间的通信
通过Overlay Network全覆盖网络进行通信
Flannel是CoreOS团队针对k8s设计的一个网络规划服务,其功能主要是让集群中的不同节点主机创建的docker容器具有全集群唯一的虚拟ip地址,而且它还能在这些ip地址之间建议一个overlay network,通过这个overlay network将数据包原封不动的传递到目标容器内(摘自B站尚硅谷教学课件)
试想,现在有三台物理机,每个物理机上都运行一个docker,分别为docker0、docker1、docker2,那么这几个docker之间如何直接通过对方的ip就可以相互访问呢?flanner解决了该问题
web app* 与backend相当于是pod,web app1、web app2、web app3与backend之间的关系就相当于下图
假设现有有一个请求过来,backend接收到该请求后发现需要运行web app2,那么此时就涉及到跨主机之间的pod的通信。
3-2-1. 同一主机节点的pod之间的通信
??首先在真实的node服务器上会创建一个flanneld的守护进程,该进程会监听一个端口,该端口用于转发或接收数据包,flanneld进程一旦启动会开启一个flannel0的网桥,flannel0用于手机docker0转发出来的数据报,docker0所做的就是分配自己的ip到对应的pod上。因此,如果是同一个节点主机上的不同pod之间的访问,实际上是通过docker0的网桥进行通信(网桥的通俗理解)。
3-2-2. 不同主机节点的pod之间的通信
??假设web app2和backend之间需要进行通信,从图中可以看出这两部分存在于不同的网段。所以其相互通信的流程大概是这样的,比如web APP2将地址10.1.15.2/24发到网关docker0,然后通过相关函数将数据包抓到flannel0,之后从etcd中获取到一些路由表记录,然后判断路由到哪台机器,由于flannel0是flanned开启的一个网桥,因此数据包会到flanned,然后对数据包进行如下封装(可以看到,flanned是使用udp进行数据包的转发):
封装后发送到另一台主机(根据封装的第一层mac地址),另一台主机截获后来到flanned(根据第二层信息),flanned进行解析转发一直送到docker0,此时根据封装好的第四层信息进行解析从而找到最终对应的pod。
??那么在这个过程中ETCD与flannel之间有哪些关联呢?ETCD会存储管理flannel可分配的ip地址段资源;监控ETCD中每个pod的实际地址,并在内存中建立维护pod节点路由表。
3-3. Pod与Service之间的通信
??旧版本通过各节点的Iptables规则实现pod与service进行通信,后续新版本中通过LVS实现维护和转发。
3-4. Pod与外网之间的通信
?pod向外网发送请求时,查找路由表,转发数据包到宿主机的网卡,宿主网卡完成路由选择后,iptables执行masquerade,把源ip更改为宿主网卡的ip,然后向外网服务器发送请求。
3-5. 外网访问pod
如果外网访问pod,需要通过service,nodeport 类型(后续有讲解)
k8s中网络说明:
注意:只有节点网络是真实存在的,相当于物理机上的网卡。pod网络和service网络是虚拟网络,pod网络中的pod之间进行通讯,通过这个扁平化的网络结构进行通讯即可。