Kubernetes调度之Pod亲和性

这里介绍Kubernetes调度中的Pod亲和性

Kubernetes调度之Pod亲和性

abstract.png

Pod亲和性

节点亲和性,是基于节点的标签对Pod进行调度。而Pod亲和性则可以实现基于已经在节点上运行Pod的标签来约束新Pod可以调度到的节点。具体地,如果X上已经运行了一个或多个满足规则Y的Pod,则这个新Pod也应该运行在X上。其中,X可以是节点、机架、可用性区域、地理区域等。可通过topologyKey字段定义拓扑域X,其取值是节点标签的键名Key;而Y则是Kubernetes尝试满足的规则。可以通过标签选择器的形式来定义。此外,Pod亲和性使用podAffinity字段,其下支持两种亲和性:

  • 「requiredDuringSchedulingIgnoredDuringExecution」:requiredDuringScheduling表明其是一个强制性的调度,调度器只有在规则被满足的时候才能执行调度;而IgnoredDuringExecution则表明其不会影响已在节点上运行的Pod
  • 「preferredDuringSchedulingIgnoredDuringExecution」:preferredDuringScheduling表明其是一个偏好性的调度,调度器会根据偏好优先选择满足对应规则的节点来调度Pod。但如果找不到满足规则的节点,调度器则会选择其他节点来调度Pod。而IgnoredDuringExecution则表明其不会影响已在节点上运行的Pod

强制性调度

这里提供了一个存在5个工作节点的K8s集群,然后我们使用Deployment部署了应用的前端服务

# 应用的前端服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-frontend
spec:  
  # Pod副本数量
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的前端服务
      labels:
        app: frontend
    spec:
      # 容器信息
      containers:
      - name: my-app-frontend
        image: jocatalin/kubernetes-bootcamp:v1

效果如下所示,可以看到前端服务运行了2个Pod。分别在my-k8s-cluster-multi-node-worker2、my-k8s-cluster-multi-node-worker3节点上

Kubernetes调度之Pod亲和性

figure 1.jpeg

现在我们来部署应用的后端服务,这里我们期望后端服务的Pod能够运行在前端服务的Pod所在的节点上。这时就可以通过节点亲和性实现。具体地:

  • 首先,使用podAffinity来定义Pod亲和性规则,使用requiredDuringSchedulingIgnoredDuringExecution定义强制性的调度规则
  • 然后,使用标签选择器来确定Pod的范围,这里我们显然选择的是前端服务的Pod
  • 最后,使用topologyKey来定义拓扑域信息,这里我们使用的是节点主机名。对于 此时即将被调度的新Pod 与 标签选择器所确定的Pod 来说,它们各自运行节点的主机名是相同的。即,后端服务的Pod 必须被调度到 与前端服务的Pod所在节点拥有相同主机名 的节点上

这样即可实现后端服务的Pod所在的节点上,一定存在前端服务的Pod

# 应用的后端服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-backend
spec:  
  # Pod副本数量
  replicas: 4
  selector:
    matchLabels:
      app: backend
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的后端服务
      labels:
        app: backend
    spec:
    # 亲和性
      affinity:
        # Pod亲和性规则
        podAffinity:
          # 强制性的调度规则, 但不会影响已在节点上运行的Pod
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname
            # 标签选择器
            labelSelector:
              matchLabels:
                app: frontend
      # 容器信息
      containers:
      - name: my-app-backend
        image: tutum/dnsutils
        command:
        - sleep
        - infinity

效果如下所示。后端服务的5个Pod均运行在my-k8s-cluster-multi-node-worker2、my-k8s-cluster-multi-node-worker3节点上

Kubernetes调度之Pod亲和性

figure 2.jpeg

偏好性调度

这里提供了一个存在5个工作节点的K8s集群,然后我们使用Deployment部署了应用的前端服务

# 应用的后端服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-backend
spec:  
  # Pod副本数量
  replicas: 2
  selector:
    matchLabels:
      app: backend
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的后端服务
      labels:
        app: backend
    spec:
      # 容器信息
      containers:
      - name: my-app-backend
        image: tutum/dnsutils
        command:
        - sleep
        - infinity

效果如下所示,可以看到后端服务运行了2个Pod。分别在my-k8s-cluster-multi-node-worker、my-k8s-cluster-multi-node-worker3节点上。而通过标签信息可知,这两个节点都位于上海

Kubernetes调度之Pod亲和性

figure 3.jpeg

现在我们来部署应用的缓存服务,这里我们期望 缓存服务Pod所在的节点 能够尽可能与 前端服务Pod所在的节点 在通过一个地理区域,以减少网络通讯的延迟。

  • 首先,使用podAffinity来定义Pod亲和性规则,使用preferredDuringSchedulingIgnoredDuringExecution定义偏好性的调度规则。可通过权重值来定义对节点偏好,权重值越大优先级越高。其中,权重范围: 1~100
  • 然后,使用标签选择器来确定Pod的范围,这里我们显然选择的是前端服务的Pod
  • 最后,使用topologyKey来定义拓扑域信息,这里我们使用的是节点的Region标签地理位置。此时即将被调度的新Pod 将会更倾向于调度到 与标签选择器所确定的Pod的所在节点 具有相同Region标签值的节点当中。即,缓存服务的Pod的所在节点 与 后端服务的Pod的所在节点 将会尽可能得位于同一个地理区域(具有相同Region标签值)
# 应用的缓存服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-redis
spec:  
  # Pod副本数量
  replicas: 4
  selector:
    matchLabels:
      app: redis
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的后端服务
      labels:
        app: redis
    spec:
    # 亲和性
      affinity:
        # Pod亲和性规则
        podAffinity:
          # 偏好性的调度规则, 但不会影响已在节点上运行的Pod
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 70  # 权重范围: 1~100, 权重值越大, 优先级越高
            podAffinityTerm:
              topologyKey: Region
              # 标签选择器
              labelSelector:
                matchLabels:
                  app: backend                  
      # 容器信息
      containers:
      - name: my-app-redis
        image: redis:3.2-alpine

效果如下所示。缓存服务的4个Pod均运行同样位于上海的节点上。需要注意的是,由于这里是偏好性调度。故如果当上海的节点由于某种原因导致无法调度Pod到其上运行,调度器选择其他地域的节点进行调度也是合法的、允许的。比如这里位于广州的节点

Kubernetes调度之Pod亲和性

figure 4.jpeg

Pod反亲和性

而Pod反亲和性,同样也是基于已经在节点上运行Pod的标签来约束新Pod可以调度到的节点。只不过其与Pod亲和性恰恰相反。即,如果X上已经运行了一个或多个满足规则Y的Pod,则这个新Pod不应该运行在X上。此外,Pod反亲和性使用podAntiAffinity字段,其下同样支持两种反亲和性:requiredDuringSchedulingIgnoredDuringExecution 强制性调度、preferredDuringSchedulingIgnoredDuringExecution 偏好性调度

强制性调度

这里提供了一个存在5个工作节点的K8s集群,然后我们使用Deployment部署了应用的后端服务。这里为了便于后续演示,我们规定后端服务的Pod只允许运行在上海的节点上

# 应用的后端服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-backend
spec:  
  # Pod副本数量
  replicas: 5
  selector:
    matchLabels:
      app: backend
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的后端服务
      labels:
        app: backend
    spec:
    # 配置节点选择器, 要求K8s只将该Pod部署到包含标签Region=ShangHai的节点上
      nodeSelector:
        Region: ShangHai
      # 容器信息
      containers:
      - name: my-app-backend
        image: tutum/dnsutils
        command:
        - sleep
        - infinity

效果如下所示,可以看到后端服务运行了5个Pod。分别运行在位于上海的my-k8s-cluster-multi-node-worker、my-k8s-cluster-multi-node-worker3、my-k8s-cluster-multi-node-worker5节点上

Kubernetes调度之Pod亲和性

figure 5.jpeg

现在我们来部署应用的前端服务,同时基于某种特殊原因的考量,我们期望该应用的前、后端服务的Pod分别运行在不同区域。即前端服务的Pod的运行在位于上海的节点,则我们希望后端服务的Pod运行在除上海之外的节点当中。这时就可以通过节点反亲和性实现。具体地:

  • 首先,使用podAntiAffinity来定义Pod反亲和性规则,使用requiredDuringSchedulingIgnoredDuringExecution定义强制性的调度规则
  • 然后,使用标签选择器来确定Pod的范围,这里我们显然选择的是后端服务的Pod
  • 最后,使用topologyKey来定义拓扑域信息,这里我们使用的是节点的Region标签地理位置。对于 此时即将被调度的新Pod 与 标签选择器所确定的Pod 来说,它们各自运行节点的地理位置是不同的。即,后端服务的Pod 必须被调度到 与前端服务的Pod所在节点拥有不同地理位置 的节点上
# 应用的前端服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-frontend
spec:  
  # Pod副本数量
  replicas: 5
  selector:
    matchLabels:
      app: frontend
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的前端服务
      labels:
        app: frontend
    spec:
    # 亲和性
      affinity:
        # Pod反亲和性规则
        podAntiAffinity:
          # 强制性的调度规则, 但不会影响已在节点上运行的Pod
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: Region
            # 标签选择器
            labelSelector:
              matchLabels:
                app: backend
      # 容器信息
      containers:
      - name: my-app-frontend
        image: jocatalin/kubernetes-bootcamp:v1

效果如下所示。前端服务的5个Pod均运行在位于广州的my-k8s-cluster-multi-node-worker2、my-k8s-cluster-multi-node-worker4节点上

Kubernetes调度之Pod亲和性

figure 6.jpeg

偏好性调度

这里提供了一个存在5个工作节点的K8s集群,然后我们使用Deployment部署了应用的后端服务

# 应用的后端服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-backend
spec:  
  # Pod副本数量
  replicas: 2
  selector:
    matchLabels:
      app: backend
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的后端服务
      labels:
        app: backend
    spec:
      # 容器信息
      containers:
      - name: my-app-backend
        image: tutum/dnsutils
        command:
        - sleep
        - infinity

效果如下所示,可以看到前端服务运行了2个Pod。分别在my-k8s-cluster-multi-node-worker、my-k8s-cluster-multi-node-worker4节点上

Kubernetes调度之Pod亲和性

figure 7.jpeg

现在我们来部署应用的缓存服务,这里由于后端服务、缓存服务都非常占用资源。故我们提出下述调度要求

  1. 缓存服务Pod所在的节点 能够尽可能与 前端服务Pod所在的节点 不是同一个节点
  2. 缓存服务Pod所在的节点 能够尽可能与 前端服务Pod所在的节点 不在同一个地理区域
  3. 上诉2点均为偏好性要求,且第1点优先级是最高的
  • 首先,使用podAntiAffinity来定义Pod反亲和性规则,使用preferredDuringSchedulingIgnoredDuringExecution定义偏好性的调度规则。可通过权重值来定义偏好,权重值越大优先级越高。其中,权重范围: 1~100
  • 然后,使用标签选择器来确定Pod的范围,这里我们显然选择的是前端服务的Pod
  • 最后,使用topologyKey来定义拓扑域信息。这里我们分别使用了节点主机名、地理位置。以此实现即将被调度的新Pod 将会更倾向于调度到 与标签选择器所确定的Pod的所在节点 具有不同节点 或 不同地理区域的节点上
# 应用的缓存服务

apiVersion: apps/v1
kind: Deployment
metadata:  
  name: my-app-redis
spec:  
  # Pod副本数量
  replicas: 4
  selector:
    matchLabels:
      app: redis
  # Pod模板
  template:
    metadata:
      # 标签信息: 应用的后端服务
      labels:
        app: redis
    spec:
    # 亲和性
      affinity:
        # Pod反亲和性规则
        podAntiAffinity:
          # 偏好性的调度规则, 但不会影响已在节点上运行的Pod
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100  # 权重范围: 1~100, 权重值越大, 优先级越高
            podAffinityTerm:
              topologyKey: kubernetes.io/hostname
              # 标签选择器
              labelSelector:
                matchLabels:
                  app: backend
          - weight: 1  # 权重范围: 1~100, 权重值越大, 优先级越高
            podAffinityTerm:
              topologyKey: Region
              # 标签选择器
              labelSelector:
                matchLabels:
                  app: backend                  
      # 容器信息
      containers:
      - name: my-app-redis
        image: redis:3.2-alpine

效果如下所示。缓存服务的4个Pod均运行在与后端服务Pod所在节点不同的节点上。但这里由于是偏好性调度,当最终结果未满足两个服务运行在不同的地理位置时,即调度器选择相同地理位置的节点进行调度也是合法的、允许的

Kubernetes调度之Pod亲和性

figure 8.jpeg

参考文献

  1. Kubernetes in Action中文版 Marko Luksa著
  2. 深入剖析Kubernetes 张磊著

原文始发于微信公众号(青灯抽丝):Kubernetes调度之Pod亲和性

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156508.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!