调度是一种向处理资源分配工作载荷的方式。在分布式环境中,调度器格外为大家需要,尤其是那些提供扩展性,资源意识以及高效能特性的调度器。
单体调度器是单个进程实体,进行调度决策并完成需要被调度的任务的部署。这些任务可以是长期运行的服务器程序,短期存在的批处理命令,MapReduce查询等等。
为了调度任务的决策,单体调度器需要:观察集群中资源的可用性(例如CPU、内存等),锁住资源,调度任务并更新可用资源。
对于单体调度器而言,它很难一次处理一个以上的任务,因为每个调度实体中只有一个资源管理器实体。相反,避免并发能够使得系统更易设计,更易于理解。
对于单体调度器,这里有一些样本:
Fleet: CoreOS的一个本地调度器(无资源意识)。
Swarm: Docker容器的一个调度后端。
Kubernetes: 一个Pods单体调度器的高级版本。
本文将涵盖2个基础单体调度器。
首先,让我们来看看fleet,一个面向systemd单元的调度器。systemd是一个高级init子系统,负责配置和启动Linux用户空间。每个单元都是一个独立的systemd配置文件,描述了你希望运行的进程。下文中,我们也会看到Swarm、Docker容器的一个调度后端。
从本质上说,fleet即集群的systemd。
fleet利用了systemd和etcd的优点,其中后者是CoreOS所使用的一个分布式key-value存储,用来创建分布式init系统。在调度一个systemd单元之前,fleet会判断哪个节点目前运行的单元文件最少,然后将下一个单元文件调向该节点。
不过,fleet不是一个具有资源意识的调度器。在进行systemd单元调度时,fleet并不将诸如CPU和内存等可用的系统资源纳入考虑范围。它只使用上述简单算法来进行调度。
我们可以在单元文件中规定一些约束。例如,我们可以声明一个单元文件应该运行在每个主机上。
如下是Fleet单元文件的一个范例,用以部署Deis储存管理器:
[Unit] Description=deis-store-admin [Service] EnvironmentFile=/etc/environment TimeoutStartSec=20m ExecStartPre=/bin/sh -c "IMAGE=`/run/deis/bin/get_image /deis/store-admin` \ && docker history $IMAGE >/dev/null 2>&1 || docker pull $IMAGE" ExecStartPre=/bin/sh -c "docker inspect deis-store-admin >/dev/null 2>&1 \ && docker rm -f deis-store-admin >/dev/null 2>&1 || true" ExecStart=/bin/sh -c "IMAGE=`/run/deis/bin/get_image /deis/store-admin` \ && docker run --name deis-store-admin --rm \ --volumes-from=deis-store-daemon-data \ --volumes-from=deis-store-monitor-data \ -e HOST=$COREOS_PRIVATE_IPV4 $IMAGE" ExecStopPost=-/usr/bin/docker rm -f deis-store-admin Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target [X-Fleet] Global=true
约束通过 X-Fleet
部分指定。这里有些指令是提供给fleet本身的,而剩余部分则是提供给systemd。比如,在上述例子中,X-Fleet
下Global=true
部分告诉fleet,要在集群中的每个机器上调度(如,部署)该单元。
可以参照单元文件与调度来获取关于定制fleet单元文件的更多选项。
通常,你可以使用fleetctl
命令来提交一个fleet单元。如果你正在使用Deis,你可以使用deisctl
命令。
用户可以通过为fleetctl的FLEETCTL_TUNNEL
(或deisctl的DEISCTL_TUNNEL
)设置集群中任意CoreOS的IP,来指定自己需要通讯的fleet守护进程所在的主机。
如下命令将会在集群中安装一个fleet单元:
deisctl install
如下命令将会运行单元:
deisctl start
Swarm是Docker容器在集群中的一个调度后端。
由于Swarm通过Docker API工作,因此我们可以通过Docker client或者其它和Docker Engine通讯的工具,来调度集群中的容器。
Swarm是对libswarm项目的扩展。Swarm有一个swarm管理器,它能够和集群中每个节点上的swarm节点通讯。Swarm的优点是支持过滤器和描述如何优化一个容器在集群的调度方式的策略。
让我们看一个示例命令:
docker run -d --name bar -e affinity:container==foo bar:v1
在这里,我们通过设定affinity:container==foo
,告诉Swarm将容器bar
部署到容器foo
所在的节点。
用户也可以选择指定软关联,只需使用~
,例如affinity:container==~foo
。如果foo容器当前不再任何节点中,Swarm将会取消关联,并根据调度策略调度容器。当前,Swarm支持的调度策略有:spead、bin packing和random。
缺省情况下,Deis使用fleet后端。不过现版本的Deis亦支持Swarm。
想要安装Swarm,只需运行:
deisctl install swarm && deisctl start swarm
切换调度后端:
deisctl config controller set schedulerModule=swarm
单体调度器的设计限制了性能和吞吐量。
由于资源管理器和调度器位于同一进程,单体调度器对于集群中的资源动态变化并不敏感。且调度是紧耦合的,这也就限制了扩展性。比如,fleet只能够调度systemd单元,Swarm只能够调度Docker容器。
fleet是相对底层的调度器,并且没有资源意识。因此并不建议在超过100个节点的集群中使用fleet。幸运的是,Deis V2将能够和Kubernetes协同工作,后者是一个更加高级的调度器。Swarm也有其自身的缺点,比如,在0.2版本中,Swarm不支持节点的故障切换。因此,当一个节点变得不可用时,Swarm不会为故障节点上的容器重新调度。
在下一篇文章中,我们将会介绍高级调度器,例如Kubernetes、Apache Mesos、Omega和Sparrow。同时,我们也会讨论这些工具,相较诸如Swarm和fleet之类的基础单体调度器所做的改进。