将 Pod 指派给节点
我们可以约束pod,然后将pod放到指定的节点上。
节点标签
我们可以给节点加标签,然后就可以被查询和识别。
查询节点
kubectl get nodes给节点加标签
kubectl label nodes 节点名称 key=value例如:想给node01添加一个type=worker
kubectl label nodes node01 type=worker结果
controlplane $ kubectl label nodes node01 type=worker
node/node01 labeled查看所有标签
kubectl get nodes --show-labels结果:type=worker成功添加
controlplane $ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
controlplane Ready control-plane 28d v1.27.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=controlplane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node01 Ready <none> 28d v1.27.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux,type=worker删除标签
kubectl label nodes 节点名称 key-例如:删除type
kubectl label nodes node01 type-结果:
controlplane $ kubectl label nodes node01 type-
node/node01 unlabeled通过标签查看节点
使用 -l 参数
controlplane $ kubectl get nodes -l kubernetes.io/hostname=node01
NAME STATUS ROLES AGE VERSION
node01 Ready <none> 28d v1.27.1查询节点上的所有pod
因为node名字部署标签,所以使用字段选择器可以看到某个节点上分配的node
kubectl get pods --field-selector spec.nodeName=node01查看所有pod所在节点
kubectl get pods --output=wide现在,我们添加type=worker 开始我们实验pua
nodeSelector
我们可以将pod轻松的放置到指定node,可以使用nodeSelector简单实现
该标签在pod模板中,在kind=pod应该也可以写吧
下面,我们使用该标签,将服务放到指定的集群上。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx-dep
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1
ports:
- containerPort: 80
nodeSelector:
type: worker因为type=worker在node01上,查询node01上的节点
controlplane $ kubectl get pods --field-selector spec.nodeName=node01
NAME READY STATUS RESTARTS AGE
nginx-c7656f7cd-4mrh9 1/1 Running 0 72s
nginx-c7656f7cd-9kgmf 1/1 Running 0 72s
nginx-c7656f7cd-flm9s 1/1 Running 0 72s现在,我们做两种尝试:直接修改yaml,去掉nodeSelector字段,看看pod会不会重新调度
猜测:不会,因为pod仍然符合
结果:重新发生了调度,并且跟换了pod
controlplane $ kubectl get pods --field-selector spec.nodeName=node01
NAME READY STATUS RESTARTS AGE
nginx-74b6b979f-lchtm 1/1 Running 0 28s
nginx-74b6b979f-w7vbd 1/1 Running 0 16s亲和性与反亲和性
nodeSelector实现了简单的node标签匹配,我们想要实现复杂的匹配,我们可以采用亲和性。
亲和性和反亲和性的好处:
- 亲和性表达能力更强,表示对哪个节点更倾向,而nodeSelector只能指定标签
- 可以表明为软需求或者偏好,如果无法找到匹配项仍然调度该节点
- 你可以使用节点上(或其他拓扑域中)运行的其他Pod的标签来实施调度约束,而不是只能使用节点本身的标签,这样子可以进行Pod之间的约束。
节点亲和性
节点亲和性类似于nodeSelector,他使你可以根据节点上的标签来约束Pod可以调度在哪些节点上。
requiredDuringSchedulingIgnoredDuringExecution: 调度器只有在规则被满足的时候才能执行调度。此功能类似于nodeSelector, 但其语法表达能力更强。preferredDuringSchedulingIgnoredDuringExecution: 调度器会尝试寻找满足对应规则的节点。根据权重选择适合的节点,如果找不到匹配的节点,调度器仍然会调度该 Pod。
注:IgnoredDuringExecution后缀表示,如果在pod运行期间,node的label发生改变,pod仍然继续运行。然而nodeSelector会因为node标签发生改变而重新进行调度
例如下面的:Deployment
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- antarctica-east1
- antarctica-west1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: type
operator: In
values:
- worker此对象会选择地域为antarctica-east1,antarctica-west1的node,并且node的类型最好为worker节点 (type是自己打上去的)
requiredDuringSchedulingIgnoredDuringExecution
该属性下会有nodeSelectorTerms属性,它是一个matchExpressions数组
matchExpressions何selector中的matchExpressions差不多
可使用操作符: In、NotIn、Exists、DoesNotExist、Gt 和 Lt
注:必须nodeSelectorTerms内的所有matchExpressions都匹配才能成功匹配
preferredDuringSchedulingIgnoredDuringExecution
该属性是一个数组,含有weight(权重)和preference(偏向)属性
进行node选择时,会对每个preferredDuringSchedulingIgnoredDuringExecution成员 进行匹配,若匹配成功,则加上权重。结果为得到全部权重和。最后按最大权重选择节点。
注意:
如果你同时指定了 nodeSelector 和 nodeAffinity,两者 必须都要满足, 才能将 Pod 调度到候选节点上。
如果你指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms, 只要其中一个 nodeSelectorTerms 满足的话,Pod 就可以被调度到节点上。
如果你指定了多个与同一 nodeSelectorTerms 关联的 matchExpressions, 则只有当所有 matchExpressions 都满足时 Pod 才可以被调度到节点上。
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions: # nodeSelectorTerm 1
- key: disk-type
operator: In
values:
- ssd
- key: cpu-type
operator: In
values:
- high-performance
- matchExpressions: # nodeSelectorTerm 2
- key: gpu-type
operator: In
values:
- nvidia例如上面:nodeSelectorTerm 1和nodeSelectorTerm 2之间只要一个就可以了。而nodeSelectorTerm 1内的matchExpressions必须所有都满足。
逐个调度方案(1.20+)
可以在调度器配置的 args 字段添加 addedAffinity实现pod的调度。
apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
- schedulerName: foo-scheduler
pluginConfig:
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: scheduler-profile
operator: In
values:
- foo然后在pod里指定调度器名字(待验证)
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
schedulerName: appPod亲和性与反亲和性
Pod 间亲和性与反亲和性使你可以基于已经在节点上运行的 Pod 的标签来约束 Pod 可以调度到的节点,而不是基于节点上的标签。
定义:
“如果 X 上已经运行了一个或多个满足规则 Y 的 Pod, 则这个 Pod 应该(或者在反亲和性的情况下不应该)运行在 X 上”。 这里的 X 可以是节点、机架、云提供商可用区或地理区域或类似的拓扑域, Y 则是 Kubernetes 尝试满足的规则。
与节点亲和性类似,Pod 的亲和性与反亲和性也有两种类型:
requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution
区别:
- 节点只有亲和性,pod有亲和性和反亲和性,要使用 Pod 间亲和性,可以使用 Pod 规约中的
.affinity.podAffinity字段。 对于 Pod 间反亲和性,可以使用 Pod 规约中的.affinity.podAntiAffinity字段。
与节点亲和性类似,Pod 的亲和性与反亲和性也有两种类型:
requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: topology.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: registry.k8s.io/pause:2.0注:topologyKey表示域选择标签,匹配规则会按域为一个整体来匹配。例如下面的对象,按zone匹配,如果一个zone中,至少需要有一个匹配,就可以调度到该zone上。如果一个zone中,存在security时,最好不要放在这个zone上
topologyKey 可以是任何合法的标签键。出于性能和安全原因,topologyKey 有一些限制:
对于 Pod 亲和性而言,在
requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution中,topologyKey不允许为空。对于
requiredDuringSchedulingIgnoredDuringExecution要求的 Pod 反亲和性, 准入控制器LimitPodHardAntiAffinityTopology要求topologyKey只能是kubernetes.io/hostname。如果不想要这种控制可以禁用或者采用其他准入控制器。
命名空间选择算符
用户可以使用亲和性规约中的namespaceSelector选择对应算符用来匹配特定的项目
template:
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- namespaceSelector:
matchExpressions:
- key: name
operator: In
values:
- nameValue也有namespaces选定对应的亲和性
template:
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- namespaces:
- abbb
- cddd例子
现在,我们需要一个3组服务,每个服务需要两个子(web-store,store),他们需要在不同节点上。
思路:将一个服务(store)使用pod反亲和性,分布在不同节点,如何另一个(web-store)使用pod亲和性靠近这个服务(store),反亲和性分布在不同的节点上。
apiVersion: apps/v1
kind: Deployment
metadata:
name: store-deploy
labels:
app: store-deploy
spec:
replicas: 3
selector:
matchLabels:
app: store
template:
metadata:
name: store
labels:
app: store
spec:
containers:
- name: store
image: redis
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: "kubernetes.io/hostname"
labelSelector:
matchLabels:
app: store
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-store-deploy
labels:
app: web-store-deploy
spec:
replicas: 3
selector:
matchLabels:
app: web-store
template:
metadata:
name: web-store
labels:
app: web-store
spec:
containers:
- name: web-store
image: nginx
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: "kubernetes.io/hostname"
labelSelector:
- matchLabels:
app: store
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: "kubernetes.io/hostname"
labelSelector:
matchLabels:
app: web-storenodeName
直接将pod指派给node,这样子更加直接,要考虑当前节点的稳定性问题
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: kube-01Pod 拓扑分布约束
控制pod在 区域(Region)、可用区(Zone)、节点和其他用户自定义的拓扑域间的约束
使用该约束,可以实现高可用部署,保证数据的高可用行。
使用该部署不是可以实现弹性伸缩,我们可以使用k8s的来HPA实现弹性扩容
Horizontal Pod Autoscaler (HPA):水平 Pod 自动伸缩器
Cluster Autoscaler:集群自动伸缩器
运算符总结
nodeAffinity和podAffinity可以使用In,NotIn,Exists,DoesNotExist
nodeAffinity可以增加使用Gt(小于),Lt(大于)