简介
Kubernetes,这个流行的容器编排平台,提供了一个强大的特性,称为“污点”(taints),用于控制 Pod 在节点上的调度。在本教程中,我们将探讨如何查看应用于 Kubernetes 节点的污点,这是有效管理 Kubernetes 集群的一项基本技能。
污点允许你使用特定的属性标记节点,这些属性可以排斥某些 Pod,确保工作负载根据节点的功能和资源得到适当的调度。了解如何查看和使用污点,有助于你在 Kubernetes 环境中保持最佳的资源分配。
设置用于测试的 Kubernetes 环境
在查看 Kubernetes 节点上的污点之前,我们需要一个正常运行的 Kubernetes 环境。对于本教程,我们将使用 Minikube,它提供了一个轻量级的本地 Kubernetes 集群,用于开发和测试目的。
让我们从安装 Minikube 开始:
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
rm minikube-linux-amd64
现在 Minikube 已经安装好了,让我们启动一个 Kubernetes 集群:
minikube start --driver=docker
你应该看到类似这样的输出:
😄 minikube v1.29.0 on Ubuntu 22.04
✨ Using the docker driver based on user configuration
📌 Using Docker driver with root privileges
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🔥 Creating docker container (CPUs=2, Memory=2200MB) ...
🐳 Preparing Kubernetes v1.26.1 on Docker 23.0.1 ...
▪ Generating certificates and keys ...
▪ Booting up control plane ...
▪ Configuring RBAC rules ...
🔎 Verifying Kubernetes components...
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟 Enabled addons: default-storageclass, storage-provisioner
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
让我们通过检查节点状态来验证集群是否正在运行:
kubectl get nodes
你应该看到类似这样的输出:
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 1m v1.26.1
太棒了!我们现在有了一个可以运行的 Kubernetes 环境来探索污点。kubectl 命令已经配置为与我们的 Minikube 集群一起工作。
理解 Kubernetes 污点
在开始查看污点之前,让我们先了解一下它们是什么,以及它们在 Kubernetes 中是如何工作的。
什么是污点?
污点是应用于 Kubernetes 节点的属性,允许节点排斥某些 Pod。可以将污点想象成标记节点不适合特定类型工作负载的标签。
污点与一个称为“容忍度”(tolerations)的概念一起工作。虽然污点应用于节点,但容忍度应用于 Pod。具有与节点污点匹配的容忍度的 Pod 可以在该被污点标记的节点上被调度。
污点结构
污点由三个部分组成:
- 键(Key):一个标识污点的字符串(例如,
gpu,disk,network) - 值(Value):分配给键的可选字符串(例如,
true,high-performance) - 影响(Effect):定义如何处理没有匹配容忍度的 Pod
最常见的污点影响有:
NoSchedule:没有匹配容忍度的新 Pod 将不会被调度到该节点上PreferNoSchedule:系统将尝试避免将没有匹配容忍度的 Pod 放置在该节点上,但不能保证NoExecute:没有匹配容忍度的新 Pod 将不会被调度到该节点上,并且没有匹配容忍度的现有 Pod 将被驱逐
以下是污点的语法:
- 带值:
key=value:effect - 无值:
key:effect
Kubernetes 集群中的某些节点具有默认污点。例如,控制平面节点通常被污点标记为 node-role.kubernetes.io/control-plane:NoSchedule,以防止常规工作负载在它们上面被调度,从而为系统组件保留资源。
让我们检查一下我们的 Minikube 节点,看看它是否有任何默认污点:
kubectl describe node minikube | grep -A3 Taints
你可能会看到类似这样的输出:
Taints: node-role.kubernetes.io/control-plane:NoSchedule
Unschedulable: false
Lease:
HolderIdentity: minikube
此输出显示我们的 Minikube 节点有一个污点,阻止常规 Pod 在其上被调度,因为它是一个控制平面节点。
查看 Kubernetes 节点上的污点
现在我们了解了什么是污点,让我们探索查看应用于 Kubernetes 节点的污点的不同方法。
方法 1:使用 kubectl describe
查看节点上污点的最详细方法是使用 kubectl describe node 命令:
kubectl describe node minikube
此命令输出有关节点的全面信息。要仅关注污点,你可以使用 grep:
kubectl describe node minikube | grep -A1 Taints
示例输出:
Taints: node-role.kubernetes.io/control-plane:NoSchedule
Unschedulable: false
方法 2:使用带有自定义列的 kubectl get
你可以使用带有自定义输出列的 kubectl get nodes 命令,仅显示污点:
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
示例输出:
NAME TAINTS
minikube [map[effect:NoSchedule key:node-role.kubernetes.io/control-plane]]
方法 3:使用带有 JSONPath 的 kubectl get
另一种方法是使用 JSONPath 提取污点信息:
kubectl get nodes minikube -o jsonpath='{.spec.taints}'
示例输出:
[{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"}]
为了更好的可读性,你可以将输出格式化为 JSON:
kubectl get nodes minikube -o jsonpath='{.spec.taints}' | jq .
如果你没有安装 jq,你可以使用以下命令安装它:
sudo apt-get update && sudo apt-get install -y jq
示例格式化输出:
[
{
"effect": "NoSchedule",
"key": "node-role.kubernetes.io/control-plane"
}
]
方法 4:使用带有 YAML 输出的 kubectl get
你还可以以 YAML 格式查看完整的节点规范并搜索污点:
kubectl get node minikube -o yaml | grep -A5 taints:
示例输出:
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
unschedulable: false
status:
addresses:
这些方法中的每一种都以不同的格式提供相同的信息。根据可读性以及你计划如何使用这些信息,选择最适合你需求的方法。
添加和移除污点
现在我们知道了如何查看污点,让我们学习如何添加和移除它们。当你需要控制 Pod 调度或为节点进行维护做准备时,这是一个常见的操作。
向节点添加污点
向节点添加污点的语法是:
kubectl taint nodes <node-name> <key>=<value>:<effect>
让我们向我们的 Minikube 节点添加一个污点,将其标记为具有 GPU:
kubectl taint nodes minikube gpu=true:NoSchedule
你应该看到类似这样的输出:
node/minikube tainted
现在,让我们验证污点是否已添加:
kubectl describe node minikube | grep -A3 Taints
示例输出:
Taints: gpu=true:NoSchedule
node-role.kubernetes.io/control-plane:NoSchedule
Unschedulable: false
Lease:
正如你所看到的,我们的节点现在有两个污点:原始的控制平面污点和我们新的 GPU 污点。
从节点移除污点
要移除污点,你需要在相同的污点定义后添加一个减号(-):
kubectl taint nodes <node-name> <key>=<value>:<effect>-
让我们移除我们刚刚添加的 GPU 污点:
kubectl taint nodes minikube gpu=true:NoSchedule-
你应该看到类似这样的输出:
node/minikube untainted
让我们验证污点是否已移除:
kubectl describe node minikube | grep -A3 Taints
示例输出:
Taints: node-role.kubernetes.io/control-plane:NoSchedule
Unschedulable: false
Lease:
HolderIdentity: minikube
现在我们的节点又只剩下控制平面污点了。
何时使用污点
污点在以下几种情况下特别有用:
- 专用硬件:使用专用硬件(如 GPU)对节点进行污点标记,以确保仅调度需要该硬件的工作负载
- 节点维护:在执行维护之前添加污点,以防止调度新的 Pod
- 安全隔离:出于安全原因,将某些工作负载与其他工作负载分开
- 资源优化:将节点专用于特定工作负载类型,以实现最佳资源利用率
通过了解如何查看、添加和移除污点,你已经获得了在 Kubernetes 集群中管理 Pod 调度的基本知识。
使用容忍度(Tolerations)
现在我们了解了污点的工作原理,让我们探索容忍度——允许 Pod 在带有匹配污点的节点上调度的机制。
理解容忍度
容忍度在 Pod 规范中指定,并允许 Pod 在具有匹配污点的节点上调度。一个容忍度由以下部分组成:
key:匹配污点键operator:Equal(匹配键和值)或Exists(仅匹配键)value:要匹配的值(使用Equal运算符时)effect:要匹配的 effect,或为空以匹配所有 effecttolerationSeconds:可选的持续时间,Pod 可以在具有匹配的NoExecute污点的节点上停留
创建一个带有容忍度的 Pod
让我们创建一个容忍我们的控制平面污点的 Pod。首先,让我们为我们的 Pod 创建一个 YAML 文件:
nano ~/project/toleration-pod.yaml
现在,将以下内容添加到文件中:
apiVersion: v1
kind: Pod
metadata:
name: toleration-pod
spec:
containers:
- name: nginx
image: nginx:latest
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
此 Pod 规范包含一个容忍度,该容忍度与我们节点上的控制平面污点匹配。保存并退出文件(在 nano 中,按 Ctrl+O,Enter,然后 Ctrl+X)。
现在,让我们创建 Pod:
kubectl apply -f ~/project/toleration-pod.yaml
你应该看到类似这样的输出:
pod/toleration-pod created
让我们检查 Pod 是否已在我们的节点上调度:
kubectl get pods -o wide
示例输出:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
toleration-pod 1/1 Running 0 12s 10.244.0.5 minikube <none> <none>
Pod 正在我们的 minikube 节点上运行,因为它有一个与控制平面污点匹配的容忍度。
使用没有容忍度的 Pod 进行测试
为了进行比较,让我们创建一个没有容忍度的 Pod:
nano ~/project/no-toleration-pod.yaml
添加以下内容:
apiVersion: v1
kind: Pod
metadata:
name: no-toleration-pod
spec:
containers:
- name: nginx
image: nginx:latest
保存并退出文件,然后创建 Pod:
kubectl apply -f ~/project/no-toleration-pod.yaml
现在,让我们检查 Pod 的状态:
kubectl get pods -o wide
你可能会注意到 Pod 仍然处于 Pending 状态:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
no-toleration-pod 0/1 Pending 0 12s <none> <none> <none> <none>
toleration-pod 1/1 Running 0 2m 10.244.0.5 minikube <none> <none>
让我们检查 Pod 为什么处于 Pending 状态:
kubectl describe pod no-toleration-pod
在 events 部分,你应该看到类似这样的内容:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 45s default-scheduler 0/1 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling.
这证实了 Pod 无法被调度,因为它不容忍控制平面污点。
清理
让我们清理我们创建的 Pod:
kubectl delete pod toleration-pod no-toleration-pod
你应该看到:
pod "toleration-pod" deleted
pod "no-toleration-pod" deleted
恭喜你!你现在了解了污点和容忍度如何协同工作以控制 Kubernetes 中的 Pod 调度。
总结
在这个实践实验中,你学习了如何使用 Kubernetes 污点和容忍度,这是控制集群中 Pod 调度的关键特性。以下是你完成的内容:
- 使用 Minikube 设置 Kubernetes 环境
- 理解污点的概念及其对 Pod 调度的影响
- 探索了在 Kubernetes 节点上查看污点的不同方法
- 使用 kubectl 命令从节点添加和移除污点
- 创建了带有和不带有容忍度的 Pod,以了解它们如何与被污点标记的节点交互
这些技能对于管理 Kubernetes 集群中的工作负载放置和资源分配至关重要。通过正确使用污点和容忍度,你可以确保 Pod 根据硬件要求、工作负载特征和资源限制在适当的节点上调度。
在你继续 Kubernetes 之旅的过程中,你可以基于这些知识构建更复杂的调度策略,例如节点亲和性和反亲和性,以进一步优化你的集群资源。


