Kubernetes中的调度
在本文中,我们将学习 Kubernetes 中的调度。在 Kubernetes 中,调度是指确保 Pod 与 Node 匹配,以便 Kubelet 可以运行它们。
调度程序监视每个新创建的 pod 或其他未调度的 pod,然后 kube-scheduler 选择一个最佳节点供它们运行。
在集群中,满足 Pod 调度要求的节点称为可行节点。如果没有合适的节点,则 Pod 将保持未调度状态,直到调度程序能够放置它。
调度程序为 Pod 找到可行节点,然后运行一组函数对可行节点进行评分,并在可行节点中选择得分最高的节点来运行 Pod。然后调度程序在称为绑定的过程中将此决定通知 API 服务器。
调度决策需要考虑的因素包括个人和集体资源需求、硬件/软件/策略约束、亲和性和反亲和性规范、数据局部性、工作负载间干扰等。
如果我们想选择我们的对象将运行的节点怎么办。在我们想要的特定节点上运行 Kubernetes 对象有几种不同的方法。
让我们通过以下方式再次检查我们现有的节点:
kubectl get nodes
此处我在master创建node,所以只能看到一个master节点。
我们可以使用规范下的“nodeName”属性手动分配节点。 例如,让我们通过分配一个节点名称再次创建 nginx pod。
nginx-node.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: iz2zegfpsrzdc0gb1tmnl9z
containers:
- name: nginx
image: nginx
说明: nodeName其实可以通过修改hostname改为我们自定义的名字。
创建 pod
kubectl apply -f nginx-node.yaml
查看pod详细信息
kubectl describe pod nginx
可以看出pod创建在 master(iz2zegfpsrzdc0gb1tmnl9z)节点上了。
在特定节点中运行对象的另一种方法是标记节点。 在我们标记节点后,我们需要在对象定义中定义我们想要选择具有该标签的节点。 在这种方法中,可能会使用相同的标签标记多个节点,因此我们的 Kubernetes 对象将在这些节点中的任何一个上运行。
用于标记节点(你可以根据需要更改键值对):
kubectl label nodes iz2zegfpsrzdc0gb1tmnl9z nginx=pod
我们可以查看到给node新加的标签在node 的labels 里。
这次让我们使用规范下的 nodeSelector 再次创建我们的 nginx pod。
nginx-label-node.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
nginx: "pod"
创建:
kubectl apply -f nginx-label-node.yaml
查看:
kubectl get pods -o wide
Node Affinity (节点亲和性)类似于 nodeSelector,因为它们都使用标签来选择对象将在其上运行的节点。 目前,有两种类型的节点亲和性:requiredDuringSchedulingIgnoredDuringExecution,preferredDuringSchedulingIgnoredDuringExecution
第一个Affinity,requiredDuringSchedulingIgnoredDuringExecution,用于将k8s对象调度到节点时,节点上必须存在标签的情况。
另一方面,第二个Affinity,preferredDuringSchedulingIgnoredDuringExecution,用于增加 k8s 对象在节点上调度的机会。 因此,如果可能,所需的 k8s 对象将在该节点上运行。
让我们看看它们在行动中是如何工作的。 我将为每个工作节点创建一个标签。
kubectl label node worker-node-1 must=label
kubectl label node worker-node-2 nicetohave=label
配置nginx pod:
nginx-one-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: must
operator: In
values:
- label
containers:
- name: nginx
image: nginx
kubectl apply -f nginx-one-affinity.yaml
同样:
nginx-two-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nicetohave
operator: In
values:
- label
containers:
- name: nginx
image: nginx
创建
kubectl apply -f nginx-two-affinity.yaml
调度 Pod 时的另一个重要参数是资源。 想象一下,您有一个容器化的应用程序,需要一定数量的 CPU 功率和内存。 然后,你可能想要请求这些资源中的一部分。
让我们看看如何通过再次运行我们的 nginx 应用程序来做到这一点,这一次需要从节点获取资源并限制容器对资源的使用。
nginx-resouce-management.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
创建:
kubectl get pod
查看:
kubectl describe pod nginx
正如我们所见,nginx 应用程序现在限制为 500m CPU 和 128Mi 内存,需要 250m CPU 和 64Mi 内存。
到目前为止,我们只讨论了希望在特定节点上运行 Kubernetes 对象的情况。 但是,如果我们希望节点排斥 pod 怎么办。 如果是这种情况,我们需要使用污点。
与节点亲和性类似,污点也适用于标签。 这次我们需要用标签和效果来污染节点。 例如:
kubectl taint nodes worker-node-1 taint=node:NoSchedule
这样,我用标签 taint=node 和效果 NoSchedule 污染了我的第一个工作节点(worker-node-1)。 这意味着在此节点上,除非允许,否则不会在此 Pod 上调度任何 Kubernetes 对象。
kubectl run nginx --image=nginx
然后查看pod:
kubectl get pod
worker-node-1山的pod将不再显示。
那么如何容忍该节点上的 Kubernetes 对象呢?
为了让受污染的节点能够容忍 k8s 对象,您需要添加一个容忍度 (.spec.toleration)。 一个例子:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "taint"
operator: "Equal"
value: "node"
effect: "NoSchedule"
现在有了这个,容差Tolerations将被添加到 Pod 以在具有相同键、值和效果在受污染节点上运行。
现在我们看到它是由已被容忍的节点运行的。
注意:如果我有 2 个或更多节点并且在它们上运行的东西不多,调度程序可能会选择未污染的节点。 为了让 nginx 应用程序在它可以容忍的受污染节点上运行。
系列:1、Kubernetes 简介
系列:2、创建Kubernetes集群
系列:3、Kubectl 的使用
系列:4.1、Kubernetes 对象
系列:4.2、Kubernetes 工作负载
系列:4.3、Kubernetes 服务
系列:4.4、Kubernetes 存储
系列:4.5、Kubernetes 配置对象
系列:5、Kubernetes中的调度(本文)
系列:6、Kubernetes 的升级与部署策略
系列:7、 Kubernetes 安全性
系列:8、部署一个全栈应用