Pod基于污点、容忍度、亲和性的多种调度策略
labels
# 对已经存在的pod打标签
kubectl label pods tomcat-test release=v1
# 对node打标签
kubectl label nodes node1 disk=ceph
# 删除标签
kubectl label pods tomcat-test release-
kubectl label nodes node1 disk-
# 检查
kubectl get pods tomcat-test --show-leabels
# 过滤出带有该标签的pod,不显示标签
kubectl get pods -l release
kubectl get pods -l release=v1
# 过滤出带有该标签的pod,并打印标签值
kubectl get pods -L release
#查看所有名称空间下的所有pod的标签
kubectl get pods --all-namespaces --show-labels
nodeName和nodeSelector
nodeName:将pod创建到你指定选择的node上
cat > pod-node.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
namespace: default
labels:
app: myapp
env: dev
spec:
# 使用nodeName指定创建的node节点
nodeName: node1
containers:
- name: tomcat-pod-java
ports:
- containerPort: 8080
image: tomcat:8.5-jre8-alpine
imagePullPolicy: IfNotPresent
- name: busybox
image: busybox:latest
# 在pod中跑一个程序,防止pod启动就结束
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
nodeSelector:将pod创建到指定标签的node上
cat > pod-node.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
namespace: default
labels:
app: myapp
env: dev
spec:
# 使用nodeSelector指定带有ceph标签的node节点
nodeSelector:
disk: ceph
containers:
- name: tomcat-pod-java
ports:
- containerPort: 8080
image: tomcat:8.5-jre8-alpine
imagePullPolicy: IfNotPresent
- name: busybox
image: busybox:latest
EOF
# 如果node标签不存在,pod会创建失败,进入pending状态
# 在同一个yaml文件中,同时声明nodeName和nodeSelector,必须两个条件都满足才能调度成功
node亲和性(nodeAffinity)
针对的是pod在选择不同类型标签的node时,选择匹配成功标签的node。key的匹配参数是node的标签(matchExpressions)或字段(matchFields)
kubectl explain pods.spec.affinity.nodeAffinity
nodeAffinity
preferredDuringSchedulingIgnoredDuringExecution(软亲和性)表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件
requiredDuringSchedulingIgnoredDuringExecution(硬亲和性)表示必须有节点满足这个位置定义的亲和性,这是个硬性条件
operator <string> -required-
Represents a key's relationship to a set of values. Valid operators are In,
NotIn, Exists, DoesNotExist. Gt, and Lt.
Possible enum values:
- `"DoesNotExist"`
- `"Exists"`
- `"Gt"`
- `"In"` # 等于
- `"Lt"`
- `"NotIn"`
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity-demo
namespace: default
labels:
app: myapp
tier: frontend
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
# 有任意一个节点拥有zone标签的值是foo或者bar,就可以把pod调度到这个node节点的foo或者bar标签上的节点上
- key: zone
# In就类似与等号
operator: In
value:
- foo
- bar
containers:
- name: myapp
image: xxx
imagePullPolicy: IfNotPresent
# 如果没有匹配成功,pod不会调度,会进入pending
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity-demo-2
namespace: default
labels:
app: myapp2
tier: frontend
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
# 权重,如果多个key都满足条件,优先选择权重高的preference
weight: 10
matchExpressions:
# 只要任意一个key value匹配,就调度到该node
- key: zone1
# In就类似与等号
operator: In
value:
- foo1
- bar1
- preference:
weight: 20
- key: zone2
operator: In
value:
- foo2
- bar2
containers:
- name: myapp2
image: xxx
imagePullPolicy: IfNotPresent
# 如果没有匹配成功,pod仍然可以调度
Pod亲和性(podAffinity)
针对的是pod在选择具有相同标签或没有标签的node时,如何去进一步选择node。key的匹配参数是pod的labels信息(labelSelector)
kubectl explain pods.spec.affinity.podAffinity
# 创建一个普通的pod1
apiVersion: v1
kind: Pod
metadata:
name: pod-first
labels:
app2: myapp2
tier: frontend
spec:
containers:
- name: myapp
image: xxx
imagePullPolicy: IfNotPresent
# 创建一个有亲和性的pod2
apiVersion: v1
kind: Pod
metadata:
name: pod-second
labels:
app: backend
tier: db
spec:
affinity:
porAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app2, operator: In, values: ["myapp2"]}
# 指的是通过什么key值匹配到集群存在的node
# 使用 kubectl get nodes --show-labels,找到kubernetes.io/hostname=
topologyKey: kubernetes.io/hostname
containers:
- name: myapp2
image: xxx
imagePullPolicy: IfNotPresent
# 这样pod2就会去找 app2=myapp2的pod1,并调度到在pod1运行的node节点进行pod2的创建
pod反亲和性(podAntiAffinity)
# 这样pod2就会去找 app2=myapp2的pod1,并调度到不在pod1运行的node节点进行pod2的创建
# 修改topologyKey
# 首先给所有工作node打标签
kubectl label nodes node1 zone=foo
kubectl label nodes node2 zone=foo
# 配置反亲和的pod
apiVersion: v1
kind: Pod
metadata:
name: pod-second
labels:
app: backend
tier: db
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app3 ,operator: In, values: ["myapp3"]}
# 表示带有zone标签的反亲和
topologyKey: zone
# 这样该pod会调度失败
污点、容忍度
给节点打一个污点,不容忍的pod就运行不起来,简言之就是可以排斥哪些pod运行。容忍度就是可以允许污点存在的pod运行。
- 污点taints:针对node,定义污点
- 容忍度tolerations:针对pod,定义容忍度
kubectl explain node.spec.taints
kubectl explain node.spec.tolerations
# 查看污点
kubectl describe node node1 | grep -i taints
# 查看容忍度
kubectl describe pods kube-apiserver-master1 -n kube-system |grep -i toleration
# 定义污点 key是node-type,value是production,污点标签是NoSchedule
kubectl taint node node1 node-type=production:NoSchedule
# 删除污点
kubectl taint node node1 node-type-
### effect参数。 表示排斥等级
# NoSchedule:
仅影响pod调度过程,当pod能容忍这个节点污点,就可以调度到当前节点,后来这个节点的污点改了,加了一个新的污点,使得之前调度的pod不能容忍了,那这个pod会怎么处理,对现存的pod对象不产生影响
# NoExecute:
既影响调度过程,又影响现存的pod对象,如果现存的pod不能容忍节点后来加的污点,这个pod就会被驱逐
# PreferNoSchedule:
最好不,也可以,是NoSchedule的柔性版本
# 定义容忍度,在pod的配置文件添加配置
cat > pod-demo.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: myapp-deploy
namespace: default
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
# 定义容忍度
tolerations:
- key: "node-type"
# 匹配策略
operator: "Equal"
value: "production"
# 排斥等级
effect: "NoExecute"
tolerationSeconds: 3600
EOF
# operator参数
# 一次匹配(Exist),类似for循环,只要有相同的就可以容忍
# 完全匹配(Equal),必须全部相同
Pod常见状态和重启策略
### 第一阶段
# Pending (挂起)
1、正在创建Pod但是Pod中的容器还没有全部被创建完成,处于此状态的Pod应该检查Pod依赖的存储是否有权限挂载、镜像是否可以下载、调度是否正常等
2、我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度没有完成。
# Failed (失败)
Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止(非正常退出)。
# Unknown (未知)
未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown,通常是由于与pod所在的node节点通信错误。
# Error (错误)
Pod 启动过程中发生了错误
# Successed
Pod中的所有容器都被成功终止,即pod里所有的containers均已terminated。
### 第二阶段
# Unschedulable:Pod不能被调度, scheduler没有匹配到合适的node节点
# PodScheduled:pod正处于调度中,在scheduler刚开始调度的时候,还没有将pod分配到指定的node,在筛选出合适的节点后就会更新etcd数据,将pod分配到指定的node
# Initialized:所有pod中的初始化容器已经完成了
# ImagePullBackOff:Pod所在的node节点下载镜像失败
# Running:Pod内部的容器已经被创建并且启动。
# 扩展
#Evicted
出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其是一些大文件、docker镜像。
# CrashLoopBackOff
容器曾经启动了,但可能又异常退出了
Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,当某个容器异常退出或者健康检查失败时,kubelet将根据 重启策略来进行相应的操作。
### Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。
# Always:只要容器异常退出,kubelet就会自动重启该容器。(这个是默认的重启策略)
# OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。
# Never:不论容器运行状态如何,kubelet都不会重启该容器。
# 正常停止pod的容器
# 状态会变成Completed
kubectl exec -it demo-pod -- /bin/bash /usr/local/tomcat/bin/shutdown.sh
# 非正常停止pod的容器
kubectl exec -it demo-pod -- /bin/bash kill 1