目录
一、Pod调度流程
Kubernetes 基于 list-watch 机制的控制器架构,实现组件间交互的解耦。
其他组件监控自己负责的资源,当这些资源发生变化时,kube- apiserver 会通知这些组件,这个过程类似于发布与订阅。
调度大致流程
- 用户使用 create yaml 创建 pod,请求给 apiServer,apiserver 将 yaml 中的属性信息(metadata) 写入 etcd
- apiServer 触发 watch 机制准备创建 pod,信息转发给调度器,调度器使用调度算法选择node,调度器将node信息给 apiServer,apiServer 将绑定的 node 信息写入etcd
- apiServer 又通过 watch 机制,调用 kubelet,指定 pod 信息,触发 docker run 命令创建容器
- 创建完成之后反馈给kubelet, kubelet又将pod的状态信息给apiserver,
- apiserver又将pod的状态信息写入etcd。
- 其中kubectl get pods命令调用的时etcd_的信息
二、 容器资源限制
2.1 内存和CPU限制
容器使用的最大资源限制:
• resources.limits.cpu
• resources.limits.memory
容器使用的最小资源需求,作为容器调度时资源分配的依据:
• resources.requests.cpu
• resources.requests.memory
官方示例:为容器和 Pod 分配内存资源 | Kubernetes
示例
apiVersion: v1
kind: Pod
metadata:
name: pod-resource
spec:
containers:
- name: web
image: nginx
resources:
requests: # 容器最小资源配额
memory: "64Mi"
cpu: "250m"
limits: # 容器最大资源上限
memory: "128Mi"
cpu: "500m"
使用 describe 查看 pod 的描述信息
三、 NodeSelector
nodeSelector:用于将Pod调度到匹配Label的Node上,如果没有匹配的标签会调度失败。作用:
• 约束Pod到特定的节点运行
• 完全匹配节点标签应用场景:
• 专用节点:根据业务线将Node分组管理
• 配备特殊硬件:部分Node配有SSD硬盘、GPU
示例操作
### 给node2 打上SSD 的标签
kubectl label node k8s-node2 disktype=ssd
## 查看node 的标签信息
kubectl get node k8s-node2 --show-labels
创建一个pod ,将pod调度到 带有 SSD标签的k8s-node2节点上
apiVersion: v1
kind: Pod
metadata:
name: pod-node-selector
spec:
nodeSelector:
disktype: 'ssd'
containers:
- name: web
image: nginx
查看是否调度到 k8s-node2 节点上
四、NodeAffinity
4.1 基本概念
用节点亲和性把 Pods 分配到工作节点。
nodeAffinity:节点亲和性,与nodeSelector作用一样,但相比更灵活,满足更多条件,诸如:
• 匹配有更多的逻辑组合,不只是字符串的完全相等
• 调度分为软策略和硬策略,而不是硬性要求
• 硬(required):必须满足
• 软(preferred):尝试满足,但不保证
操作符:In、NotIn、Exists、DoesNotExist、Gt、Lt
官方示例:
用节点亲和性把 Pods 分配到节点 | Kubernetes
4.2 Pod 示例
4.2.1使用首选的节点亲和性调度 Pod
下面示例软策略匹配 节点标签 gpu=nvidia
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: gpu
operator: In
values:
- nvidia
containers:
- name: web
image: nginx
软性策略调度到 k8s-master1 节点上,master1 并没有该 gpu=nvidia 标签 ,软性策略调度成功。
4.2.2依据强制的节点亲和性调度 Pod
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity2
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu
operator: In
values:
- nvidia
containers:
- name: web
image: nginx
如上改为硬性策略后 ,pod 必须调度到 有标签gpu=nvidia 的节点上,而k8s测试集群中没有这样的节点
如下 我们可以看到 pod-node-affinity2 处于Pending 状态
使用describe 查看pod 状态,没有匹配到 node
Warning FailedScheduling 36s default-scheduler 0/4 nodes are available: 4 node(s) didn't match Pod's node affinity/selector. preemption: 0/4 nodes are available: 4 Preemption is not helpful for scheduling.
五、Taints与Tolerations
5.1 基本概念
节点亲和性 是 Pod 的一种属性,它使 Pod 被吸引到一类特定的节点 (这可能出于一种偏好,也可能是硬性要求)。 污点(Taint)则相反——它使节点能够排斥一类特定的 Pod。
容忍度(Toleration)是应用于 Pod 上的,允许(但并不要求)Pod 调度到带有与之匹配的污点的节点上。
污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod,是不会被该节点接受的。
Taints:避免Pod调度到特定Node上
Tolerations:允许Pod调度到持有Taints的Node上应用场景:
• 专用节点:根据业务线将Node分组管理,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
• 配备特殊硬件:部分Node配有SSD硬盘、GPU,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
• 基于Taint的驱逐
5.2Taints与Tolerations
查看节点标签
pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod3
spec:
containers:
- name: web
image: nginx
给 k8s-master1 和 k8s-master2 打上 污点, 键名是 gpu ,键值是 nvidia ,效果是 NoSchedule。表示只有拥有和这个污点相匹配的容忍度的 pod 才能被分配到 两个 master节点上。
kubectl taint node k8s-master1 gpu=nvidia:NoSchedule
kubectl taint node k8s-master2 gpu=nvidia:NoSchedule
给两个 node 节点也打上污点
## k8s-node1 打上 GPU 污点
kubectl taint node k8s-node1 gpu=nvidia:NoSchedule
## k8s-node2 打上 ssd 污点
kubectl taint node k8s-node2 ssd=ssd:NoSchedule
## 起一个 Pod
apiVersion: v1
kind: Pod
metadata:
name: pod4
spec:
containers:
- name: web
image: nginx
可以看到 pod4 处于 Pending 状态,没有配置污点容忍 pod无法调度成功
Warning FailedScheduling 24s default-scheduler 0/4 nodes are available: 1 node(s) had untolerated taint {ssd: ssd}, 3 node(s) had untolerated taint {gpu: nvidia}. preemption: 0/4 nodes are available: 4 Preemption is not helpful for scheduling.
我们给 k8s-node2 加上 ssd 污点容忍,让 pod5 在 k8s-node2 上调度
apiVersion: v1
kind: Pod
metadata:
name: pod5
spec:
tolerations:
- key: "ssd"
operator: "Equal"
value: "ssd"
effect: "NoSchedule"
containers:
- name: web
image: nginx
由于其他 node 有污点,node2 有 ssd 污点容忍,在 pod5 在node2上成功运行。
污点移除
kubectl taint node k8s-master2 gpu=nvidia:NoSchedule-
kubectl taint node k8s-master1 gpu=nvidia:NoSchedule-
kubectl taint node k8s-node1 gpu=nvidia:NoSchedule-
kubectl taint node k8s-node2 ssd=ssd:NoSchedule-
六、NodeName
6.1 基本概念
nodeName 是比亲和性或者 nodeSelector 更为直接的形式。nodeName 是 Pod 规约中的一个字段。如果 nodeName 字段不为空,调度器会忽略该 Pod, 而指定节点上的 kubelet 会尝试将 Pod 放到该节点上。 使用 nodeName 规则的优先级会高于使用 nodeSelector 或亲和性与非亲和性的规则。
使用 nodeName 来选择节点的方式有一些局限性:
- 如果所指代的节点不存在,则 Pod 无法运行,而且在某些情况下可能会被自动删除。
- 如果所指代的节点无法提供用来运行 Pod 所需的资源,Pod 会失败, 而其失败原因中会给出是否因为内存或 CPU 不足而造成无法运行。
- 在云环境中的节点名称并不总是可预测的,也不总是稳定的。
6.2 NodeName 字段的 Pod 规约示例
apiVersion: v1
kind: Pod
metadata:
name: pod6
spec:
containers:
- name: nginx
image: nginx
nodeName: k8s-node2
k8s-master1 和 k8s-master2 ,还有 k8s-node1 和k8s-node2 都打上了污点,nodeName的优先级更高,所以pod 成功调度。