diff --git a/SUMMARY.md b/SUMMARY.md index 5209de3aabddf7a85fa39c1b14db0e1bd708ec66..e9cbae0bb800e8fc0b13942680746148ce454d7d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -77,4 +77,4 @@ ### 调度器 * [Kubernetes 调度器介绍](docs/50.Kubernetes调度策略.md) -* [Kubernetes 亲和性调度](docs/51.Kubernetes亲和性调度.md) \ No newline at end of file +* [Kubernetes 亲和性调度](docs/51.Kubernetes亲和性调度.md) diff --git a/book.json b/book.json index 211aea750b2d1dc38a65dde59724688b323674d6..983bf0e9430ca590eeabcb9be10bd2d85d9af95c 100644 --- a/book.json +++ b/book.json @@ -66,10 +66,10 @@ "bookmark": "favicon.ico" }, "3-ba": { - "token": "98a42f33a08c40eef600d39d605ab818" + "token": "d611849735f187dd788dc054908f7d7a" }, "ga": { - "token": "UA-69668147-7" + "token": "UA-69668147-3" } } } diff --git "a/docs/51.Kubernetes\344\272\262\345\222\214\346\200\247\350\260\203\345\272\246.md" "b/docs/51.Kubernetes\344\272\262\345\222\214\346\200\247\350\260\203\345\272\246.md" index b1487ab2f724c0a466ab2af2e956b0ec70ee92c8..7f0b1e674e38e07e60dc2aa45d678fd0527d3241 100644 --- "a/docs/51.Kubernetes\344\272\262\345\222\214\346\200\247\350\260\203\345\272\246.md" +++ "b/docs/51.Kubernetes\344\272\262\345\222\214\346\200\247\350\260\203\345\272\246.md" @@ -1,8 +1,8 @@ # 51. Kubernetes 亲和性调度 -一般情况下我们部署的 Pod 是通过集群的自动调度策略来选择节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 Pod 的调度,比如我们内部的一些服务 gitlab 之类的也是跑在`Kubernetes`集群上的,我们就不希望对外的一些服务和内部的服务跑在同一个节点上了,害怕内部服务对外部的服务产生影响;但是有的时候我们的服务之间交流比较频繁,又希望能够将这两个服务的 Pod 调度到同一个的节点上。这就需要用到 Kubernetes 里面的一个概念:亲和性。 -亲和性有分成节点亲和性(`nodeAffinity`)和 Pod 亲和性(`podAffinity`)。 +一般情况下我们部署的 Pod 是通过集群的自动调度策略来选择节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 Pod 的调度,比如我们内部的一些服务 gitlab 之类的也是跑在`Kubernetes`集群上的,我们就不希望对外的一些服务和内部的服务跑在同一个节点上了,害怕内部服务对外部的服务产生影响;但是有的时候我们的服务之间交流比较频繁,又希望能够将这两个服务的 Pod 调度到同一个的节点上。这就需要用到 Kubernetes 里面的一个概念:亲和性和反亲和性。 +亲和性有分成节点亲和性(`nodeAffinity`)和 Pod 亲和性(`podAffinity`)。 ## nodeSelector 在了解亲和性之前,我们先来了解一个非常常用的调度方式:nodeSelector。我们知道`label`是`kubernetes`中一个非常重要的概念,用户可以非常灵活的利用 label 来管理集群中的资源,比如最常见的一个就是 service 通过匹配 label 去匹配 Pod 资源,而 Pod 的调度也可以根据节点的 label 来进行调度。 @@ -21,7 +21,7 @@ $ kubectl label nodes node02 com=youdianzhishi node "node02" labeled ``` -我们可以通过上面的`--show-labels`参数可以查看上述标签是否生效。当 node 被打上了相关标签后,在调度的时候就可以使用这些标签了,只需要在 Pod 的`spec`字段中添加`nodeSelector`字段,里面是我们需要被调度的节点的 label 即可。比如,下面的 Pod 我们要强制调度到 node02 这个节点上去,我们就可以使用 nodeSelector 来表示了:(test-busybox.yaml) +我们可以通过上面的`--show-labels`参数可以查看上述标签是否生效。当 node 被打上了相关标签后,在调度的时候就可以使用这些标签了,只需要在 Pod 的`spec`字段中添加`nodeSelector`字段,里面是我们需要被调度的节点的 label 即可。比如,下面的 Pod 我们要强制调度到 node02 这个节点上去,我们就可以使用 nodeSelector 来表示了:(node-selector-demo.yaml) ```yaml apiVersion: v1 kind: Pod @@ -43,7 +43,7 @@ spec: 然后我们可以通过 describe 命令查看调度结果: ```shell -$ kubectl create -f test-busybox.yaml +$ kubectl create -f node-selector-demo.yaml pod "test-busybox" created $ kubectl describe pod test-busybox Name: test-busybox @@ -69,48 +69,88 @@ Events: 通过上面的例子我们可以感受到`nodeSelector`的方式比较直观,但是还够灵活,控制粒度偏大,接下来我们再和大家了解下更加灵活的方式:节点亲和性(`nodeAffinity`)。 -## 节点亲和性 -`nodeAffinity`就是节点亲和性,相对应的是`Anti-Affinity`,就是反亲和性,这种方法比上面的`nodeSelector`更加灵活,它可以进行一些简单的逻辑组合了,不只是简单的相等匹配。 -调度可以分成**软策略**和**硬策略**两种方式: +## 亲和性和反亲和性调度 +上节课我们了解了 kubernetes 调度器的一个调度流程,我们知道默认的调度器在使用的时候,经过了 predicates 和 priorities 两个阶段,但是在实际的生产环境中,往往我们需要根据自己的一些实际需求来控制 pod 的调度,这就需要用到 nodeAffinity(节点亲和性)、podAffinity(pod 亲和性) 以及 podAntiAffinity(pod 反亲和性)。 + +亲和性调度可以分成**软策略**和**硬策略**两种方式: -* `软策略`就是如果你没有满足调度要求的节点的话,Pod 就会忽略这条规则,继续完成调度过程,说白了就是**满足条件最好了,没有的话也无所谓了**的策略 +* `软策略`就是如果你没有满足调度要求的节点的话,pod 就会忽略这条规则,继续完成调度过程,说白了就是**满足条件最好了,没有的话也无所谓了**的策略 * `硬策略`就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是**你必须满足我的要求,不然我就不干**的策略。 -`nodeAffinity`就有上面两种策略:`preferredDuringSchedulingIgnoredDuringExecution`和`requiredDuringSchedulingIgnoredDuringExecution`,前面的就是软策略,后面的就是硬策略。 +对于亲和性和反亲和性都有这两种规则可以设置: +`preferredDuringSchedulingIgnoredDuringExecution`和`requiredDuringSchedulingIgnoredDuringExecution`,前面的就是软策略,后面的就是硬策略。 + +> 这命名不觉得有点反人类吗?有点无语...... + +## nodeAffinity +节点亲和性主要是用来控制 pod 要部署在哪些主机上,以及不能部署在哪些主机上的。它可以进行一些简单的逻辑组合了,不只是简单的相等匹配。 -如下例子:(**test-node-affinity.yaml**) +比如现在我们用一个 Deployment 来管理3个 pod 副本,现在我们来控制下这些 pod 的调度,如下例子:(**node-affinity-demo.yaml**) ```yaml -apiVersion: v1 -kind: Pod +apiVersion: apps/v1beta1 +kind: Deployment metadata: - name: with-node-affinity + name: affinity labels: - app: node-affinity-pod + app: affinity spec: - containers: - - name: with-node-affinity - image: nginx - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: # 硬策略 - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: NotIn - values: - - node03 - preferredDuringSchedulingIgnoredDuringExecution: # 软策略 - - weight: 1 - preference: - matchExpressions: - - key: com - operator: In - values: - - youdianzhishi -``` - -上面这个 Pod 首先是要求 Pod 不能运行在 master 和 node03 这两个节点上,如果有个节点满足`com=youdianzhishi`的话就优先调度到这个节点上,同样的我们可以使用`descirbe`命令查看具体的调度情况是否满足我们的要求。这里的匹配逻辑是 label 的值在某个列表中,现在`Kubernetes`提供的操作符有下面的几种: + replicas: 3 + revisionHistoryLimit: 15 + template: + metadata: + labels: + app: affinity + role: test + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + name: nginxweb + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: # 硬策略 + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: NotIn + values: + - node03 + preferredDuringSchedulingIgnoredDuringExecution: # 软策略 + - weight: 1 + preference: + matchExpressions: + - key: com + operator: In + values: + - youdianzhishi +``` + +上面这个 pod 首先是要求不能运行在 node03 这个节点上,如果有个节点满足`com=youdianzhishi`的话就优先调度到这个节点上。 + +下面是我们测试的节点列表信息: +```shell +$ kubectl get nodes --show-labels +NAME STATUS ROLES AGE VERSION LABELS +master Ready master 154d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master= +node02 Ready 74d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,com=youdianzhishi,course=k8s,kubernetes.io/hostname=node02 +node03 Ready 134d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03 +``` + +可以看到 node02 节点有`com=youdianzhishi`这样的 label,按要求会优先调度到这个节点来的,现在我们来创建这个 pod,然后使用`descirbe`命令查看具体的调度情况是否满足我们的要求。 +```shell +$ kubectl create -f node-affinity-demo.yaml +deployment.apps "affinity" created +$ kubectl get pods -l app=affinity -o wide +NAME READY STATUS RESTARTS AGE IP NODE +affinity-7b4c946854-5gfln 1/1 Running 0 47s 10.244.4.214 node02 +affinity-7b4c946854-l8b47 1/1 Running 0 47s 10.244.4.215 node02 +affinity-7b4c946854-r86p5 1/1 Running 0 47s 10.244.4.213 node02 +``` + +从结果可以看出 pod 都被部署到了 node02,其他节点上没有部署 pod,这里的匹配逻辑是 label 的值在某个列表中,现在`Kubernetes`提供的操作符有下面的几种: * In:label 的值在某个列表中 * NotIn:label 的值不在某个列表中 @@ -122,100 +162,245 @@ spec: > 如果`nodeSelectorTerms`下面有多个选项的话,满足任何一个条件就可以了;如果`matchExpressions`有多个选项的话,则必须同时满足这些条件才能正常调度 POD。 -## Pod 亲和性 -上面两种方式都是让 Pod 去选择节点的,有的时候我们也希望能够根据 Pod 之间的关系进行调度,`Kubernetes`在1.4版本引入了 Pod 亲和性(`podAffinity`)的概念就可以实现我们这个需求。 +## podAffinity +pod 亲和性主要解决 pod 可以和哪些 pod 部署在同一个拓扑域中的问题(其中拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的 cluster、zone 等等),而 pod 反亲和性主要是解决 pod 不能和哪些 pod 部署在同一个拓扑域中的问题,它们都是处理的 pod 与 pod 之间的关系,比如一个 pod 在一个节点上了,那么我这个也得在这个节点,或者你这个 pod 在节点上了,那么我就不想和你待在同一个节点上。 -和`nodeAffinity`类似,`podAffinity`也有`requiredDuringSchedulingIgnoredDuringExecution`和 `preferredDuringSchedulingIgnoredDuringExecution`两种调度策略,唯一不同的是如果要使用互斥性,我们需要使用`podAntiAffinity`字段。 -如下例子,我们希望`with-pod-affinity`和`busybox-pod`能够就近部署,而不希望和`node-affinity-pod`部署在同一个拓扑域下面:(**test-pod-affinity.yaml**) +由于我们这里只有一个集群,并没有区域或者机房的概念,所以我们这里直接使用主机名来作为拓扑域,把 pod 创建在同一个主机上面。 +```shell +$ kubectl get nodes --show-labels +NAME STATUS ROLES AGE VERSION LABELS +master Ready master 154d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master= +node02 Ready 74d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,com=youdianzhishi,course=k8s,kubernetes.io/hostname=node02 +node03 Ready 134d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03 +``` + +同样,还是针对上面的资源对象,我们来测试下 pod 的亲和性:(pod-affinity-demo.yaml) ```yaml -apiVersion: v1 -kind: Pod +apiVersion: apps/v1beta1 +kind: Deployment metadata: - name: with-pod-affinity + name: affinity labels: - app: pod-affinity-pod + app: affinity spec: - containers: - - name: with-pod-affinity - image: nginx - affinity: - podAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchExpressions: - - key: app - operator: In - values: - - busybox-pod - topologyKey: kubernetes.io/hostname - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 1 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: app - operator: In - values: - - node-affinity-pod - topologyKey: kubernetes.io/hostname -``` - -上面这个例子中的 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`查看: + replicas: 3 + revisionHistoryLimit: 15 + template: + metadata: + labels: + app: affinity + role: test + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + name: nginxweb + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: # 硬策略 + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - busybox-pod + topologyKey: kubernetes.io/hostname +``` + +上面这个例子中的 pod 需要调度到某个指定的主机上,至少有一个节点上运行了这样的 pod:这个 pod 有一个`app=busybox-pod`的 label。 + +我们查看有标签`app=busybox-pod`的 pod 列表: ```shell -$ 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" +$ kubectl get pods -o wide -l app=busybox-pod +NAME READY STATUS RESTARTS AGE IP NODE +test-busybox 1/1 Running 164 7d 10.244.4.205 node02 +``` + +我们看到这个 pod 运行在了 node02 的节点上面,所以按照上面的亲和性来说,上面我们部署的3个 pod 副本也应该运行在 node02 节点上: +```shell +$ kubectl get pods -o wide -l app=affinity +NAME READY STATUS RESTARTS AGE IP NODE +affinity-564f9d7db9-lzzvq 1/1 Running 0 3m 10.244.4.216 node02 +affinity-564f9d7db9-p79cq 1/1 Running 0 3m 10.244.4.217 node02 +affinity-564f9d7db9-spfzs 1/1 Running 0 3m 10.244.4.218 node02 +``` + +如果我们把上面的 test-busybox 和 affinity 这个 Deployment 都删除,然后重新创建 affinity 这个资源,看看能不能正常调度呢: +```shell +$ kubectl delete -f node-selector-demo.yaml +pod "test-busybox" deleted +$ kubectl delete -f pod-affinity-demo.yaml +deployment.apps "affinity" deleted +$ kubectl create -f pod-affinity-demo.yaml +deployment.apps "affinity" created +$ kubectl get pods -o wide -l app=affinity +NAME READY STATUS RESTARTS AGE IP NODE +affinity-564f9d7db9-fbc8w 0/1 Pending 0 2m +affinity-564f9d7db9-n8gcf 0/1 Pending 0 2m +affinity-564f9d7db9-qc7x6 0/1 Pending 0 2m ``` -上面的事件信息也验证了我们的想法。 +我们可以看到处于`Pending`状态了,这是因为现在没有一个节点上面拥有`busybox-pod`这个 label 的 pod,而上面我们的调度使用的是硬策略,所以就没办法进行调度了,大家可以去尝试下重新将 test-busybox 这个 pod 调度到 node03 这个节点上,看看上面的 affinity 的3个副本会不会也被调度到 node03 这个节点上去? + +我们这个地方使用的是`kubernetes.io/hostname`这个拓扑域,意思就是我们当前调度的 pod 要和目标的 pod 处于同一个主机上面,因为要处于同一个拓扑域下面,为了说明这个问题,我们把拓扑域改成`beta.kubernetes.io/os`,同样的我们当前调度的 pod 要和目标的 pod 处于同一个拓扑域中,目标的 pod 是不是拥有`beta.kubernetes.io/os=linux`的标签,而我们这里3个节点都有这样的标签,这也就意味着我们3个节点都在同一个拓扑域中,所以我们这里的 pod 可能会被调度到任何一个节点: +```shell +$ kubectl get pods -o wide +NAME READY STATUS RESTARTS AGE IP NODE +affinity-7d86749984-glkhz 1/1 Running 0 3m 10.244.2.16 node03 +affinity-7d86749984-h4fb9 1/1 Running 0 3m 10.244.4.219 node02 +affinity-7d86749984-tj7k2 1/1 Running 0 3m 10.244.2.14 node03 +``` -> 在`labelSelector`和 `topologyKey`的同级,还可以定义 namespaces 列表,表示匹配哪些 namespace 里面的 pod,默认情况下,会匹配定义的 pod 所在的 namespace;如果定义了这个字段,但是它的值为空,则匹配所有的 namespaces。 +## podAntiAffinity +这就是 pod 亲和性的用法,而 pod 反亲和性则是反着来的,比如一个节点上运行了某个 pod,那么我们的 pod 则希望被调度到其他节点上去,同样我们把上面的 podAffinity 直接改成 podAntiAffinity,(pod-antiaffinity-demo.yaml) +```yaml +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: affinity + labels: + app: affinity +spec: + replicas: 3 + revisionHistoryLimit: 15 + template: + metadata: + labels: + app: affinity + role: test + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + name: nginxweb + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: # 硬策略 + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - busybox-pod + topologyKey: kubernetes.io/hostname +``` -查看上面我们定义的3个 POD 结果: +这里的意思就是如果一个节点上面有一个`app=busybox-pod`这样的 pod 的话,那么我们的 pod 就别调度到这个节点上面来,上面我们把`app=busybox-pod`这个 pod 固定到了 node03 这个节点上面来,所以正常来说我们这里的 pod 不会出现在 node03 节点上: ```shell -$ kubectl get po -o wide -NAME READY STATUS RESTARTS AGE IP NODE -test-busybox 1/1 Running 0 8m 172.30.95.18 192.168.1.140 -with-node-affinity 1/1 Running 0 10m 172.30.81.25 192.168.1.172 -with-pod-affinity 1/1 Running 0 8m 172.30.95.17 192.168.1.140 +$ kubectl create -f pod-antiaffinity-demo.yaml +deployment.apps "affinity" created +$ kubectl get pods -o wide +NAME READY STATUS RESTARTS AGE IP NODE +affinity-bcbd8854f-br8z8 1/1 Running 0 5s 10.244.4.222 node02 +affinity-bcbd8854f-cdffh 1/1 Running 0 5s 10.244.4.223 node02 +affinity-bcbd8854f-htb52 1/1 Running 0 5s 10.244.4.224 node02 +test-busybox 1/1 Running 0 23m 10.244.2.10 node03 ``` -亲和性/反亲和性调度策略比较如下: +这就是 pod 反亲和性的用法。 -| 调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 | -| --------------- | ---- | --------------------------------------- | ----- | ---------------- | -| nodeAffinity | 主机 | In, NotIn, Exists, DoesNotExist, Gt, Lt | 否 | 指定主机 | -| podAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD同一拓扑域 | -| podAnitAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD不在同一拓扑域 | +## 污点(taints)与容忍(tolerations) +对于`nodeAffinity`无论是硬策略还是软策略方式,都是调度 pod 到预期节点上,而`Taints`恰好与之相反,如果一个节点标记为 Taints ,除非 pod 也被标识为可以容忍污点节点,否则该 Taints 节点不会被调度 pod。 -## 污点(Taints)与容忍(tolerations) -对于`nodeAffinity`无论是硬策略还是软策略方式,都是调度 POD 到预期节点上,而`Taints`恰好与之相反,如果一个节点标记为 Taints ,除非 POD 也被标识为可以容忍污点节点,否则该 Taints 节点不会被调度pod。 +比如用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 pod,则污点就很有用了,pod 不会再被调度到 taint 标记过的节点。我们使用`kubeadm`搭建的集群默认就给 master 节点添加了一个污点标记,所以我们看到我们平时的 pod 都没有被调度到 master 上去: +```shell +$ kubectl describe node master +Name: master +Roles: master +Labels: beta.kubernetes.io/arch=amd64 + beta.kubernetes.io/os=linux + kubernetes.io/hostname=master + node-role.kubernetes.io/master= +...... +Taints: node-role.kubernetes.io/master:NoSchedule +Unschedulable: false +...... +``` -比如用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 POD,则污点就很有用了,POD 不会再被调度到 taint 标记过的节点。taint 标记节点举例如下: +我们可以使用上面的命令查看 master 节点的信息,其中有一条关于 Taints 的信息:node-role.kubernetes.io/master:NoSchedule,就表示给 master 节点打了一个污点的标记,其中影响的参数是`NoSchedule`,表示 pod 不会被调度到标记为 taints 的节点,除了 NoSchedule 外,还有另外两个选项: + +* `PreferNoSchedule`:NoSchedule 的软策略版本,表示尽量不调度到污点节点上去 +* `NoExecute`:该选项意味着一旦 Taint 生效,如该节点内正在运行的 pod 没有对应 Tolerate 设置,会直接被逐出 + + +污点 taint 标记节点的命令如下: ```shell -$ kubectl taint nodes 192.168.1.40 key=value:NoSchedule -node "192.168.1.40" tainted +$ kubectl taint nodes node02 test=node02:NoSchedule +node "node02" tainted +``` + +上面的命名将 node02 节点标记为了污点,影响策略是 NoSchedule,只会影响新的 pod 调度,如果仍然希望某个 pod 调度到 taint 节点上,则必须在 Spec 中做出`Toleration`定义,才能调度到该节点,比如现在我们想要将一个 pod 调度到 master 节点:(taint-demo.yaml) +```yaml +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: taint + labels: + app: taint +spec: + replicas: 3 + revisionHistoryLimit: 10 + template: + metadata: + labels: + app: taint + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - name: http + containerPort: 80 + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" ``` -如果仍然希望某个 POD 调度到 taint 节点上,则必须在 Spec 中做出`Toleration`定义,才能调度到该节点,举例如下: +由于 master 节点被标记为了污点节点,所以我们这里要想 pod 能够调度到 master 节点去,就需要增加容忍的声明: ```yaml tolerations: -- key: "key" -operator: "Equal" -value: "value" -effect: "NoSchedule" +- key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" +``` + +然后创建上面的资源,查看结果: +```shell +$ kubectl create -f taint-demo.yaml +deployment.apps "taint" created +$ kubectl get pods -o wide +NAME READY STATUS RESTARTS AGE IP NODE +...... +taint-845d8bb4fb-57mhm 1/1 Running 0 1m 10.244.4.247 node02 +taint-845d8bb4fb-bbvmp 1/1 Running 0 1m 10.244.0.33 master +taint-845d8bb4fb-zb78x 1/1 Running 0 1m 10.244.4.246 node02 +...... +``` + +我们可以看到有一个 pod 副本被调度到了 master 节点,这就是容忍的使用方法。 + +对于 tolerations 属性的写法,其中的 key、value、effect 与 Node 的 Taint 设置需保持一致, 还有以下几点说明: + +* 1. 如果 operator 的值是 Exists,则 value 属性可省略 +* 2. 如果 operator 的值是 Equal,则表示其 key 与 value 之间的关系是 equal(等于) +* 3. 如果不指定 operator 属性,则默认值为 Equal + +另外,还有两个特殊值: + +* 1. 空的 key 如果再配合 Exists 就能匹配所有的 key 与 value,也是是能容忍所有 node 的所有 Taints +* 2. 空的 effect 匹配所有的 effect + +最后,如果我们要取消节点的污点标记,可以使用下面的命令: +```shell +$ kubectl taint nodes node02 test- +node "node02" untainted ``` -effect 共有三个可选项,可按实际需求进行设置: +这就是污点和容忍的使用方法。 - 1. `NoSchedule`:POD 不会被调度到标记为 taints 节点。 - 2. `PreferNoSchedule`:NoSchedule 的软策略版本。 - 3. `NoExecute`:该选项意味着一旦 Taint 生效,如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出。 - \ No newline at end of file diff --git a/scheduler/node-affinity-demo.yaml b/scheduler/node-affinity-demo.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3c65eccd564ef40eed7038ba45fe74f001f91630 --- /dev/null +++ b/scheduler/node-affinity-demo.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: affinity + labels: + app: affinity +spec: + replicas: 3 + revisionHistoryLimit: 10 + template: + metadata: + labels: + app: affinity + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - name: http + containerPort: 80 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: NotIn + values: + - node03 + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: com + operator: In + values: + - youdianzhishi + diff --git a/scheduler/node-selector-demo.yaml b/scheduler/node-selector-demo.yaml new file mode 100644 index 0000000000000000000000000000000000000000..64409109b56d939e10fcff149dc782eaf7983d8b --- /dev/null +++ b/scheduler/node-selector-demo.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + labels: + app: busybox-pod + name: test-busybox +spec: + containers: + - command: + - sleep + - "3600" + image: busybox + name: test-busybox + nodeSelector: + com: youdianzhishi diff --git a/scheduler/pod-affinity-demo.yaml b/scheduler/pod-affinity-demo.yaml new file mode 100644 index 0000000000000000000000000000000000000000..84779fda888bc49c4427fedcfbf600d38aa974dc --- /dev/null +++ b/scheduler/pod-affinity-demo.yaml @@ -0,0 +1,30 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: affinity + labels: + app: affinity +spec: + replicas: 3 + revisionHistoryLimit: 10 + template: + metadata: + labels: + app: affinity + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - name: http + containerPort: 80 + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - busybox-pod + topologyKey: kubernetes.io/hostname diff --git a/scheduler/pod-antiaffinity-demo.yaml b/scheduler/pod-antiaffinity-demo.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e2bda52b2ee6184753eb7c811336b43f38b26fa2 --- /dev/null +++ b/scheduler/pod-antiaffinity-demo.yaml @@ -0,0 +1,30 @@ +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: affinity + labels: + app: affinity +spec: + replicas: 3 + revisionHistoryLimit: 10 + template: + metadata: + labels: + app: affinity + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - name: http + containerPort: 80 + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - busybox-pod + topologyKey: kubernetes.io/hostname