Shell脚本如何配置容器节点亲和

wen 实用脚本 2

Shell脚本如何配置容器节点亲和:从基础到生产级实践指南

目录导读

  1. 什么是容器节点亲和性?为什么需要它?
  2. Kubernetes节点亲和性核心概念
  3. Shell脚本配置节点亲和性的三种方法
  4. 实战:Shell脚本自动生成动态亲和性配置
  5. 常见问题与排错(QA)
  6. 生产环境最佳实践

什么是容器节点亲和性?为什么需要它?

节点亲和性(Node Affinity) 是Kubernetes调度器用来决定Pod应该运行在哪些节点上的规则,它允许运维人员通过标签(Labels)和选择器(Selectors)控制Pod的部署位置,从而实现:

Shell脚本如何配置容器节点亲和

  • 性能优化:将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

生产环境最佳实践

  1. 避免硬亲和性滥用:硬亲和性可能导致调度失败,建议在关键服务中使用软亲和性+权重设计
  2. 标签命名规范:使用infra.kubernetes.io/company.com/前缀避免冲突
  3. 自动化标签管理:通过Shell脚本+cronjob定期清理过期标签
  4. 结合PodAntiAffinity:配合使用podAntiAffinity实现高可用分散部署
  5. 监控与告警:监控Pod调度延迟,设置规则当长时间Pending时触发告警

通过以上Shell脚本实践,你已经掌握了从基础配置到生产级动态调度的能力,节点亲和性配置是Kubernetes集群精细化运维的基石,建议先在测试环境验证脚本逻辑,再逐步推广到生产集群,更多高级用法,可参考Kubernetes官方文档的“Assigning Pods to Nodes”章节,或搜索社区中基于Shell的自动化运维方案(例如在github.com/kubernetes/kubernetes中搜索相关Issue)。

抱歉,评论功能暂时关闭!