Kubernetes容器调度策略

容器编排中一个重要且复杂的方面是调度应用程序容器。如何将容器适当放置到可用的共享基础架构资源上,是在最佳计算资源使用状况下实现最大性能的关键所在。node

Cattle是Rancher 1.6的默认编排引擎,提供了各类调度功能来有效地放置服务:nginx

https://rancher.com/docs/rancher/v1.6/en/cattle/scheduling/#scheduling-servicesdocker

随着基于Kubernetes的Rancher 2.0版本的发布,Rancher如今使用原生的Kubernetes调度。在本文中,咱们将看看Rancher 2.0中可用的调度方法与Cattle的调度的比较。安全

节点调度架构

根据原生的Kubernetes行为,默认状况下,Rancher 2.0工做负载中的pod将分布在可调度且具备足够可用容量的节点(主机)上。但就像1.6版本同样,Rancher 2.0也有助于:工具

  • 在特定节点上运行全部pod性能

  • 使用标签进行节点调度测试

如下是1.6 UI中的调度方式。Rancher容许您在特定主机上运行全部容器,指定硬/软主机标签,或在部署服务时使用亲和性/反亲和性规则。3d

如下是Rancher 2.0中对应的节点调度UI,它在部署工做负载时提供相同的功能。rest

Rancher使用底层的原生Kubernetes构造来指定节点的亲和性/反亲和性。相应的Kubernetes的详细文档参考此处:

https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity

下面的示例中咱们未来看看如何使用节点调度选项来调度工做负载pod,而后看看Kubernetes YAML规范和Rancher 1.6 Docker Compose配置的对比。

示例:在特定节点上运行全部Pod

在部署工做负载(导航到Cluster> Project> Workloads)时,能够将工做负载中的全部pod调度到特定节点。

在这里,我使用特定节点上的nginx镜像部署scale = 2的工做负载。

若是某节点有足够的计算资源可用,Rancher将选择该节点;若是使用hostPort,则不会发生端口冲突。若是该工做负载使用与另外一个工做负载冲突的nodePort来对外暴露,那么部署是能够成功建立的,但它不会建立nodePort服务。如此一来,工做负载则彻底不会暴露了。

在“工做负载/Workload”选项卡上,您能够按节点列出工做负载。在此,我能够看到个人Nginx工做负载的两个pod都安排在指定的节点上了:

Kubernetes pod规范中的调度规则以下所示:

示例:主机标签的亲和性/反亲和性**

我在Rancher 2.0集群中向node1添加了标签foo = bar,以测试基于标签的节点调度规则。

主机标签亲和性:硬

下图展现了如何在Rancher 2.0 UI中指定主机标签的亲和性规则。硬亲和性规则意味着所选主机必须知足全部调度规则。若是找不到此类主机,则工做负载将没法部署。

在PodSpec YAML中,此规则将转换为字段nodeAffinity。另外请注意,我已经包含了Rancher 1.6 docker-compose.yml以使用标签实现相同的调度行为。

主机标签亲和性:软

若是您是Rancher 1.6用户,那么您必定知道软亲和性规则意味着调度程序会尝试按规则部署应用程序,但即便有主机不知足规则也能够成功部署。如下是如何在Rancher 2.0 UI中指定此规则:

pod的相应YAML规范以下所示:

主机标签反亲和性

除了key = value主机标签匹配规则外,Kubernetes调度结构还支持如下运算符:

所以,要实现反亲和性,可使用运算符NotIn和DoesNotExist做为节点标签。

Rancher 1.6的其余调度功能

若是您是Cattle用户,想必您很熟悉Rancher 1.6中提供的一些其余调度功能:

  • 选择使用容器标签的主机:

https://rancher.com/docs/rancher/v1.6/en/cattle/scheduling/#finding-hosts-with-container-labels

  • 可以根据资源约束进行调度:

https://rancher.com/docs/rancher/v1.6/en/rancher-services/scheduler/#resource-constraints

  • 可以仅在主机上调度特定服务:

https://rancher.com/docs/rancher/v1.6/en/rancher-services/scheduler/#restrict-services-on-host

若是您是在Rancher 1.6设置中使用这些功能,则可使用原生的Kubernetes调度选项在Rancher 2.0中复制它们。在Rancher v2.0.8中,在部署工做负载时暂时没有对这些选项的UI支持,但您始终能够经过在Rancher集群上导入Kubernetes YAML规范来使用它们。

使用容器标签进行调度

Rancher 1.6中的这一功能容许您将容器调度到具备特定标签的容器的主机。要在Rancher 2.0上执行此操做,请使用Kubernetes inter-pod亲和和反亲和功能:

https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity

如文档中所述,Kubernetes容许您根据pod标签而不是节点标签来约束pod能够被调度到哪些节点。

Rancher 1.6中最经常使用的调度功能之一是使用容器上的标签对服务自己进行反亲和。要在Rancher 2.0中复制此行为,咱们能够在Kubernetes YAML规范中使用pod反亲和构造。例如,能够考虑使用Nginx Web工做负载。要确保此工做负载中的pod不在同一主机上,您可使用podAntiAffinity构造,以下所示。经过使用标签指定podAntiAffinity,咱们能够确保每一个Nginx副本不在单个节点上共存。

使用Rancher CLI,能够将此工做负载部署到Kubernetes集群上。请注意,上面的部署指定了三个副本,而且我在Kubernetes集群中有三个可调度节点。

因为指定了podAntiAffinity,所以三个pod最终位于不一样的节点上。为了进一步检查podAntiAffinity的应用方式,我能够将部署扩展到四个pod。请注意,因为调度程序没法找到知足podAntiAffinityrule的另外一个节点,所以没法调度第四个pod。

基于资源的调度

在Rancher 1.6中建立服务时,能够在UI的“安全/主机”选项卡中指定内存预留和mCPU预留。Cattle会将服务的容器安排到具备足够可用计算资源的主机上。

在Rancher 2.0中,您可使用pod容器规范下的resources.requests.memory和resources.requests.cpu指定工做负载pod所需的内存和CPU资源。您能够在此处找到有关这些规范的更多详细信息:

https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container

指定这些资源请求时,Kubernetes调度程序会将pod分配给具备足够容量的节点。

仅给主机调度特定服务

Rancher 1.6可以在主机上指定容器标签,从而只将特定容器调度给它。

要在Rancher 2.0中实现此目的,能够在pod规范中使用相应的Kubernetes的“添加节点taints(如主机标签)并使用容差”的功能:

https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/

全局服务

在Rancher 1.6中,全局服务是指在环境中的每一个主机上部署容器的服务:

https://rancher.com/docs/rancher/v1.6/en/cattle/scheduling/#global-service

若是服务的标签为io.rancher.scheduler.global:'true',则Rancher 1.6调度程序将在环境中的每一个主机上调度服务容器。如文档中所述,若是将新主机添加到环境中,而且主机知足全局服务的主机要求,则Rancher将自动启动该服务。

下面的示例是Rancher 1.6中的全局服务示例。请注意,只需放置所需标签就足以使服务全局化。

咱们如何使用Kubernetes在Rancher 2.0中部署全局服务?

为此,Rancher为用户的工做负载部署了Kubernetes DaemonSet对象(https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)。DaemonSet的功能与Rancher 1.6全局服务彻底相同。Kubernetes调度程序将在集群的每一个节点上部署一个pod,而且随着新节点的添加,调度程序将在它们上启动新的pod,前提是它们与工做负载的调度要求相匹配。

此外,在2.0中,您还能够将DaemonSet限制为部署到具备特定标签的节点,具体可参考文档:

https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/

使用Rancher 2.0 UI部署DaemonSet

若是您是Rancher 1.6用户,要使用UI将全局服务迁移到Rancher 2.0,请导航到Cluster> Project> Workloads视图。部署工做负载时,您能够选择如下工做负载类型:

这就是上面的DaemonSetworkload相应的Kubernetes YAML规范:

从Docker Compose到Kubernetes YAML

要使用Compose配置将Rancher 1.6全局服务迁移到Rancher 2.0,请按照下列步骤操做。

您可使用Kompose工具将docker-compose.yml文件从Rancher 1.6转换为Kubernetes YAML,而后使用Kubernetes集群中的Kubectl客户端工具或Rancher CLI部署应用程序。

回头想一想上面提到的docker-compose.yml规范,其中的Nginx服务就是全局服务。以下是使用Kompose将其转换为Kubernetes YAML的方法:

下面开始针对您的Kubernetes集群配置Rancher CLI,并部署生成的* -daemonset.yaml文件。

如上所示,个人Kubernetes集群有两个能够调度工做负载的工做节点,而且部署global-daemonset.yaml为Daemonset启动了两个pod,每一个节点上有一个pod。

** 总 结 **

在本文中,咱们回顾了如何将Rancher 1.6的各类调度功能迁移到Rancher 2.0。大多数调度技术在Rancher 2.0中都有相同的选项,或者它们能够经过原生的Kubernetes结构实现。