摘要:比如你有个业务:一个“Web服务Pod”要频繁读“缓存Pod”(比如Redis)的数据。如果这两个Pod不在同一台机器,Web服务每次读缓存都要跨机器传数据,速度慢、还耗网络;这时用“Pod亲和”,就能强制让“Web服务Pod”调度到“缓存Pod所在的机器”上
比如你有个业务:一个“Web服务Pod”要频繁读“缓存Pod”(比如Redis)的数据。如果这两个Pod不在同一台机器,Web服务每次读缓存都要跨机器传数据,速度慢、还耗网络;这时用“Pod亲和”,就能强制让“Web服务Pod”调度到“缓存Pod所在的机器”上——相当于让“服务员(Web)”和“仓库(缓存)”挨在一起,拿东西更快,效率更高。
再举个例子:你部署了“前端Pod”“后端Pod”“数据库Pod”,它们之间要频繁通信,用亲和调度让它们凑在同一台机器,能减少网络延迟,让整个业务跑起来更流畅。
比如你有个“数据库Pod”(比如MySQL),它需要占用机器大量的CPU、内存,还对磁盘IO要求很高;如果再把另一个“大数据计算Pod”(比如Spark)也调度到这台机器,两个Pod就会抢资源——数据库变慢、计算任务也卡壳,双双出问题;
这时用“Pod互斥”,就能强制让“大数据计算Pod”避开“数据库Pod所在的机器”,相当于“不让两个吃资源的‘大胃王’抢同一碗饭”,保证各自都能正常工作。
再比如:你部署了多个“相同的服务Pod”(比如3个Web服务),为了避免“一台机器挂了,所有Web服务都完蛋”,用互斥调度让这3个Pod分别待在3台不同的机器上——就算其中一台机器故障,另外两台的Web服务还能正常提供服务,业务不中断。
从例子中我们可以看出,这个东西很有用也很有必要。
下面看下实际是怎么运行的。
假如有一个Pod已经部署了,称为目标Pod,现在新创建的Pod想和它处在同一个节点机上,这种就称为亲和调度。下面准备做个实验,先安装redis,然后再安装whoami镜像,让whoami亲和redis的Pod。
首先安装Redis,做为目标Pod。
#文件名:redis-deployment.yaml cat redis-deployment.yaml apiVersion: apps/v1kind: Deploymentmetadata:name: redislabels:app: redisspec:replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redis # Pod 核心标签(whoami 会亲和这个标签)spec:containers:- name: redisimage: redis:6.2ports:- containerPort: 6379nodeSelector: zone: northEOF#部署 kubectl apply -f redis-deployment.yaml我这里使用nodeSelector将Redis调度到节点2机器上。
#文件名:whoami-with-podAffinity.ymlcat whoami-with-podAffinity.ymlapiVersion: apps/v1kind: Deploymentmetadata:name: whoamilabels:app: whoamispec:replicas: 1selector:matchLabels:app: whoamitemplate:metadata:labels:app: whoamispec:containers:- name: whoamiimage: crpi-gj5arn39i861t1eu.cn-hangzhou.personal.cr.aliyuncs.com/dev-team-sz/whoami# 核心:Pod 亲和配置 affinity:podAffinity: preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues: [redis]topologyKey: "kubernetes.io/hostname"EOF#部署kubectl apply -f whoami-with-podAffinity.yml和上篇的概念一样,软亲和就是尽量满足条件。
属性路径图示:
下面主要说下podAffinityTerm下属的几个字段:
labelSelector表示标签选择,是判断选择的条件。topologykey
简单说就是**“按什么范围算‘在一起’”**的划分标准。比如想让两个Pod“凑在一起”,但“在一起”可以有不同的范围:可以是“同一台服务器(节点)”、可以是“同一个个机房(机房)”、可以是“同一地区(region)”。
topologyKey就是用来指定这个范围的——它的值是节点上的一个标签键,调度器会根据这个标签判断“哪些范围算同一个组”。
当topologyKey:"kubernetes.io/hostname"时:表示“同一节点”才算“在一起”(因为每个节点的kubernetes.io/hostname标签值都是唯一的服务器名)。这时候Pod亲和就会让新Pod跑到目标Pod所在的那台具体服务器上。namespaceSelector
简单说就是**“给目标Pod加个‘命名空间过滤条件’”**,用来控制Pod亲和/互斥规则只对“特定命名空间里的Pod”生效。
举个例子:假设有两个命名空间:prod(生产环境)和test(测试环境),两个命名空间里都有带app=redis标签的Pod。
如果想让whoami只亲和生产环境(prod)里的Redis Pod,就可以用namespaceSelector限定范围——这样即使测试环境有同样标签的Redis,whoami也只会看生产环境的。如果不配置namespaceSelector,规则会匹配所有命名空间里符合标签的Pod。namespaces
直接指定具体的命名空间列表,让规则只对这些命名空间里的Pod生效。
和namespaceSelector对比理解更清楚:namespaceSelector是通过标签筛选命名空间(比如“所有带env=prod标签的命名空间”),而namespaces是直接写死命名空间名称(比如["prod","staging"])。
比如,我想部署两个whoami副本,但又不想调度到同一台机器上,在前面例子中说过,要是节点挂了,我这两个副本也一起完了。所以我想让它们必须不能调度到同一个节点上,那么互斥调度可以实现。
#文件名:whoami-anti-affinity.yamlcat whoami-anti-affinity.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: whoamilabels:app: whoamispec:replicas: 2selector:matchLabels:app: whoamitemplate:metadata:labels:app: whoami # 关键:所有副本都带这个标签,用于互斥匹配spec:containers:- name: whoamiimage: crpi-gj5arn39i861t1eu.cn-hangzhou.personal.cr.aliyuncs.com/dev-team-sz/whoamiaffinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- whoamitopologyKey: "kubernetes.io/hostname"EOF#部署 kubectl apply -f whoami-anti-affinity.yaml查看Pod,确实起作用了!!
whoami-.. 10.244.169.135 k8s-node2whoami-.. 10.244.36.113 k8s-node1由于结构相同,这里就不再做路径图示。
kubectl delete -f redis-deployment.yamlkubectl delete -f whoami-with-podAffinity.ymlkubectl delete -f whoami-anti-affinity.yamlrm -rf redis-deployment.yamlrm -rf whoami-with-podAffinity.ymlrm -rf whoami-anti-affinity.yaml来源:恋爱脑一点号