第一期 K8s中如何将Deploy副本调度到指定节点

真成运维 2025-8-25 5 8/25

你好,我是老成,一名业务/项目运维工程师,就职于国内500强企业。关注我,学运维带你少走弯路!

第一期,K8s 业务运维日常工作中遇到的问题之 K8s 中如何将 Deploy 副本调度到指定节点。

问题描述

现在 K8s 集群中,只有两个节点开放了外网权限,你需要将一个 Deployment(2个副本)调度在这两个节点上运行,其中 Deployment 添加了 Pod 之间的反亲和性,就是2个副本无法调度在一个 K8s 节点中。

你应该如何配置,使其这2个副本调度在开放了外网的节点?

处理方案

需要结合使用节点亲和性 + Pod 反亲和性。

核心思路:

  1. 节点选择:使用 nodeSelector 或 nodeAffinity ,通过给节点打标签(Label)来限制 Pod 只能运行在指定的两个节点上。
  2. Pod 分布:使用 podAntiAffinity 确保两个 Pod 不会调度到同一个节点。

方案1:使用 nodeAffinity+podAntiAffinity

节点选择使用 nodeAffinity,Pod 选择使用 podAntiAffinity

步骤 1:为可外网的节点打上专属标签

首先,给你那两个有外网权限的节点打上一个易于识别的标签(例如:network=public)。

# 语法:kubectl label nodes <node-name> <label-key>=<label-value>
kubectl label nodes k8s-node-1 network=public
kubectl label nodes k8s-node-2 network=public

验证标签是否打成功:

kubectl get nodes --show-labels | grep 'network=public'

步骤 2:编写 Deployment YAML 配置

在 Deployment 的 Spec 中配置 affinity字段,同时包含 nodeAffinitypodAntiAffinity

apiVersion: apps/v1
kind: Deployment
metadata:
  name: your-public-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: your-public-app
  template:
    metadata:
      labels:
        app: your-public-app
    spec:
      affinity:
        # 节点亲和性 - 将 Pod 吸引到有 public 网络的节点
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: network
                operator: In
                values:
                - public

        # Pod 反亲和性 - 阻止 Pod 调度到已有相同应用的节点
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - your-public-app
            topologyKey: kubernetes.io/hostname
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

配置详解

  1. **nodeAffinity**(节点亲和性)
  • requiredDuringSchedulingIgnoredDuringExecution: 这是一个硬性要求。调度器必须将 Pod 分配到满足条件的节点上,否则 Pod 会处于 Pending 状态。
  • key: networkvalues: [public]: 这意味着 Pod 只会被调度到拥有 network=public标签的节点上。
  1. **podAntiAffinity**(Pod 反亲和性)
  • requiredDuringSchedulingIgnoredDuringExecution:同样是一个硬性要求。调度器必须满足这个分布条件。
  • labelSelector: 这里选择的是 Pod 自身的标签 (app: your-public-app)。意思是“寻找有 app=your-public-app标签的 Pod”。
  • topologyKey: kubernetes.io/hostname: 这是最关键的配置。它定义了“同一个拓扑域”的范围。kubernetes.io/hostname表示以节点主机名作为拓扑域。因此,该规则的含义是:“如果某个节点(hostname)上已经存在一个带有 app=your-public-app标签的 Pod,那么就禁止再把我调度到这个节点上”。

最终调度结果

根据以上配置,Kubernetes 调度器会得到如下逻辑:

  1. 筛选节点:首先,从所有节点中筛选出标签为 network=public的节点(假设只有 k8s-node-1k8s-node-2)。
  2. 分配第一个 Pod:随机选择其中一个节点(例如 k8s-node-1)运行第一个 Pod。
  3. 分配第二个 Pod:由于设置了反亲和性,调度器发现 k8s-node-1上已有相同应用的 Pod,因此它会将第二个 Pod 调度到另一个也是 network=public的节点 k8s-node-2上。
  4. 完美达成目标:两个 Pod 分别运行在两个有公网的节点上,且彼此隔离。

方案2:使用 nodeSelector(更简单但不灵活)

如果你的需求很简单,只是绑定标签,也可以不使用 nodeAffinity,而用更简单的 nodeSelector。但仍然需要 podAntiAffinity 来保证 Pod 分散。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: your-public-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: your-public-app
  template:
    metadata:
      labels:
        app: your-public-app
    spec:
      nodeSelector: # 使用更简单的 nodeSelector
        network: public
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - your-public-app
            topologyKey: kubernetes.io/hostname
      containers:
      - name: your-app-container
        image: your-image:latest

nodeAffinityvs nodeSelector:

  • nodeSelector更简单,但功能单一(只能简单匹配)。
  • nodeAffinity功能更强大,可以支持更复杂的表达式(如 In, NotIn, Exists, Gt, Lt等),是官方推荐的高级用法。

总结

工具 作用 实现需求
节点标签 network=public 标记目标节点 将 Pod 限制在特定节点
节点亲和性 nodeAffinity 吸引 Pod 到标签节点 将 Pod 限制在特定节点
Pod 反亲和性 podAntiAffinity 排斥具有相同标签的 Pod 确保副本分散在不同节点

END

这篇文章有用吗?

点击星号为它评分!

平均评分 0 / 5. 投票数: 0

到目前为止还没有投票!成为第一位评论此文章。

很抱歉,这篇文章对您没有用!

让我们改善这篇文章!

告诉我们我们如何改善这篇文章?

- THE END -

真成运维

8月25日23:25

最后修改:2025年8月25日
0

非特殊说明,本博所有文章均为博主原创。