你好,我是老成,一名业务/项目运维工程师,就职于国内500强企业。关注我,学运维带你少走弯路!
第一期,K8s 业务运维日常工作中遇到的问题之 K8s 中如何将 Deploy 副本调度到指定节点。
问题描述
现在 K8s 集群中,只有两个节点开放了外网权限,你需要将一个 Deployment(2个副本)调度在这两个节点上运行,其中 Deployment 添加了 Pod 之间的反亲和性,就是2个副本无法调度在一个 K8s 节点中。
你应该如何配置,使其这2个副本调度在开放了外网的节点?
处理方案
需要结合使用节点亲和性 + Pod 反亲和性。
核心思路:
-
节点选择:使用 nodeSelector 或 nodeAffinity ,通过给节点打标签(Label)来限制 Pod 只能运行在指定的两个节点上。 -
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
字段,同时包含 nodeAffinity
和 podAntiAffinity
。
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
配置详解
-
**nodeAffinity**
(节点亲和性)
-
requiredDuringSchedulingIgnoredDuringExecution
: 这是一个硬性要求。调度器必须将 Pod 分配到满足条件的节点上,否则 Pod 会处于 Pending 状态。 -
key: network
和values: [public]
: 这意味着 Pod 只会被调度到拥有network=public
标签的节点上。
-
**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 调度器会得到如下逻辑:
-
筛选节点:首先,从所有节点中筛选出标签为 network=public
的节点(假设只有k8s-node-1
和k8s-node-2
)。 -
分配第一个 Pod:随机选择其中一个节点(例如 k8s-node-1
)运行第一个 Pod。 -
分配第二个 Pod:由于设置了反亲和性,调度器发现 k8s-node-1
上已有相同应用的 Pod,因此它会将第二个 Pod 调度到另一个也是network=public
的节点k8s-node-2
上。 -
完美达成目标:两个 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
nodeAffinity
vs nodeSelector
:
-
nodeSelector
更简单,但功能单一(只能简单匹配)。 -
nodeAffinity
功能更强大,可以支持更复杂的表达式(如In
,NotIn
,Exists
,Gt
,Lt
等),是官方推荐的高级用法。
总结
工具 | 作用 | 实现需求 |
---|---|---|
节点标签 network=public |
标记目标节点 | 将 Pod 限制在特定节点 |
节点亲和性 nodeAffinity |
吸引 Pod 到标签节点 | 将 Pod 限制在特定节点 |
Pod 反亲和性 podAntiAffinity |
排斥具有相同标签的 Pod | 确保副本分散在不同节点 |
END
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://www.qiuyl.com/xueyw/yewuywrcwt/467
Abutogel: <a href=" https://abutowin.icu/# ">S...