5.Pod资源高级用法
pod 是 k8s 最小调度单元,pod 里可以运行一个或者多个容器
1.1 Pod 高级用法:node 节点选择器和 nodeName
1.1.1、nodeName:
在 Kubernetes 中,NodeName 是每个 Node 节点的唯一标识符,它是一个字符串,通常是节点的主机名(hostname)。在创建 Pod 时,可以通过指定 nodeName 字段来将 Pod 调度到特定的Node 节点上。指定 pod 节点运行在具体 node 上
1.1.2、nodeSelector:
在 Kubernetes 中,nodeSelector 是一种用于在 Pod 级别上选择运行节点的方法。通过使用nodeSelector 字段,你可以指定一组键值对(标签),以便将 Pod 调度到具有匹配标签的节点上运行。
每个节点都可以使用一组标签进行标识,这些标签可以根据硬件规格、操作系统、地理位置或其他特定的属性来定义。当创建 Pod 时,你可以通过在Pod 的配置中指定 nodeSelector 字段,来告诉Kubernetes 调度器选择具有匹配标签的节点来运行该 Pod。
以下是一个示例 Pod 配置,展示了如何使用 nodeSelector 字段来选择节点:
在上述示例中,nodeSelector 字段包含了两个键值对:disk: ssd 和 region:us-west。这意味着Kubernetes 将尝试将这个 Pod 调度到具有标签 disk=ssd 和 region=us-west 的节点上。那我们需要给节点打标签才可以:
1.2 Pod 高级用法:亲和性 affinity
在 k8s 中亲和性有两种:节点亲和性(node affinity)和 Pod 亲和性(pod affinity)。
Pod 亲和性(Pod Affinity):Pod 亲和性用于指定 Pod 之间的关系,使它们倾向于在同一 节点或具有相似特征的节点上运行。这可以在以下场景中发挥作用: • 数据本地性:当两个或多个 Pod 需要访问相同的本地数据时,可以使用 Pod 亲和性 将它们调度到同一节点上。例如,在分布式数据库中,多个数据库实例需要访问相同的 数据卷或存储,可以通过 Pod 亲和性将它们调度到同一节点上,减少网络传输延迟。 • 互为依赖:当两个或多个 Pod 之间存在依赖关系,需要相互通信或协同工作时,可以 使用 Pod 亲和性将它们调度到同一节点上。例如,在微服务架构中,某个服务需要与 特定的缓存服务进行交互,可以使用 Pod 亲和性将它们调度到同一节点上,提高性能 和减少网络开销。 • 服务发现和负载均衡:在需要实现服务发现和负载均衡的场景中,可以使用 Pod 亲和 性将属于同一服务的多个实例调度到同一节点或相近的节点上。这样可以提高服务的可 用性、降低延迟,并简化负载均衡配置。
节点亲和性(Node Affinity):节点亲和性用于指定 Pod 与节点之间的关系,使 Pod 倾向 于在具有特定标签或节点特征的节点上运行。这可以在以下场景中发挥作用: • 资源需求:当某个 Pod 对计算资源(如 CPU、内存)或其他特定硬件资源(如 GPU)有特定需求时,可以使用节点亲和性将它调度到具有相应资源的节点上。这有助 于优化资源利用和性能。 • 逻辑分组:当需要将相关的 Pod 分组部署到特定节点上时,可以使用节点亲和性。例 如,在分布式系统中,某个节点需要承担特定的角色或任务,可以使用节点亲和性将相 关的 Pod 调度到该节点上,以便实现逻辑上的分组和管理。 • 特定硬件或软件要求:当某个 Pod 需要依赖特定的硬件设备或软件环境时,可以使用 节点亲和性将它调度到具备所需条件的节点上。例如,某个 Pod 需要与具有特定硬件 加速器的节点进行通信,可以使用节点亲和性将它调度到具备所需硬件的节点上。
1.2.1 node 节点亲和性
node 节点亲和性:nodeAffinity
例 1:使用 requiredDuringSchedulingIgnoredDuringExecution
我们检查当前节点中有任意一个节点拥有 a=b 标签,就可以把 pod 调度到有 a=b 这个标签的节点 上。
status 的状态是 pending,上面说明没有完成调度,因为没有任何一个拥有 a=b 标签的节点,而 且使用的是硬亲和性,必须满足条件才能完成调度
例 2:使用 preferredDuringSchedulingIgnoredDuringExecution 软亲和性
上面说明软亲和性是可以运行这个 pod 的,尽管没有任何一个节点具有 a1=b1 这个标签
1.2.2 Pod 和 Pod 亲和性
podAffinity:表示 Pod 与其它 Pod 的亲和性。可以使用 requiredDuringSchedulingIgnoredDuringExecution、 preferredDuringSchedulingIgnoredDuringExecution 等字段来指定 Pod 与其它 Pod 的亲和性规则。这些字段中可以使用 topologyKey 和 labelSelector 字段来指定 Pod 之间的关系。
pod 亲和性分两种: podaffinity(pod 亲和性):Pod 亲和性是指一组 Pod 可以被调度到同一节点上,即它们互相吸引, 倾向于被调度在同一台节点上。例如,假设我们有一组具有相同标签的 Pod,通过使用 Pod 亲和性规 则,我们可以让它们在同一节点上运行,以获得更高的性能和更好的可靠性。
podunaffinity(pod 反亲和性):Pod 反亲和性是指一组 Pod 不应该被调度到同一节点上,即它 们互相排斥,避免被调度在同一台节点上。例如,如果我们有一组应用程序 Pod,我们可以使用 Pod 反亲和性规则来避免它们被调度到同一节点上,以减少单点故障的风险和提高可靠性。
例 1:pod 和 pod 亲和性
定义两个 pod,调度到同一个位置
通过上面可以看到,第一个 pod 调度到了 xianchaonode1 上了。
topologyKey: kubernetes.io/hostname :这个是 Kubernetes 中一个用于指定节点位置拓扑的 关键字,kubernetes.io/hostname 是一个节点标签的 key 值,不同的节点这个 key 对应的 value 值 是节点主机名,它表示 Pod 应该与具有相同的主机名的节点进行亲和性或反亲和性调度。也就是两个 pod 调度到同一个 node 节点或者不同的 node 节点上。
上面说明第一个 pod 调度到哪,第二个 pod 也调度到哪,这就是 pod 节点亲和性
例 2:pod 节点反亲和性
定义两个 pod,第一个 pod 做为基准,第二个 pod 跟它调度到不同的节点上
上面结果表示两个 pod 不在一个 node 节点上,这就是 pod 节点反亲和性
1.3 污点和容忍度
我们给节点打一个污点,不容忍的 pod 就运行不上来,污点就是定义在节点上的键值属性数据,
可以定决定拒绝那些 pod,容忍度是定义在 pod 上的,用来指定能容忍哪些污点。
taints 是键值数据,用在节点上,定义污点;
tolerations 是键值数据,用在 pod 上,定义容忍度,能容忍哪些污点
taints 的 effect 用来定义对 pod 对象的排斥等级(效果):
NoSchedule: 仅影响 pod 调度过程,当 pod 能容忍这个节点污点,就可以调度到当前节点,后来这个节点的 污点改了,加了一个新的污点,使得之前调度的 pod 不能容忍了,那这个 pod 会怎么处理,对 现存的 pod 对象不产生影响
NoExecute: 既影响调度过程,又影响现存的 pod 对象,如果现存的 pod 不能容忍节点后来加的污点,这个 pod 就会被驱逐
PreferNoSchedule: 最好不,也可以,是 NoSchedule 的柔性版本
上面可以看到 master 这个节点的污点是 Noschedule
所以我们创建的 pod 都不会调度到 master 上,因为我们创建的 pod 没有容忍度
1.3.1 管理节点污点
例 1:把 xianchaonode1 当成是生产环境专用的。
显示如下: taint-pod pending
pod 是 pending 状态,说明,xianchaomaster1 和 xianchaonode1 都打了污点,pod 没定义 容忍度,所以不会调度到任何一个节点上。
删除污点
kubectl taint nodes xianchaonode1 node-type=production:NoSchedule
1.4 Pod高级用法:对pod内的容器做健康探测
1.4.1 Liveness Probe(存活探测)
Liveness Probe 用于监测 pod 内的容器是否处于运行状态。当 Liveness Probe 探测失败时,Kubernetes根据重启策略决定是否重启该容器。适用于需要在容器发生故障时立即进行重启的应用场景,比如 Web 服务器和数据库等应用。
1.4.2 Readiness Probe(就绪探测)
Readiness Probe 用于监测 pod 内的容器是否已经准备好接受流量,即容器是否已经完成初始化并已经启动了应用程序。当容器的Readiness Probe 探测失败时,Kubernetes 将停止将新的流量转发到该容器。适用于需要应用程序启动较长时间的应用场景,比如大型 Web 应用程序。
1.4.3 Startup Probe(启动探测)
Startup Probe 用于监测 pod 内的容器是否已经启动成功并准备好接受流量。与 Liveness Probe 不同的是,Startup Probe 只会在容器启动时执行一次。当 Startup Probe 探测失败时,Kubernetes 将自动重启该容器。适用于需要较长启动时间的应用场景,比如应用 程序需要大量预热或者需要等待外部依赖组件的应用程序。 
1.4.4 liveness 案例分享
Liveness Probe 用于检查 pod 内的容器是否在运行,并在容器出现故障时重新启动容器。Liveness Probe 支持三种探针:httpGet、exec 和 tcpSocket。
1.4.4.1 使用Http接口进行探测
文件说明
1、initialDelaySeconds:首次探测之前等待的时间,单位是秒。在容器启动之后,等待指定的时间后 才开始进行探测,避免容器还未启动完成就开始进行探测,导致探测失败。
2、periodSeconds:探测器的周期时间,单位是秒。探测器将在每隔一定时间间隔内进行一次探测。默 认周期时间是 10 秒。
svc跟pod关联之后,通过ipvsadm -Ln,可以看到ip了。
1.4.4.2 使用tcp接口进行探测:
可以看到pod里的容器重启了一次。因为默认的重启策略是always,只要探测失败就重启。
1.4.5 readiness probe 案例分享
Readiness probe 用于检查容器是否已经准备好接受流量。Readiness Prode 支持三种探针: httpGet , exec 和 tcpSocket。
文件说明
1、initialDelaySeconds:首次探测之前等待的时间,单位是秒。在容器启动之后,等待指定的时间后才开始进行探测,避免容器还未启动完成就开始进行探测,导致探测失败。
2、periodSeconds:探测器的周期时间,单位是秒。探测器将在每隔一定时间间隔内进行一次探测。默认周期时间是 10 秒。
3、failureThreshold:探测失败的阈值,failureThreshold: 3 是指在连续失败了 3 次探测后,探测就会被认定为失败,容器将被认为是不健康的,并且将被终止并重新启动。
4、successThreshold:探测成功的阈值,假设 successThreshold: 1,则当容器探测成功一次后,容器将被认为是健康的,继续运行。
所以上面最终的探测方式如下:
探测将在容器启动等待1分钟,然后开始执行。探测周期的时间间隔为2秒,也就是每隔2秒进行一次探测。如果在探测期间出现3次失败,则Pod将被标记为NotReady,如果探测成功一次,才会将其标记为Ready。
上面可以看到pod没有立即ready,因为initialDelaySeconds: 1.表示pod启动后1s才开始探测,所以至少要等1s,探测没问题才能就绪。
模拟探测失败的情况: 在Nginx 容器中删除 /usr/share/nginx/html/index.html文件,这样httpGet 探针将无法访问该文件,从而导致探测失败。
1.5 Pod容器健康探测
1.5.1 为什么要对容器做探测
在 Kubernetes 中 Pod 是最小的计算单元,而一个 Pod 又由多个容器组成,相当于每个容器就是一个应用,应用在运行期间,可能因为某些意外情况致使程序挂掉。那么如何监控这些容器状态稳定性,保证服务在运行期间不会发生问题,发生问题后进行重启等机制,就成为了重中之重的事情,考虑到这点 kubernetes 推出了活性探针机制。有了存活性探针能保证程序在运行中如果挂掉能够自动重启,但是还有个经常遇到的问题,比如说,在 Kubernetes 中启动 Pod,显示明明 Pod 已经启动成功,且能访问里面的端口,但是却返回错误信息。还有就是在执行滚动更新时候,总会出现一段时间,Pod 对外提供网络访问,但是访问却发生 404,这两个原因,都是因为 Pod已经成功启动,但是Pod 的的容器中应用程序还在启动中导致,考虑到这点 Kubernetes 推出了就绪性探针机制。
1.5.1.1 默认的健康检查
Kubernetes 默认的健康检查机制: 每个容器启动时都会执行一个进程, 此进程由 Dockerfile 的CMD 或 ENTRYPOINT 指定。 如果进程退出时返回码非零, 则认为容器发生故障, Kubernetes 就会根据restartPolicy 策略决定是否重启容器。
在上面的例子中, 容器进程返回值非零, Kubernetes 则认为容器发生故障, 需要重启。 有不少情况是发生了故障, 但进程并不会退出。 比如访问 Web 服务器时显示 500 内部错误, 可能是系统超载, 也可能是资源死锁, 此时 httpd 进程并没有异常退出,在这种情况下重启容器可能是最直接、最有效的解决方案。
k8s提供了三种来实现容器探测的方法,分别是:
startupProd: 探测容器中的应用是否已经启动。如果提供了启动探测(startUp prode),则禁用其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功 Success。
livenessprobe:用指定的方式(exec、tcp、http)检测 pod 中的容器是否正常运行,如果检测失败,则认为容器不健康,那么 Kubelet 将根据 Pod 中设置的 restartPolicy 策略来判断 Pod是否要进行重启操作,如果容器配置中没有配置 livenessProbe,Kubelet 将认为存活探针探测s一直为 success(成功)状态。
readnessprobe:就绪性探针,用于检测容器中的应用是否可以接受请求,当探测成功后才使Pod 对外提供网络访问,将容器标记为就绪状态,可以加到 pod 前端负载,如果探测失败,则将容 器标记为未就绪状态,会把 pod 从前端负载移除。
可以自定义在pod启动时是否执行这些检测,如果不设置,则检测结果均默认为通过,如果设置,则顺序为startUpProd> readinessProbe和livenessProbe,readinessProbe和livenessProbe是并发关系
官方文档:Caution: Liveness probes do not wait for readiness probes to succeed. If you want to wait before executing a liveness probe you should use initialDelaySeconds or a startupProbe
也就是 Liveness probes 并不会等到 Readiness probes 成功之后才运行,根据上面的官方文档,Liveness 和 readiness 应该是某种并发的关系。
目前 LivenessProbe 和 ReadinessProbe、startupprobe 探测都支持下面三种探针: 1、exec:在容器中执行指定的命令,如果执行成功,退出码为 0 则探测成功。 2、TCPSocket:通过容器的 IP 地址和端口号执行 TCP 检 查,如果能够建立 TCP 连接,则表明 容器健康。 3、HTTPGet:通过容器的 IP 地址、端口号及路径调用 HTTP Get 方法,如果响应的状态码大于等 于 200 且小于 400,则认为容器健康 探针探测结果有以下值: 1、Success:表示通过检测。 2、Failure:表示未通过检测。 3、Unknown:表示检测没有正常进行。
Pod 探针相关的属性:
探针(Probe)有许多可选字段,可以用来更加精确的控制 Liveness 和 Readiness 两种探针的行为
initialDelaySeconds:容器启动后要等待多少秒后探针开始工作,单位“秒”,默认是 0 秒,最小值是 0
periodSeconds: 执行探测的时间间隔(单位是秒),默认为 10s,单位“秒”,最小值是 1
timeoutSeconds: 探针执行检测请求后,等待响应的超时时间,默认为 1,单位“秒”。
successThreshold:连续探测几次成功,才认为探测成功,默认为 1,在 Liveness 探针中必须为 1,最小值为 1。
failureThreshold: 探测失败的重试次数,重试一定次数后将认为失败,在 readiness 探针中,Pod 会被标记为未就绪,默认为 3,最小值为 1
两种探针区别:
ReadinessProbe 和 livenessProbe 可以使用相同探测方式,只是对 Pod 的处置方式不同:
readinessProbe 当检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。
livenessProbe 当检测失败后,将杀死容器并根据 Pod 的重启策略来决定作出对应的措施。
1.5.1.2 启动探测 startupProbe
exec 模式
tcpsocket模式
httpget模式
1.5.3 ReadinessProbe + LivenessProbe + startupProbe配合使用
一般程序中需要设置三种探针结合使用,并且也要结合实际情况,来配置初始化时间和检测间隔,下面列一个简单的springboot项目的例子。