Shell脚本如何配置容器节点亲和:从基础到生产级实践指南
目录导读
- 什么是容器节点亲和性?为什么需要它?
- Kubernetes节点亲和性核心概念
- Shell脚本配置节点亲和性的三种方法
- 实战:Shell脚本自动生成动态亲和性配置
- 常见问题与排错(QA)
- 生产环境最佳实践
什么是容器节点亲和性?为什么需要它?
节点亲和性(Node Affinity) 是Kubernetes调度器用来决定Pod应该运行在哪些节点上的规则,它允许运维人员通过标签(Labels)和选择器(Selectors)控制Pod的部署位置,从而实现:

- 性能优化:将GPU密集型Pod调度到带GPU的节点
- 成本控制:将高内存Pod调度到低价实例
- 合规性:确保数据驻留在特定地理区域的节点
❓ 问:节点亲和性与节点选择器(nodeSelector)有什么区别?
答:nodeSelector仅支持精确匹配(等于),而节点亲和性支持更复杂的逻辑:In(属于)、NotIn(不属于)、Exists(存在标签)、DoesNotExist(标签不存在),以及软性(preferred)和硬性(required)两种约束级别。
Kubernetes节点亲和性核心概念
1 两种亲和性类型
- requiredDuringSchedulingIgnoredDuringExecution:Pod必须满足该规则才能被调度(硬约束)
- preferredDuringSchedulingIgnoredDuringExecution:调度器会尽量满足,但不强制(软约束)
2 节点标签操作示例
# 给节点添加自定义标签 kubectl label nodes worker-node-1 disktype=ssd # 查看节点标签 kubectl get nodes --show-labels # 删除标签 kubectl label nodes worker-node-1 disktype-
3 YAML中的亲和性写法
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
Shell脚本配置节点亲和性的三种方法
直接生成带亲和性的Pod YAML
#!/bin/bash
# 生成一个带有节点亲和性的Deployment配置
cat <<EOF > redis-affinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- nvme
containers:
- name: redis
image: redis:6.2
EOF
echo "已生成 affinity 配置文件"
kubectl apply -f redis-affinity.yaml
动态读取节点标签并生成规则
#!/bin/bash
# 自动采集节点列表,生成多条件亲和性
NODES=$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}')
for NODE in $NODES; do
ZONE=$(kubectl get node $NODE -o jsonpath='{.metadata.labels.topology\.kubernetes\.io/zone}')
GPU_COUNT=$(kubectl get node $NODE -o jsonpath='{.metadata.labels.nvidia\.com/gpu\.count}')
if [[ "$GPU_COUNT" -gt 0 && "$ZONE" == "us-east-1a" ]]; then
echo "节点 $NODE 符合条件: GPU=$GPU_COUNT, 区域=$ZONE"
# 生成专属亲和性配置
sed "s/__ZONE__/$ZONE/g" template.yaml > gpu-deploy.yaml
kubectl apply -f gpu-deploy.yaml
fi
done
通过kubectl patch实时修改
#!/bin/bash
# 给已有Deployment添加节点亲和性
DEPLOY_NAME="my-app"
kubectl patch deployment $DEPLOY_NAME -p '{
"spec": {
"template": {
"spec": {
"affinity": {
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [{
"matchExpressions": [{
"key": "node-role.kubernetes.io/worker",
"operator": "Exists"
}]
}]
}
}
}
}
}
}
}'
echo "已为 $DEPLOY_NAME 添加节点亲和性"
实战:Shell脚本自动生成动态亲和性配置
以下是一个生产级脚本,可根据集群资源动态分配Pod:
#!/bin/bash
# 文件名: create-affinity-deploy.sh
# 用途: 根据节点剩余CPU和内存,自动生成带权重亲和性的部署
set -e
CLUSTER_PREFIX="hpc-worker"
APP_NAME="simulation-job"
LABEL_KEY="compute-class"
NODE_SELECTOR="cpu=high"
# 获取可用节点列表
AVAILABLE_NODES=$(kubectl get nodes -l node-role.kubernetes.io/worker -o name | awk -F'/' '{print $2}')
# 为每个节点计算资源并生成动态亲和性
for NODE in $AVAILABLE_NODES; do
# 获取节点CPU和内存使用率
CPU_ALLOC=$(kubectl describe node $NODE | grep "Allocated resources" -A 5 | grep cpu | awk '{print $4}' | sed 's/%//')
MEM_ALLOC=$(kubectl describe node $NODE | grep "Allocated resources" -A 5 | grep memory | awk '{print $4}' | sed 's/%//')
if [[ $CPU_ALLOC -lt 60 && $MEM_ALLOC -lt 70 ]]; then
echo "节点 $NODE 资源充足,设置标签 $LABEL_KEY=high"
kubectl label node $NODE "$LABEL_KEY=high" --overwrite
else
echo "节点 $NODE 资源紧张,设置标签 $LABEL_KEY=standard"
kubectl label node $NODE "$LABEL_KEY=standard" --overwrite
fi
done
# 应用带软亲和性的部署(优先调度到high节点)
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: $APP_NAME
spec:
replicas: 5
selector:
matchLabels:
app: $APP_NAME
template:
metadata:
labels:
app: $APP_NAME
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: $LABEL_KEY
operator: In
values:
- high
- weight: 20
preference:
matchExpressions:
- key: $LABEL_KEY
operator: In
values:
- standard
containers:
- name: sim-container
image: simulation:latest
resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "4"
memory: "8Gi"
EOF
echo "部署完成,Pod将优先调度到高资源节点"
常见问题与排错(QA)
Q1:为什么设置了硬亲和性,Pod仍然Pending?
A:可能原因:
- 节点标签不存在或拼写错误 → 运行
kubectl get nodes --show-labels确认 - 所有节点都不满足条件 → 检查
nodeSelectorTerms逻辑,考虑添加软亲和性作为兜底 - 节点Taints未容忍 → 同时检查
tolerations
Q2:如何测试节点亲和性配置是否正确?
A:使用kubectl explain pod.spec.affinity.nodeAffinity查看官方文档;
也可以通过kubectl get pod -o yaml <pod-name> | grep -A 10 nodeAffinity验证是否生效。
Q3:Shell脚本批量修改后如何回滚?
A:建议在执行前备份当前配置:
kubectl get deployment <name> -o yaml > backup-$(date +%s).yaml
回滚时使用备份文件覆盖:
kubectl replace -f backup-xxx.yaml
生产环境最佳实践
- 避免硬亲和性滥用:硬亲和性可能导致调度失败,建议在关键服务中使用软亲和性+权重设计
- 标签命名规范:使用
infra.kubernetes.io/或company.com/前缀避免冲突 - 自动化标签管理:通过Shell脚本+cronjob定期清理过期标签
- 结合PodAntiAffinity:配合使用
podAntiAffinity实现高可用分散部署 - 监控与告警:监控Pod调度延迟,设置规则当长时间Pending时触发告警
通过以上Shell脚本实践,你已经掌握了从基础配置到生产级动态调度的能力,节点亲和性配置是Kubernetes集群精细化运维的基石,建议先在测试环境验证脚本逻辑,再逐步推广到生产集群,更多高级用法,可参考Kubernetes官方文档的“Assigning Pods to Nodes”章节,或搜索社区中基于Shell的自动化运维方案(例如在github.com/kubernetes/kubernetes中搜索相关Issue)。