文章目录
- k8s中的集群调度
-
-
- [Pod 创建流程](#Pod 创建流程)
- 通过指定节点来创建pod所在的node节点
- 通过标签来指定pod创建在哪个节点上
- [pod 的亲和性](#pod 的亲和性)
- Pod的亲和性和反亲和性
- 污点与容忍
-
k8s中的集群调度
Kubernetes 是通过 List-Watch 的机制进行每个组件的协作,保持数据同步的,每个组件之间的设计实现了解耦
在 Kubernetes 集群中,Pod 是最小的部署单元,它包含一个或多个容器。Pod 的创建和调度是由 Kubernetes 的多个组件共同完成的,包括 API Server、Controller Manager、Scheduler 和 kubelet。本文将带您深入了解这一过程。
Pod 创建流程
- 用户请求 :用户通过
kubectl
或其他 API 客户端向 API Server 发送创建 Pod 的请求。 - 存储请求:API Server 将 Pod 的元数据存储到 etcd 中。一旦存储成功,API Server 向客户端确认请求完成。
- 事件通知:etcd 在存储操作完成后,会向 API Server 发送一个创建事件。
- Controller Manager 监听:Controller Manager 通过 List-Watch 机制监听 API Server 的事件。当它接收到 Pod 创建事件时,会检查是否有对应的 Replication Controller (RC) 或其他控制器来确保所需的 Pod 副本数量。
- 调度准备:如果 Pod 副本数量不足,Controller Manager 会创建新的 Pod 副本,并在 API Server 中记录详细信息。
- Scheduler 监听:Scheduler 也通过 List-Watch 机制监听 API Server 的事件。当它接收到新的 Pod 创建事件时,它将决定将该 Pod 调度到哪个 Node 上。
- 调度决策:Scheduler 根据一系列的调度算法和策略(如资源需求、节点亲和性等)来选择最佳的 Node。
- 绑定 Pod:Scheduler 更新 Pod 的信息,包括其被调度到的 Node,并将这些信息写回 API Server,由 API Server 更新到 etcd。
- kubelet 监听:在每个 Node 上运行的 kubelet 通过 List-Watch 机制监听 API Server,等待被调度到该 Node 上的 Pod 事件。
- 容器启动:当 kubelet 发现有一个新的 Pod 被调度到它所在的 Node 时,它会调用 Docker(或其他容器运行时)来启动 Pod 中的容器。
- 状态反馈:kubelet 将 Pod 及其容器的状态反馈给 API Server,API Server 再将这些状态信息存储到 etcd 中。
通过指定节点来创建pod所在的node节点
没有设置指定节点时会通过调度器来进行pod创建的调度
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web1
labels:
app: web1
spec:
replicas: 4
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80
可以看到pod节点会平均创建在node01 和 node02 上
通过指定节点来指定创建在node01节点上
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web1
labels:
app: web1
spec:
replicas: 4
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
nodeName: node01 # 添加nodeName: node01
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80
不通过调度器,直接通过指定节点将所有pod节点都部署在了node01节点上了
通过标签来指定pod创建在哪个节点上
给node节点添标签
bash
kubectl label nodes node02 pji=a
kubectl label nodes node01 pji=b
可以看见node02 的标签为 pji=a ,node01 的标签为pji=b
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web1
labels:
app: web1
spec:
replicas: 4
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
nodeSelector: #添加标签
pji: a #标签值pji: a
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80
以上配置可以将pod节点部署到node02节点上
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web1
labels:
app: web1
spec:
replicas: 4
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
nodeSelector:
pji: b
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80
以上配置可以将pod部署到node01上
pod 的亲和性
在 Kubernetes 中,Pod 亲和性(Pod Affinity)是一种调度策略,用于确保 Pod 调度到特定的节点上。这种策略可以通过标签选择器(Label Selector)来实现,使得具有特定标签的 Pod 倾向于调度到具有相同标签的节点上。
Pod 亲和性可以分为以下几种类型:
- 软亲和性(Soft Affinity) :
podAffinityTerm
:指定 Pod 应该调度的节点集合。preferredDuringSchedulingIgnoredDuringExecution
:定义 Pod 应该优先调度到哪些节点上。
- 硬亲和性(Hard Affinity) :
podAffinityTerm
:指定 Pod 必须调度的节点集合。requiredDuringSchedulingIgnoredDuringExecution
:定义 Pod 必须调度到哪些节点上。
例如,如果您有一个包含两个节点的集群,并且希望将特定的 Pod 调度到具有标签node-role.kubernetes.io/master: ""
的节点上,
硬策略 匹配标签pji=a的node的节点配置如下
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web1
labels:
app: web1
spec:
replicas: 4
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: pji
operator: In
values:
- a
若是配置一个不存在的标签这会如下
出现Pending状态
软策略
设置标签为bcde但是此集群没有标签bcde的主机
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web1
labels:
app: web1
spec:
replicas: 20
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: pji
operator: In
values:
- bcde
则会调度在node01 (b)和 node02©上
Pod的亲和性和反亲和性
在 Kubernetes 中,亲和性(Affinity)和反亲和性(Anti-Affinity)是调度策略的一部分,用于影响 Kubernetes 调度器如何将 Pod 调度到集群中的节点上。这些特性可以帮助您确保 Pod 之间或 Pod 与节点之间保持特定的关系。
亲和性(Affinity)
亲和性是指调度器倾向于将 Pod 调度到满足特定条件的节点上。它包括以下几种类型:
- 节点亲和性(Node Affinity) :
- 软亲和性(Soft Affinity):如果节点不满足条件,调度器可以忽略亲和性。
- 硬亲和性(Hard Affinity):如果节点不满足条件,调度器将不会调度 Pod。
- Pod 亲和性(Pod Affinity) :
- 软亲和性:如果其他 Pod 不满足条件,调度器可以忽略亲和性。
- 硬亲和性:如果其他 Pod 不满足条件,调度器将不会调度 Pod。
- Pod 反亲和性(Pod Anti-Affinity) :
- 软反亲和性:如果其他 Pod 不满足条件,调度器可以忽略反亲和性。
- 硬反亲和性:如果其他 Pod 不满足条件,调度器将不会调度 Pod。
反亲和性(Anti-Affinity)
反亲和性是亲和性的对立面。与亲和性不同,反亲和性用于防止 Pod 调度到某些节点上,或者避免与某些 Pod 一起调度。反亲和性通常用于避免资源争用或实现高可用性。
亲和性配置
yaml
apiVersion: v1
kind: Pod
metadata:
name: web5
labels:
app: web2
spec:
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web2 # 在有pod标签app=web2的标签上创建
topologyKey: pji #在拥有pji标签的节点上创建
反亲和性
yaml
apiVersion: v1
kind: Pod
metadata:
name: web5
labels:
app: web1
spec:
containers:
- name: nginx
image: nginx:1.14
ports:
- containerPort: 80
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- web2
topologyKey: "kubernetes.io/hostname"
之前的pod标签为web2 ,设置非亲缘性后 web5创建会避开node02
当然可以。
污点与容忍
污点(Taint)
污点是向节点添加的一个标签,它告诉 Kubernetes 调度器不要将 Pod 调度到具有该污点的节点上。这通常用于防止 Pod 调度到不希望它们运行的节点上,例如,当节点正在进行维护或出现问题时。
污点可以具有以下三个属性:
- 键(Key):污点的键,用于标识污点。
- 值(Value):与键关联的值。
- 效果(Effect) :当污点匹配时,Pod 应该受到的影响。有效果包括
NoSchedule
、PreferNoSchedule
和NoExecute
。
污点的创建
给node01创建一个键值对为ry=87的污点,使用NoSchedule策略
bash
kubectl taint node node01 ry=87:NoSchedule
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx4
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
创建新的Pod都创建在node02下,而不会创建在node01上
容忍(Tolerations)
容忍是 Pod 上的一个标签,它告诉 Kubernetes 调度器,尽管节点具有某个污点,但该 Pod 应该被调度到该节点上。容忍可以有多个键值对,并且可以设置不同的效果和时间范围。
设置容忍
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx4
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
tolerations:
- key: "ry"
operator: "Equal"
value: "87"
effect: "NoSchedule"
可以看见,node01的污点被无视了