Pod健康检查和服务可用性检查
LivenessProbe探针:
用于判断容器是否存活(Running状态),如果该探针探测到容器不正常,那么kubelet会将其kill,并根据容器的重启策略进行处理
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
args: # 容器启动时执行该命令
# 容器启动后前30秒,文件是存在的,所以执行cat /tmp/health会返回成功代码;30秒后会删除该文件,再执行cat /tmp/health会返回失败代码
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy # kubelet在容器内执行cat /tmp/health命令去探测,返回值为0,则认为容器健康
initialDelaySeconds: 5 # kubelet在执行第一次探测前要等待5秒
periodSeconds: 5 # kubelet应该每5秒执行一次存活探测
探测时间的设置
- initialDelaySeconds:容器启动后多少秒再去进行探测,默认时0s,最小值时0s
- periodSeconds:容器启动后进行探测的间隔为多少秒,默认时10s,最小为1s
- timeoutSeconds:容器启动后进行探测超时等待的时间为多少秒,默认为1s,最小为1s
- successThreshold:容器探测失败后,再连续探测几次成功才算成功,存活和启动探测的这个值必须是 1,默认值是1
- failureThreshold:容器探测成功后,再连续探测几次失败才算失败,默认值是3,最小值是1
探针的三种方式
- ExecAction:在容器内部运行一个命令,该命令返回码为0,表明容器健康
- TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果能建立TCP连接,则表明容器健康
- HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP get方法,如果状态码大于等于200且小于400,则认为容器健康
ReadyinessProbe探针:
用于判断容器是否就绪(Ready状态),Ready状态的Pod才能接收请求。如果在运行过程中,Pod的Ready状态变为False,那么它将会从Service后端Endpoint列表中去除(该Pod被Service管理)
StartupProbe探针:
如果容器启动较慢,可以使用该探针来延长对容器存活性的探测,可以通过将 failureThreshold * periodSeconds 参数设置为足够长的时间来应对糟糕情况下的启动时间
亲和性和反亲和性
NodeSelector定向调度
-
当一个Pod被Scheduler服务调度的时候,它会执行一些列复杂的算法,最终将Pod调度到一个最佳的节点上
-
如果想将Pod调度到指定的节点上,可以通过Node标签和nodeSelector属性相匹配,达到上述目的
- 首先用kubectl label为一个节点打标签,然后在Pod的定义中加入nodeSelector
kubectl label node k8s-node app=nginx
pod的yaml文件
apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent nodeSelector: app=nginx
- 在运行kubectl create -f pod-yaml创建Pod,scheduler就会将Pod调度到拥有app=nginx标签的Node上
- 如果我们指定了Pod的nodeSelector,但是,集群中的node中没有包含对应的标签,则Pod将无法被调度
亲和性调度功能
节点亲和性(nodeAffinaity)
两种亲和性表达:
- requiredDuringSchedulingIgnoredDuringExecution:硬限制,必须满足指定的规则才可以调度Pod到Node上
- preferredDuringSchedulingIgnoredDuringExecution:软限制,强调优先满足指定规则,调度器会尝试将Pod调度到Node上,但并不强求
- IgnoredDuringExecution:Pod所在节点在Pod运行期间标签发生了改变,并不会影响该Pod继续在此节点上运行
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: k8s.gcr.io/xx:2.0
硬性要求:只能运行在有标签kubernetes.io/os:linux的节点上
软性要求:尽量运行在有标签another-node-label-key:another-node-label-value的节点上
NodeAffinity语法支持的操作符: In,NotIn(互斥)、Exists、DoesNotExist(互斥)、Gt、Lt
NodeAffinity设置的规则:
- 如果同时设定了nodeSelector和NodeAffinity,则必须两者同时满足,Pod才能被调度到指定Node上
- 如果NodeAffinity中指定了多个nodeSelectorTerms,则只要一个匹配成功就能将Pod调度到指定的Node上
- 如果在一个nodeSelectorTerms指定了多个matchExpressions,则该节点需要满足所有的matchExpressions才能运行次Pod
Pod亲和性(PodAffinity)和反亲和性(PodAntiAffinity)
Pod亲和性:在生产环境中有些Pod相互依赖、频繁调用,他们就应该尽可能的部署在一个Node、机架、机房、网段或者区域中
在将一个Node加入Master中时,Node可能就会被加上默认的标签:
kubernetes.io/hostname;topology.kubernetes.io/region;topology.kubernetes.io/zone
Pod亲和和互斥的调度具体做法,就是通过Pod的定义上增加的topologyKey属性,来声明一些相关联的Pod是否要放在一个区域或节点上
Pod的亲和和互斥与节点亲和条件设置相同:requiredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
举例说明Pod的亲和和反亲和性
apiVersion: v1
kind: Pod
metadata:
name: pod-flag
labels:
security: "S1"
app: "nginx"
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: topology.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
Pod将会被调度到有topology.kubernetes.io/zone标签,且Pod标签为security=S1,但是不与security=S2的Pod为同一个Node
Pod的亲和性操作符包括: In,NotIn(互斥)、Exists、DoesNotExist(互斥)、Gt、Lt
在原则上topologyKey可以使用任意合法的标签,但是出于安全考虑,topologyKey有如下限制:
- Pod亲和性和带有硬性、软性限制,topologyKey不能为空
- Pod反亲和性和带有硬性限制,topologyKey只能是 kubernetes.io/hostname
- Pod亲和性除了设置Label Selector和topologyKey外,还可以指定Namespace列表进行限制
- Pod被调度到某个Node上必须满足硬性限制和matchExpressions
污点(Taints)和容忍(Tolerations)
**Taint:**让Node拒绝Pod运行,标记了Taint的节点就是不希望Pod被调度过来,但此节点仍然是有效的节点;如果希望某些特定的Pod调度过来,则需要设置Tolerations
在节点上设置Taint:
kubectl taint node k8s-node key=value:NoSchedule
在该节点上设置了key=value的污点,而且Pod中如果没有设置容忍该污点,则无法将Pod调度到该节点上
在Pod上声明容忍该污点:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
---
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
在设置容忍的时候,key和effect要和污点的设置保持一致,并且满足以下条件之一:
- operator值是Exists,则无需指定value
- operator值是Equal并且value相等
- 如果不指定operator则默认是Equal
特例:
空的key匹配Exists操作能够匹配所有键和值
空的effect匹配所有的effect
effect类型:
NoSchedule:没有设置容忍该污点的Pod无法被调度到该节点
PreferNoSchedule:没有设置容忍该污点的Pod尽量避免调度到该节点
NoExecute:没有设置容忍该污点的Pod无法被调度到该节点,而且如果Pod已经在该节点上运行则会被驱逐
系统允许一个节点上有多个Taint和Tolerations,K8S处理的逻辑顺序为:
- 列出节点中所有的Taint,忽略能够匹配Taint的Toleration;剩下没被忽略的Taint就起以下作用:
- 剩余的Taint中存在effect=NoSchedule,调度器不会把该Pod调度到这一节点上
- 剩余的Taint中没有NoSchedule,但是有PreferNoSchedule,调度器尝试不把这个Pod调度到该节点上
- 剩余的Taint中有NoExecute,Pod无法被调度到该节点,如果Pod已经在该节点上运行,则会被驱逐
从K8S 1.6开始引入两个与Taint相关的新特性,新特性是用来改善异常情况下的Pod调度与驱逐问题(当节点有磁盘、内存、节点失联等问题时)
- TaintNodesByCondition:
- 不断地检查所有Node状态,设置对应的Condition
- 根据Node Condition设置对应的Taint(添加的是NoSchedule的污点),主要有以下几种:
- node.kubernetes.io/not-ready:节点未就绪
- node.kubernetes.io/unreachable:节点不可触达(相当于失联的状态)
- node.kubernetes.io/out-of-disk:节点磁盘空间已满
- node.kubernetes.io/network-unavailable:节点网络不可用
- node.kubernetes.io/unschedulable:节点不可调度
- 根据Taint驱逐Node上的Pod
- TaintBasedEvictions:添加的是NoExecute效果的污点