一、Pod调度
在kubernetes平台上,很少会直接创建一个Pod,大多数情况下会通过RC(ReplicationController)、Deployment、DaemonSet、Job等控制器完成对一组Pod副本的创建,调用以及生命周期管理的自动控制任务。
在最早的kubernetes版本里面没有这么多的Pod副本控制器,只有一个Pod副本控制器RC(ReplicationController),其实现方式: RC独立于所控制的Pod,并通过Label标签这个松耦合关联关系控制目标Pod实例的创建和销毁,随着kubernetes发展,RC出现了新的继任者--Deplyment,用于更加自动完成Pod副本的部署,版本更新、回滚等操作。
严格来说RC的继承者并不是Deployment而是ReplicaSet,因为ReplicaSet更加强调了RC标签选择器的灵活性。之前RC的标签选择器只能选择一个标签,而ReplicaSet拥有集合式的标签选择器,可以选择更多的Pod。
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
与RC不同,ReplicaSet被设计成能控制多个不同标签的Pod副本。比如,应用MyApp发布两个v1和v2两个版本,用户希望MyApp的Pod副本数保持在3个,可以同时用包含v1和v2版本的Pod,就可以使用ReplicaSet。
selector:
matchLabels: #用于定义一组label
version: v2
matchExpressions: #用于定义一组基于集合的筛选条件
- {key: version, opetator: In, values: {v1,v2}}
Kubernetes中的滚动升级就是利用ReplicaSet的特性实现,同时Deployment也是通过ReplicaSet来实现Pod副本自动控制功能。我们不需要直接使用ReplicaSet来控制Pod的副本,而是通过管理Deplyment对象来控制副本。
二、亲和性(Affinity)
大多数情况下,我们希望Deployment创建的Pod被调用到集群中任何一个可用节点,而不关心具体调用到哪个节点。而在实际的生产环境中,希望某种Pod发副本全部在指定的一个或者一些节点上运行,比如将Mysql数据库调度到一个具有SSD盘的目标节点上,此时Pod模板中的NodeSelector属性就开始发挥作用了,将MySQL定向调度案例可以分为2步骤:
(1) 把具有SSD硬盘的Node都打上自定义标签disk=ssd;
(2) 在Pod模板中设定 NodeSelector的值为 "disk:ssd"
如此一来,K8S在调度Pod副本的时候,就会先按照Node的标签过滤出合适的目标节点,然后选择一个最佳的节点进行调度。
生产环境中遇到的问题:
(1) NodeSelector选择的Label不存在或者不符合条件,比如这些目标节点宕机或者资源不足;
(2) 如果要选择多种合适的目标节点,比如SSD硬盘的节点或者超高速硬盘的节点,如何解决?
kubernetes引入了NodeAffinity(节点亲和性)来解决问题。
三、K8S中特殊控制器(DaemonSet、StatefulSet、Job、CronJob)
(1) 不同Pod之前的亲和性(Affinity)。比如把MySQL数据库和Redis中间件不能被调度到同一个目标节点,或者两个不同的Pod必须被调用到同一个Node上,以实现本地文件共享或者本地网络通信等特殊需求,这个就是PodAffinity要解决的事情。
(2) 有状态集群调度。对于ZooKeeper、MongoDB、Kafka等有状态的集群。虽然集群中每个Worker节点看起来都是相同的,但每个Worker节点都必须有明确的、不变的唯一ID(主机名和IP地址),这些节点的启动和停止次序通常有严格的顺序。由于集群中需要持久化保存数据,所以集群中的Worker节点对应的Pod不管在哪个Node上恢复,都需要挂载原来的Volume,因此这些Pod还需要捆绑具体的PV。针对这种复杂需求,K8S提供了StatefulSet这种特殊的副班控制器来解决问题,在K8S1.19版本之后,StatefulSet才可用于正式生产环境中。
(3) 在每个Node上调度并且仅仅创建一个Pod副本。这种调度通常用于系统监控相关的Pod,比如主机上的日志采集、主机性能采集等进程需要被部署到集群中的每个节点并且只能部署一个副本,这就是DaemonSet这种特殊Pod副本控制器所解决的问题。
(4) 对于批处理作业,需要创建多个Pod副本来协同工作,当这些Pod副本都完成自己的任务时,整个批处理作业就结束了。这种Pod运行且仅运行一次的特殊调度用RC或者Deployment都无法解决,所以K8S引入了新的Pod调度器Job来解决问题,并继续延伸了定时作业的调度器CronJob。
与单独Pod实例不同,由RC、ReplicaSet、Deployment、DaemonSet等控制器创建的Pod副本实例都属于这些控制器,这样就存在问题,如果这些控制器被删除后,归属于这些控制器的Pod副本怎么处理? 在Kubernetes 1.9之前,在RC等对象被删除后,它们所创建的控制器不会被删除,在Kubernetes 1.9之后,这些Pod都会被删除,如果不希望这么做,可以使用kubectl命令 --cascade=false参数取消这一默认特性。
kubectl delete replicaset my-repsec --cascade=false