惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
L
LINUX DO - 最新话题
Recorded Future
Recorded Future
月光博客
月光博客
博客园 - 【当耐特】
博客园 - 叶小钗
宝玉的分享
宝玉的分享
量子位
雷峰网
雷峰网
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
Vercel News
Vercel News
L
LangChain Blog
B
Blog
Y
Y Combinator Blog
爱范儿
爱范儿
GbyAI
GbyAI
S
Security @ Cisco Blogs
T
The Blog of Author Tim Ferriss
A
About on SuperTechFans
博客园 - Franky
P
Palo Alto Networks Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
云风的 BLOG
云风的 BLOG
C
Cisco Blogs
Scott Helme
Scott Helme
I
Intezer
T
The Exploit Database - CXSecurity.com
MyScale Blog
MyScale Blog
T
Tor Project blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Troy Hunt's Blog
N
News and Events Feed by Topic
大猫的无限游戏
大猫的无限游戏
F
Fortinet All Blogs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Security Affairs
Cyberwarzone
Cyberwarzone
PCI Perspectives
PCI Perspectives
小众软件
小众软件
D
DataBreaches.Net
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Know Your Adversary
Know Your Adversary
Forbes - Security
Forbes - Security
S
Securelist
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
The Last Watchdog
The Last Watchdog

蛮荆

如何获取更多的免费服务器 Kubernetes 调度器队列 - 设计与实现 Kubernetes 调度器 - 核心流程 Kubernetes Networking Model & CNI Kubernetes 控制器管理总结 Kubernetes CronJob 设计与实现 Kubernetes Job 设计与实现 Kubernetes HPA 设计与实现 Kubernetes Deployment 滚动更新实现原理 Kubernetes GC 设计与实现 Kubernetes Pod 驱逐 - 设计与实现 Kubernetes Daemonset 设计与实现 Kubernetes ReplicaSet 设计与实现 Kubernetes EndPoint 设计与实现 Kubernetes Informer 设计与实现 降本增效之应用优化 (三) 日志存储与检索 Kubernetes Pod 设计与实现 - 创建流程 Kubernetes 探针设计与实现 Unix 编程艺术名句摘录 Kubernetes - CRI 概述 Golang 编译速度为什么这么快? Kubernetes Pod 设计与实现 - Pause 容器 Kubernetes - kube-proxy 代理模式工程优化 Kubernetes 应用最佳实践 - 优雅关闭长连接 Kubernetes Service 类型和会话亲和性 Kubernetes 为什么需要 Ingress Kubernetes 架构 - 控制平面和数据平面 降本增效之应用优化 (二) 大报表 Go 语言如何获取 CPU 利用率 降本增效之应用优化 (一) Redis 业务规则引擎演变过程简述 微服务中的熔断算法 漏桶算法和令牌桶算法 jsonparser 为什么比标准库的 encoding/json 快 10 倍 ? zap 高性能设计与实现 HTTP Router 算法演进 fastcache 高性能设计与实现 Web 常见的三个安全问题 ants Code Reading Go 线程安全 map 方案选型 布隆过滤器 死锁、活锁、饥饿、自旋锁 sync.Pool Code Reading Go 内存管理概述 Go netpoll Code Reading goroutine 泄漏与检测 time/Timer Code Reading GMP Scheduler Code Reading Go channel 的 15 条规则和底层实现 为什么 Linux “一切皆文件” context.Context Code Reading runtime/HACKING.md Goland 最佳实践 互联网开发与金庸武学 为什么 Redis 6.0 引入多线程模型? Kubernetes 应用最佳实践 - 金丝雀发布 容器中如何正确配置 GOMAXPROCS ? singleflight Code Reading sync.Map Code Reading sync.Cond Code Reading sync.WaitGroup Code Reading sync.RWMutex Code Reading sync.Mutex Code Reading sync.Once Code Reading Go 无锁编程 sync/atomic Code Reading goroutine 交替打印奇偶数 GODEBUG Go 并发模式 Go 汇编 UUID 通用技术选型 Kubernetes 应用最佳实践 - 水平自动伸缩 Go 高性能 Tips fasthttp 为什么比标准库 net/http 快 10 倍 ? 技术文章配图指南 ChatGPT 初体验 Docker 网络原理概览 iptables 的五表五链 Go 的反射与三大定律 Docker 官方提供的最佳实践 Go 语言内置的设计模式 HTTP1 到 HTTP3 的工程优化 Kubernetes 应用最佳实践 - Sidecar 模式 Kubernetes 应用最佳实践 - init 容器和钩子函数 为什么 recover 必须在 defer 中调用? 为什么 defer 的执行顺序和注册顺序不同? Go map 设计与实现 Go 切片扩容底层实现 Go 语言中的零拷贝 Go Delve 云原生和边缘计算简介 Kubernetes Pod 服务质量等级 Kubernetes 应用最佳实践 - 探针 Kubernetes 应用最佳实践 - 资源请求和限制 CDN 原理 Kubernetes 应用最佳实践 - 开篇 缓存策略和模式 Go 内存模型 Kubernetes 核心概念 软件版本语义化
Kubernetes 应用最佳实践 - 亲和性和污点容忍度
2023-03-31 · via 蛮荆

2023-03-31 Cloud Native Kubernetes Kubernetes 应用最佳实践

亲和性

亲和性用于指定某个 Pod 应该或尽可能在哪些 Node 上运行。

两种策略

1. requiredDuringSchedulingIgnoredDuringExecution

也称之为硬性亲和性 (暴力变量命名法),Pod 必须被调度到满足条件的节点上,如果没有满足的条件,就一直重试。

2. preferredDuringSchedulingIgnoredDuringExecution

也称之为软性亲和性,即使没有满足条件的节点,调度器依然会将 Pod 调度到某一个节点上。

在软性亲和性中,可以为每个匹配表达式设置权重,取值范围是 1 - 100。当调度器找到所有匹配 Pod 亲和性标签的节点时,会通过遍历匹配表达式对权重值求和,选择出总分,从而确定调度的优先级。

后缀

不论是软性亲和性还是硬性亲和性,都有两种通用的后缀:

  • IgnoredDuringExecution: 如果节点标签变化后不再满足 Pod 的匹配条件,节点上已经运行的 Pod 不会受到影响
  • requiredDuringSchedulingRequiredDuringExecution: 如果节点标签变化后不再满足 Pod 的匹配条件,节点上已经运行的 Pod 会被驱逐

常用操作符

操作符 作用
In 标签值存在于集合中
NotIn 标签值不存在于集合中
Exists 包含对应标签
DoesNotExist 不包含对应的标签

匹配表达式

  • nodeSelectorTerms: 如果存在多个条件,节点满足任何一个条件就可以
  • matchExpressions: 如果存在多个条件,节点必须满足所有的条件才可以

三种类型

大部分情况下,可以使用标签选择器来约束 Pod 的调度,保证将 Pod 调度到匹配标签的节点上。

但是相比于标签选择器,亲和性拥有更强的表达能力和调度控制能力,亲和度类型有下面三种:

  1. nodeAffinity: Node 亲和性,表示 Pod 倾向于调度到拥有指定标签的节点上
  2. podAffinity: Pod 亲和性,表示 Pod 倾向于和拥有同样标签的 Pod 调度到一起
  3. podAntiAffinity: Pod 反亲和性,表示 Pod 尽量避免和拥有同样标签的 Pod 调度到一起

注意: 如果同时指定了标签选择器和亲和性,则两者的条件必须同时满足,才能将 Pod 调度到节点上。


示例

通过亲和性规则,我们可以实现更强大的调度逻辑语义,下面来看几个小的示例。

1. 必须调度到 XX 节点

...
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-server
spec:
  # ...
  
  affinity:  # 亲和性
    nodeAffinity: # Node 亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬性亲和性
        nodeSelectorTerms:
          - matchExpressions:
              - key: memory-size # 内存标签名称
                operator: In
                values:
                  - large # 内存标签值
  containers:
    ...

通过上面的 yaml 声明,指定 Redis 必须被调度到拥有较大内存的节点上面。

2. 尽量调度到 XX 节点

...
apiVersion: apps/v1
kind: Stateful
metadata:
  name: mysql-server
spec:
  # ...
  
  affinity: # 亲和性
    nodeAffinity: # Node 亲和性
      preferredDuringSchedulingIgnoredDuringExecution: # 软性亲和性
        - weight: 100 # 权重设置为最高
          nodeSelectorTerms:
            - matchExpressions:
                - key: storage # 硬盘标签名称
                  operator: In
                  values:
                    - ssd # 硬盘标签值
  containers:
    ...

通过上面的 yaml 声明,指定 MySQL 尽可能被调度到拥有 SSD 的节点上面。

3. 避免单点故障

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3 # 副本数量
  selector:
    matchLabels:
      app: nginx
  template:
    # ...
    
    spec:
      affinity:
        podAntiAffinity: # Pod 反亲和性
          requiredDuringSchedulingIgnoredDuringExecution: # 硬性亲和性
          - labelSelector:
              matchExpressions:
              - key: app # 标签名称
                operator: In
                values:
                - nginx # 标签值
            topologyKey: "kubernetes.io/hostname" # 拓扑域
      containers:
        ...

通过上面的 yaml 声明,指定拥有 3 个副本的 Nginx 必须被调度到 3 个不同节点上面,避免单个节点宕机时服务中断,提高可用性。

上面的 yaml 声明中,有一行代码:

topologyKey: "kubernetes.io/hostname"

这里简单进行说明: 这行代码用于指定反亲和性的拓扑域 key, 告诉调度器应该根据节点的主机名称来确定节点之间的拓扑域。因为我们使用的是反亲和性规则, 同时使用主机名称作为拓扑域 key, 两者结合,确保了同一个 Pod 不会被调度到具有相同主机名称的节点上。


污点和容忍度

污点的作用目标是 Node (节点), 容忍度的作用目标是 Pod。一个 Node 可以设置多个污点,一个 Pod 也可以设置多个容忍度。

和亲和性的差异

污点 (Taint) 和容忍度 (Toleration) 和亲和性机制类似,可以优化 Pod 在集群节点间的调度,只不过两者的工作方式正好相反。

  • 对于亲和性来说,可以将 Pod 调度到满足亲和性的节点上
  • 对于污点来说,只要给节点设置了污点,默认情况下所有 Pod 都无法调度到该节点,只有能容忍该节点污点的 Pod 才会被调度过来

关键字段

名称 描述
key
value
operator 污点操作符
effect 污点影响

常用操作符

操作符 作用
Equal 容忍度等于具体的值
Exists 容忍度包含具体的值

污点影响

NoSchedule

表示只有可以容忍节点污点的 Pod 才会被调度到这个节点上。

PreferNoSchedule

表示 NoSchedule 的宽松版本,如果 Pod 没有节点的污点容忍度,会尽可能阻止 Pod 被调度到这个节点上,但是如果没有其他节点可以调度,Pod 还是会被调度到这个节点上。

NoExecute

前面两种类型只影响到 调度期间的 Pod, NoExecute 类型同时还会影响当前正在节点 运行期间的 Pod。

如果一个节点添加了 NoExecute 污点,那么就会该节点上正在运行着的 Pod 进行检测, 如果 Pod 没有这个新增的 NoExecute 污点容忍度,将会被驱逐。


示例

$ kubectl taint nodes node-123 compute_type=GPU:NoSchedule

上面的命令为名称为 node-123 的节点添加了污点,其中:

  • 污点的 key 字段为 compute_type, 表示计算类型
  • 污点的 value 字段为 GPU
  • 污点的 effect 字段为 NoSchedule

通过这行命令设置,保证只有可以容忍污点的 Pod 才可以被调度到该节点上面,换句话说,这是一个 GPU 计算型节点。

1. 实现节点专用

利用污点和容忍度,可以实现 “非生产环境的 Redis 不能运行在生产环境的节点上” 这个功能。

$ kubectl taint nodes node-123 environment=production:NoSchedule

在生产环境的节点 node-123 上面添加一个污点 (environment=production),并将污点效果设置为 NoSchedule。

apiVersion: v1
kind: Deployment
metadata:
  name: redis-server
spec:
  tolerations: # 容忍度
    - key: environment # 污点 key 
      operator: Equal  # 污点操作符
      value: production # 污点 value
      effect: NoSchedule # 污点影响
  containers:
    ...

在 Pod 中定义了一个污点容忍度规则,确保只有生产环境中的 Pod 会被调度到该节点上面。


最佳实践

亲和性

1. 优化资源分配

通过亲和性将业务相关联的 Pod 调度到同一个节点或者同一组节点 (例如以机架进行分组),可以提高资源利用率并节省成本,尤其是在使用云服务商提供的按量付费资源时效果更明显。

例如在测试环境中,不需要保证高可用性,这时就可以把无状态服务和缓存服务调度到同一节点,通过更紧凑地编排 Pod 的分布来减少总节点的数量,这样多余的节点就不会产生任何费用了。

除了优化资源分配外,还可以实现协同部署,例如将一个前端 Pod 和一个后端 Pod 部署到靠近的节点上,可以降低延时,提升请求的响应时间。

2. 高可用和容错性

通过亲和性将 Pod 调度到不同的节点,扩大服务发生故障时的节点域,提高服务的可用性和容错性,避免单点故障。

污点和容忍度

1. 保证资源独享

通过污点将重要的节点标记为不可调度,然后为重要的服务 Pod 设置容忍度机制,保证只有重要的服务才会被调度到重要的节点上 (例如专门用于 CPU, GPU 密集计算型的节点), 实现 “将 Pod 调度给指定节点” 功能。

2. 避免服务中断

通过容忍性规则可以保证在节点维护或升级期间,将节点标记为故障节点,并触发已运行 Pod 的驱逐和调度,避免服务中断。

注意事项

Pod 间亲和性 (podAffinity) 和反亲和性 (podAntiAffinity) 都需要相当的计算量,因此在大规模集群中会显著降低调度性能,官方建议不要在数百个及以上节点的集群中使用这两类规则。

标签命名 (附录)

Kubernetes 推荐每个资源对象都应该充分使用标签,这样就可以指定任意维度对资源进行拆分组合,下面是官方的标签类型和名称建议。

描述
name 应用名称
instance 应用实例唯一名称
version 应用当前版本
component 应用位于架构中的组件类型
part-of 更高级别应用名称
managed-by 应用管理工具

下面是一个 wordpress 的无状态应用示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    name: wordpress
    instance: wordpress-abcxzy
    version: "4.9.4"
    managed-by: helm
    component: server
    part-of: wordpress
...

扩展阅读