K8S学习笔记之最小控制单元Pod (二)

该博客围绕Kubernetes展开,介绍了污点和容忍度,污点是节点属性,决定拒绝哪些pod,容忍度用于pod;还阐述了Pod的生命周期和状态、重启策略,以及两个钩子函数、存活性和就绪性探测探针、启动探测探针等内容。

污点和容忍度

给了节点选则的主动权,我们给节点打一个污点,不容忍的pod就调度不上来,污点就是定义在节点上的键值属性数据,可以定决定拒绝那些pod;

污点是节点的属性;亲和度是pod的属性。

taints是键值数据,用在node上,定义污点;
tolerations是键值数据,用在pod上,定义容忍度,能容忍哪些污点

# 查看节点属性详细信息
kubectl describe nodes master1
# kubectl explain node.spec.taints
effect	    <string> -required-  定义对pod对象的排斥等级(效果)
key	        <string> -required-
timeAdded	<string>
value	    <string>

# NoSchedule:
仅影响pod调度过程,当pod能容忍这个节点污点,就可以调度到当前节点。后来这个节点的污点改了,加了一个新的污点,对现存的pod对象不产生影响,新的不容忍的pod不会进来。

# NoExecute:
既影响调度过程,又影响现存的pod对象,如果现存的pod不能容忍节点后来加的污点,这个pod就会被驱逐

# PreferNoSchedule:
"最好不,也可以"是NoSchedule的柔性版本
# 在pod对象定义容忍度的时候支持两种操作:
1.等值密钥:key和value上完全匹配
2.存在性判断:key和effect必须同时匹配,value可以是空
在pod上定义的容忍度可能不止一个,在节点上定义的污点可能多个,需要琢个检查容忍度和污点能否匹配,每一个污点都能被容忍,才能完成调度,如果不能容忍怎么办,那就需要看pod的容忍度了。
## 【0】为什么kube-api-server可以调度到master节点上
# 其定义了Tolerations  :NoExecute
kubectl describe pods kube-apiserver-master1 -n kube-system
# master 节点定义了污点
# Traints  node-role.kubernetes.io/master:NoExecute
kubectl describe nodes master1
## 【1】给node2定义污点并且测试pod容忍度
kubectl taint –help
kubectl taint node node2 node-type=pro:NoSchedule
# 创建pod
vim pod-test-taint.yaml
kubectl apply -f pod-test-taint.yaml
kubectl get pods -o wide
# 可以看到都被调度到node1上了,因为node2这个节点打了污点,而我们在创建pod的时候没有容忍度,所以node2上不会有pod调度上去的
apiVersion: v1
kind: Pod
metadata:
  name: taint-pod
  namespace: default
  labels:
    tomcat: tomcat-pod
spec:
  containers:
  - name:  taint-pod
    ports:
    - containerPort: 8080
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent 
## 【2】给node1打上污点,测试驱逐pod的现象
kubectl taint node node1 node-type=dev:NoExecute
kubectl get pods -o wide
# 看到node1上已经存在的pod节点都被驱逐了
## 【3】定义pod容忍度,使其调度到node2上
vim pod-test-toleration.yaml
kubectl apply -f pod-test-toleration.yaml
kubectl get pods -o wide
apiVersion: v1
kind: Pod
metadata:
  name: myapp-deploy
  namespace: default
  labels:
    app: myapp
    release: canary
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
  tolerations:
  - key: "node-type"
    operator: "Equal"
    value: "pro"
    effect: "NoSchedule"
## 【4】修改“等值匹配”为“存在性匹配”
# 只要有一个node-type的键,不管值是什么,不管是什么效果,都能容忍
tolerations:
- key: "node-type"
  operator: "Exists"
  value: ""
  effect: "NoSchedule"
  tolerationSeconds: 3600
## 【5】删除污点,避免影响后续测试
kubectl taint nodes node1 node-type:NoExecute-
kubectl taint nodes node2 node-type-

生命周期和状态

pod状态

## 挂起(Pending)
我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度没有完成,处于pending的状态会持续一段时间:包括调度Pod的时间和通过网络下载镜像的时间。 
## 运行中(Running)
Pod已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
## 成功(Succeeded)
Pod 中的所有容器都被成功终止,并且不会再重启。
## 失败(Failed)
Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
## 未知(Unknown)
未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown
## Evicted状态
出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其是一些大文件、docker镜像。
## CrashLoopBackOff状态
容器曾经启动了,但可能又异常退出了
## Error状态
Pod 启动过程中发生了错误

pod重启策略

Pod的重启策略(RestartPolicy)应用于Pod内的所有容器,并且仅在Pod所处的Node上由kubelet进行判断和重启操作。当某个容器异常退出或者健康检查失败时,kubelet将根据 RestartPolicy 的设置来进行相应的操作。

Always:当容器失败时,由kubelet自动重启该容器。(默认)
OnFailure:当容器终止运行且退出码不为0时,由kubelet自动重启该容器。
Never:不论容器运行状态如何,kubelet都不会重启该容器。

pod生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BsoU47sU-1657098393971)(./pic/pod生命周期.jpg)]

Init容器

1.初始化工作需要的容器,有一个或者多个,按照定义的顺序执行(串行)。
2.只有所有的初始化容器执行完毕后主容器才能执行(先与主容器运行,为主容器启动提供支持)。
3.初始化容器执行完毕后就退出了。
4.与主容器存储卷共享,数据共享。

5.可以利用初始化容器,做一些程序设计:进行一些预检查参数、初始化数据库、初始化缓存或挂载卷等操作
Init容器与普通的容器区别是:
1、Init 容器不支持 Readiness,因为它们必须在Pod就绪之前运行完成
2、每个Init容器必须运行成功,下一个才能够运行
3、如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止,然而,如果Pod对应的restartPolicy值为 Never,它不会重新启动。

主容器

# 初始化容器启动之后,开始启动主容器,包含了用户定义的程序镜像等
# pod在整个生命周期中有非常多的用户行为:
1、初始化容器完成初始化
2、主容器启动后可以做启动后钩子
3、主容器结束前可以做结束前钩子
4、在主容器运行中可以做一些健康检测,如liveness probe,readness probe

创建过程

apiserver作为交互门户,提供有各种API,以及与etcd存储插件交互,统筹协调各个组件,来创建和存储一个资源。
schedule作为调度中心,可以根据pod资源信息,将pod调度到不同工作节点上
kubelet负责将调度到具体节点上的资源清单,进行创建
期间,apiserver会统筹交互,并将各个插件的操作结果和资源信息存储到etcd中

两个钩子函数(pre和post)

postStart:容器创建成功后,运行前的任务,用于资源部署、环境准备等。
preStop:在容器被终止前的任务,用于优雅关闭应用程序、通知其他系统等。
# postStart:容器启动后钩子
该钩子在容器被创建后立刻触发,通知容器它已经被创建。如果该钩子对应的hook handler执行失败,则该容器会被杀死,并根据该容器的重启策略决定是否要重启该容器,这个钩子不需要传递任何参数。

# preStop:容器结束前钩子
该钩子在容器被删除前触发,其所对应的hook handler必须在删除该容器的请求发送给Docker daemon之前完成。在该钩子对应的hook handler完成后不论执行的结果如何,Docker daemon会发送一个SGTERN信号量给Docker daemon来删除该容器,这个钩子不需要传递任何参数。
# 示例:
# 启动后,将web.xml文件copy到/root/目录下;销毁前,请求到http://monitor.com:8080/waring发送警告
# 支持exec、httpGet、tcpSocket三种方式
containers: 
  - name: tomcat-test
    image: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    lifecycle:
      postStart: 
        exec:
          command:
            - "cp"
            - "/usr/local/tomcat/conf/web.xml"
            - "/root/web.xml"
      preStop:
        httpGet:
          host: monitor.com
          path: /waring
          port: 8080
          scheme: HTTP
# 利用生命周期函数优雅删除资源对象
lifecycle:
  preStop:
    exec:
    # nginx -s quit gracefully terminate while SIGTERM triggers a quick exit
      command: ["/usr/local/nginx/sbin/nginx","-s","quit"]

存活性探测和就绪性探测(探针)

## livenessProbe:存活性探测
许多应用程序经过长时间运行,最终过渡到无法运行的状态,除了重启,无法恢复。通常情况下,K8S会发现应用程序已经终止,然后重启应用程序pod。有时应用程序可能因为某些原因(后端服务故障等)导致暂时无法对外提供服务,但应用软件没有终止,导致K8S无法隔离有故障的pod,调用者可能会访问到有故障的pod,导致业务不稳定。K8S提供livenessProbe来检测容器是否正常运行,并且对相应状况进行相应的补救措施。
## readinessProbe:就绪性探测
在没有配置readinessProbe的资源对象中,pod中的容器启动完成后,就认为pod中的应用程序可以对外提供服务,该pod就会加入相对应的service,对外提供服务。但有时一些应用程序启动后,需要较长时间的加载才能对外服务,如果这时对外提供服务,执行结果必然无法达到预期效果,影响用户体验。比如使用tomcat的应用程序来说,并不是简单地说tomcat启动成功就可以对外提供服务的,还需要等待spring容器初始化,数据库连接上等等。
# 三种探测方式
ExecAction
在容器中执行指定的命令,如果执行成功,退出码为 0 则探测成功。
TCPSocketAction
通过容器的 IP 地址和端口号执行 TCP 检 查,如果能够建立 TCP 连接,则表明容器健康。
HTTPGetAction
通过容器的IP地址、端口号及路径调用 HTTP Get方法,如果响应的状态码大于等于200且小于400,则认为容器健康

# 探针属性
initialDelaySeconds: Pod启动后首次进行检查的等待时间,单位“秒”。
periodSeconds: 检查的间隔时间,默认为10s,单位“秒”。
timeoutSeconds: 探针执行检测请求后,等待响应的超时时间,默认为1s,单位“秒”。
successThreshold:连续探测几次成功,才认为探测成功,默认为 1,在 Liveness 探针中必须为1,最小值为1。
failureThreshold: 探测失败的重试次数,重试一定次数后将认为失败,在 readiness 探针中,Pod会被标记为未就绪,默认为 3,最小值为 1

# 探针区别
readinessProbe 当检测失败后,将 Pod 的 IP:Port 从对应的 EndPoint 列表中删除。
livenessProbe 当检测失败后,将杀死容器并根据 Pod 的重启策略来决定作出对应的措施。
# 示例【1】存活探测
# vim pod-test-liveness.yaml
# 容器在初始化后,首先创建一个 /tmp/healthy 文件,存活30秒
# 存活探针检检测方式为执行 shell 命令,有/tmp/healthy则为存活;反之,不存活则按照重启策略重启pod
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  labels:
    app: liveness
spec:
  containers:
  - name: liveness
    image: busybox
    args:                       #创建测试探针探测的文件
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      initialDelaySeconds: 10   #延迟检测时间
      periodSeconds: 5          #检测时间间隔
      exec:
        command:
        - cat
        - /tmp/healthy
# 示例【2】就绪性探测
# vim pod-test-readiness.yaml
# 利用springboot的actuator插件,请求API接口:/actuator/health查看应用状态
# 如果探测成功则代表内部程序以及启动,就开放对外提供接口访问;否则内部应用没有成功启动,暂不对外提供访问,直到就绪探针探测成功。
## 首先需要只做一个springboot项目的镜像(具体查看附录:将MVN项目打包成镜像)
## pod启动成功后访问:http://10.11.2.58:31180/sayHello 也能成功
apiVersion: v1
kind: Service
metadata:
  name: springboot
  labels:
    app: springboot
spec:
  type: NodePort
  ports:
  - name: server
    port: 8080
    targetPort: 8080
    nodePort: 31180
  selector:
    app: springboot
---
apiVersion: v1
kind: Pod
metadata:
  name: springboot
  labels:
    app: springboot
spec:
  containers:
  - name: springboot
    image: docker-demo:1.0-SNAPSHOT
    ports:
    - name: server
      containerPort: 8080
    readinessProbe: 
      initialDelaySeconds: 20   
      periodSeconds: 5          
      timeoutSeconds: 10   
      httpGet:
        scheme: HTTP
        port: 8080
        path: /actuator/health
# 示例【3】两者结合使用
# 【就绪】性探测成功后,应用才可对外提供服务
# 【存活】性探测在指定时间段检测应用健康状态,让应用提供稳定持续的服务
## 需要根据自己应用特性自行设计使用
... ...

启动探测(探针)

## startupProbe: 启动探测
探测容器中的应用是否已经启动。如果提供了启动探测(startup probe),则禁用所有其他探测,直到它成功为止。如果启动探测失败,kubelet 将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功 Success。
可以自定义在 pod 启动时是否执行这些检测,如果不设置,则检测结果均默认为通过,如果设置,则顺序为 startupProbe>readinessProbe>livenessProbe。
## 使用场景
正常情况下,我们会在 pod template 中配置 livenessProbe 来探测容器是否正常运行,如果异常则会触发restartPolicy 重启容器。但是存在特殊情况:
1.服务启动时间是60秒,如果配置的探针启动后10秒检查一次,异常次数为一次,那么这个容器就会陷入重启的死循环
2.如果将检查周期设置为60秒,那么下次服务启动时间增加为70秒,又要重新修改资源文件
3.提高异常次数的阈值,那么将会降低我们发现异常服务的周期时间,对于线上问题不能及时的排查
所以,就需要使用startProbe和livenessProbe配合使用,先确保程序已经启动成功,再进行存活性检测。避免了存活性检测因为程序启动慢等因素导致死循环等。
## 关于livenessProbe和readinessProbe的执行顺序问题
LivenessProbe 会导致 pod 重启,ReadinessProbe 只是不提供服务,他俩没有必然的先后顺序!
(详见官方:https://github.com/kubernetes/kubernetes/issues/60647 )

1.kubelet 使用存活探测器来知道什么时候要重启容器。例如,存活探测器可以捕捉到死锁(应用程序在运行,但是无法继续执行后面的步骤)。这样的情况下重启容器有助于让应用程序在有问题的情况下可用。

2.kubelet 使用就绪探测器可以知道容器什么时候准备好了并可以开始接受请求流量,当一个 Pod 内的所有容器都准备好了,才能把这个Pod看作就绪了。这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。在Pod还没有准备好的时候,会从 Service 的负载均衡器中被剔除的。

3.kubelet 使用启动探测器(startupProbe)可以知道应用程序容器什么时候启动了。如果配置了这类探测器,就可以控制容器在启动成功后再进行存活性和就绪检查,确保这些存活、就绪探测器不会影响应用程序的启动。这可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlgebraFly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值