最近更新时间:2024-12-03 20:50:59
在 Kubernetes 集群管理中,为确保集群的稳定性和可靠性,避免因节点故障引发一系列严重问题,我们强烈建议不要在 Deployment 或 StatefulSet 中设置 nodeName 字段,而是采用更为灵活和可靠的 nodeSelector 或 affinity 规则进行节点调度。
节点故障场景
在 Kubernetes 集群运行过程中,节点可能会由于多种原因发生故障,例如硬件故障、软件崩溃、网络问题等。当节点出现故障时,该节点上运行的关键组件(如 kubelet)的功能将受到影响。
kubelet 状态上报失效
kubelet 在 Kubernetes 集群中负责与节点上运行的容器和其他组件进行交互,并向 kube-controller-manager 上报节点和容器的状态信息。一旦节点发生故障,kubelet 将无法正常工作,导致无法及时准确地向 kube-controller-manager 反馈节点状态。
节点标记为 not-ready
kube-controller-manager 依赖 kubelet 上报的状态信息来判断节点的健康状况。当在一定时间内未收到节点的状态更新时,kube-controller-manager 会将该节点标记为 not-ready 状态,以表示该节点当前不可用于新的 Pod 调度。
添加 NoExecute 污点
同时,为了防止不健康节点对集群造成更大的影响,kube-controller-manager 会在标记为 not-ready 的节点上添加 NoExecute 污点。这个污点会影响已经在该节点上运行的 Pod。
Pod 驱逐触发
当节点被添加了 NoExecute 污点后,根据 Kubernetes 的 Pod 驱逐策略,那些对污点敏感的 Pod 将被驱逐。如果 Deployment 或 StatefulSet 中使用了 nodeName 字段来指定 Pod 运行的节点,那么这些被驱逐的 Pod 在重新创建时,由于配置中固定了 nodeName,会尝试重新调度到已经故障的节点上。
循环创建现象
由于节点故障未解决,被驱逐的 Pod 重新创建到故障节点后,可能会再次被驱逐,如此反复,形成 Pod 的循环创建和驱逐。这种循环会导致大量 Pod 处于 Terminating 状态,增加集群的负担。
资源消耗
在 Pod 循环创建和驱逐的过程中,会消耗大量的系统资源,包括 CPU、内存和网络带宽等。尤其是内存资源,在频繁的 Pod 操作过程中,可能会迅速被耗尽。
服务 OOM 错误
关键服务(如 apiserver 和 etcd)依赖于足够的系统资源来维持正常运行。当集群资源被大量用于处理故障节点相关的 Pod 问题时,这些关键服务可能会因为得不到足够的内存而出现 OOM(内存溢出)错误,进而导致整个 Kubernetes 集群的服务中断或不稳定。
原理
nodeSelector 是一种基于标签的简单节点选择方法。在 Kubernetes 中,节点和 Pod 都可以被打上标签。标签是由键值对组成的元数据,用于描述节点或 Pod 的特定属性。nodeSelector 通过在 Pod 的配置中指定所需的节点标签,使 Pod 能够被调度到具有相应标签的节点上。
配置步骤
(1)节点标签设置:使用 kubectl 命令为节点添加标签。例如,若要为节点 node-1 添加一个名为 “env=production” 的标签,可以执行以下命令:
kubectl label nodes node-1 env=production
(2)Pod 配置:在 Deployment 或 StatefulSet 的 Pod 模板中配置 nodeSelector。以下是一个示例的 Deployment 配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
nodeSelector:
env: production
containers:
- name: my-container
image: my-image
配置效果
上述配置确保了名为 “my-deployment” 的 Deployment 所创建的 Pod 将被调度到具有 “env=production” 标签的节点上。
原理
nodeAffinity(节点亲和性)提供了更灵活和强大的节点选择机制。它支持更复杂的逻辑和条件判断,能够更好地满足多样化的集群调度需求。
配置步骤
以下是一个使用 requiredDuringSchedulingIgnoredDuringExecution 类型的节点亲和性的示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk-type
operator: In
values:
- ssd
containers:
- name: my-container
image: my-image
配置效果
在上述配置中,Pod 在调度时要求节点具有 “disk-type=ssd” 的标签。这种配置方式能够根据节点的特定属性进行更精准的调度。
disablenodename-admission 是一个遵循标准 Admission wehook 规范的组件,其核心功能是禁止用户在创建或更新 Deployment 和 StatefulSet 时中设置 NodeName 字段,以防止用户将Pod强制调度到特定节点。
在 Pod 创建过程中,disablenodename-admission 组件会介入 Pod 的创建请求处理流程。当它检测到 Pod 的 PodTemplateSpec 中存在 nodeName 字段时,会立即拒绝该 Pod 的创建操作,并返回明确的错误提示信息,引导用户采用 nodeSelector 或 affinity 规则进行节点调度。
当前版本为 0.1.0,适用于各种 Kubernetes 集群环境,特别是对集群稳定性和可靠性要求较高的生产环境。通过部署和启用该组件,可以有效地预防因不恰当使用 nodeName 字段而导致的集群故障风险。
注意:新增disablenodename-admission组件需要集群K8s版本在v1.16.0以上;如果您当前集群版本小于v1.16.0,请考虑按需升级,以避免组件安装失败。
在 Kubernetes 集群的管理和操作中,避免在 Deployment 或 StatefulSet 中设置 nodeName 字段,并合理运用 nodeSelector 或 affinity 规则进行节点调度,是保障集群稳定运行的重要实践。同时,借助 disablenodename-admission 组件可以进一步强化这种配置规范,确保集群的可靠性和安全性。
纯净模式
鼠标选中内容,快速反馈问题