一般情况下我们部署的 POD 是通过集群自动调度选择某个节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 POD 的调度,比如我们内部的一些服务 gitlab 之类的也是跑在Kubernetes集群上的,我们就不希望对外的一些服务和内部的服务跑在同一个节点上了,害怕内部服务对外部的服务产生影响;有的时候呢我们两个服务直接交流比较频繁,又希望能够将这两个服务的 POD 调度到同样的节点上。这就需要用到 Kubernetes 里面的一个概念:亲和性,亲和性主要分为两类:nodeAffinity和podAffinity。
nodeSelector
我们知道label是kubernetes中一个非常重要的概念,用户可以非常灵活的利用 label 来管理集群中的资源,比如最常见的一个就是 service 通过匹配 label 去选择 POD 的。而 POD 的调度也可以根据节点的 label 进行特定的部署。
我们可以通过下面的命令查看我们的 node 的 label:
1
2
3
4
5
6
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
192.168.1.140 Ready <none> 42d v1.8.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=192.168.1.140
192.168.1.161 Ready <none> 118d v1.8.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/cluster-service=true,kubernetes.io/hostname=192.168.1.161
192.168.1.170 Ready <none> 118d v1.8.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/cluster-service=true,kubernetes.io/hostname=192.168.1.170
192.168.1.172 Ready <none> 114d v1.8.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/cluster-service=true,kubernetes.io/hostname=192.168.1.172
$ kubectl describe pod test-busybox
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 49s default-scheduler Successfully assigned test-busybox to 192.168.1.140
Normal SuccessfulMountVolume 49s kubelet, 192.168.1.140 MountVolume.SetUp succeeded for volume "default-token-hmpbz" Normal Pulling 49s kubelet, 192.168.1.140 pulling image "busybox" Normal Pulled 41s kubelet, 192.168.1.140 Successfully pulled image "busybox" Normal Created 41s kubelet, 192.168.1.140 Created container
Normal Started 41s kubelet, 192.168.1.140 Started container
我们可以看到 Events 下面的信息,上面的 POD 被正确的调度到了140节点。通过上面的例子我们可以感受到nodeSelector的方式比较直观,但是还够灵活,控制粒度偏大,下面我们再看另外一种更加灵活的方式:nodeAffinity。
上面这个 POD 首先是要求 POD 不能运行在140和161两个节点上,如果有个节点满足source=qikqiak的话就优先调度到这个节点上,同样的我们可以使用descirbe命令查看具体的调度情况是否满足我们的要求。这里的匹配逻辑是 label 的值在某个列表中,现在Kubernetes提供的操作符有下面的几种:
上面这个例子中的 POD 需要调度到某个指定的主机上,至少有一个节点上运行了这样的 POD:这个 POD 有一个app=busybox-pod的 label。podAntiAffinity则是希望最好不要调度到这样的节点:这个节点上运行了某个 POD,而这个 POD 有app=node-affinity-pod的 label。根据前面两个 POD 的定义,我们可以预见上面这个 POD 应该会被调度到140的节点上,因为busybox-pod被调度到了140节点,而node-affinity-pod被调度到了140以为的节点,正好满足上面的需求。通过describe查看:
1
2
3
4
5
6
7
8
$ kubectl describe pod with-pod-affinity
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 8s default-scheduler Successfully assigned with-pod-affinity to 192.168.1.140
Normal SuccessfulMountVolume 7s kubelet, 192.168.1.140 MountVolume.SetUp succeeded for volume "default-token-lcl77" Normal Pulling 7s kubelet, 192.168.1.140 pulling image "nginx"