13、pod的常见状态与探针
pod的常见状态与探针
pod的常见状态
Pod调度流程
创建时序图:
1、用户创建pod的信息通过API Server存储到etcd中,etcd记录pod的元信息并将结果返回API Server
2、API Server告知调度器请求资源调度分配,调度器通过计算,将优先级高的node与pod绑定并告知API Server
3、API Server将此信息写入etcd,得到etcd回复后调用kubelet创建pod
4、kubelet使用docker run创建pod内的容器,得到反馈信息后将容器信息告知API Server
5、API Server将收到的信息写入etcd并得到回馈
6、此时使用kubectl get pod就可以查看到信息了
Pod常见状态
-
Unschedulable:Pod不能被调度,kube-scheduler没有匹配到合适的node节点。
-
PodScheduled:pod正处于调度中,在kube-scheduler刚开始调度的时候,还没有将pod分配到指定的node,在筛选出合适的节点后就会更新etcd数据,将pod分配到指定的node。
-
Failed:Pod中有容器启动失败而导致pod工作异常。
-
Unknown:由于某种原因无法获得pod的当前状态,通常是由于与pod所在的node节点通信错误。
-
Initialized:所有pod中的初始化容器已经完成了
-
ContainerCreating 正在创建
-
Running:Pod内部的容器已经被创建并且启动。
-
Ready:表示pod中的容器已经可以提供访问服务。
-
Completed: 运行完成
-
Error: pod启动过程中发生错误
-
NodeLost:Pod所在节点失联
-
Waiting:Pod等待启动
-
Terminating:Pod正在被销毁
-
CrashLoopBackOff :pod创建失败,但是kubelet正在将它重启
-
ErrImagePull:镜像拉取出错,超时或下载被强制终止
-
ImagePullBackOff:Pod所在的node节点下载镜像失败
-
Pending:正在创建Pod但是Pod中的容器还没有全部被创建完成=处于此状态的Pod应该检查Pod依赖的存储是否有权限挂载等。
-
InvalidImageName:node节点无法解析镜像名称导致的镜像无法下载
-
ImageInspectError:无法校验镜像,镜像不完整导致
-
ErrImageNeverPull:策略禁止拉取镜像,镜像中心权限是私有等
-
RegistryUnavailable:镜像服务器不可用,网络原因或harbor宕机
-
CreateContainerConfigError:不能创建kubelet使用的容器配置
-
CreateContainerError:创建容器失败
-
RunContainerError:pod运行失败,容器中没有初始化PID为1的守护进程等
-
ContainersNotInitialized:pod没有初始化完毕
-
ContainersNotReady:pod没有准备完毕
-
ContainerCreating:pod正在创建中
-
PodInitializing:pod正在初始化中
-
DockerDaemonNotReady:node节点decker服务没有启动
-
NetworkPluginNotReady:网络插件没有启动
Pause 容器
Pause 容器,又叫 Infra 容器,是pod的基础容器,镜像体积只有几百KB 左右,配置在kubelet中,主要的功能是一个pod中多个容器的网络通信。
Infra 容器被创建后会初始化 Network Namespace,之后其它容器就可以加入到 Infra 容器中共享Infra 容器的网络了,因此如果一个 Pod 中的两个容器 A 和 B,那么关系如下 :
- A容器和B容器能够直接使用 localhost 通信;
- A容器和B容器可以可以看到网卡、IP与端口监听信息。
- Pod 只有一个 IP 地址,也就是该 Pod 的 NetworkNamespace 对应的 IP 地址(由Infra 容器初始化并创建)。
- k8s环境中的每个Pod有一个独立的IP地址(前提是地址足够用),并且此IP被当前 Pod 中所有容器在内部共享使用。
- pod删除后Infra 容器随机被删除,其IP被回收。
Pause容器共享的Namespace:
- NET Namespace:Pod中的多个容器共享同一个网络命名空间,即使用相同的IP和端口信息。
- IPC Namespace:Pod中的多个容器可以使用System V IPC或POSIX消息队列进行通信。
- UTS Namespace:pod中的多个容器共享一个主机名。MNT Namespace、PID Namespace、User Namespace未共享
init容器
简介
Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。
你可以在 Pod 的规约中与用来描述应用容器的 containers
数组平行的位置指定 Init 容器。
每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init 容器与普通的容器非常像,除了如下两点:
- 它们总是运行到完成。
- 每个都必须在下一个启动之前成功完成。
如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的 restartPolicy
值为 "Never",并且 Pod 的 Init 容器失败, 则 Kubernetes 会将整个 Pod 状态设置为失败。
Init 容器的状态在 status.initContainerStatuses
字段中以容器状态数组的格式返回
官方文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/init-containers/
init容器作用:
- 可以为业务容器提前准备好业务容器的运行环境,比如将业务容器需要的配置文件提前生成并放在指定位置、检查数据权限或完整性、软件版本等基础运行环境。
- 可以在运行业务容器之前准备好需要的业务数据,比如从OSS下载、或者从其它位置copy。
- 检查依赖的服务是否能够访问
init容器的特点:
- 一个pod可以有多个业务容器还能在有多个init容器,但是每个init容器和业务容器的运行环境都是隔离的。
- init容器会比业务容器先启动。
- init容器运行成功之后才会继续运行业务容器。
- 如果一个pod有多个init容器,则需要从上到下逐个运行并且全部成功,最后才会运行业务容器。
- init容器不支持探针检测(因为初始化完成后就退出再也不运行了)
使用 Init 容器
Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
- Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。 例如,没有必要仅为了在安装过程中使用类似
sed
、awk
、python
或dig
这样的工具而去FROM
一个镜像来生成一个新的镜像。 - Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
- 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
- Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可以访问 应用容器不能访问的 Secret 的权限。
- 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 一旦前置条件满足,Pod 内的所有的应用容器会并行启动
示例:
#yaml
root@k8s-master-01:/opt/yaml/test/init-container# cat init-container-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: init-test
namespace: myserver
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: xmtx.harbor.com/baseimages/nginx:1.22
volumeMounts:
- mountPath: /usr/share/nginx/html/myserver
name: myserver-data
initContainers:
- name: init-web-data
image: xmtx.harbor.com/baseimages/centos:7.9.2009
command: ['/bin/bash','-c',"for i in `seq 1 5`;do echo '<h1>'$i web page at $(date +%Y%m%d%H%M%S) '<h1>' >> /data/nginx/html/myserver/index.html;sleep 1;done"]
volumeMounts:
- mountPath: "/data/nginx/html/myserver"
name: myserver-data
- name: init-web-data2
image: xmtx.harbor.com/baseimages/centos:7.9.2009
command: ['/bin/bash','-c',"for i in `seq 1 5`;do echo '<h1>'$i web page at $(date +%Y%m%d%H%M%S) '<h1>' >> /data/nginx/html/myserver/index2.html;sleep 1;done"]
volumeMounts:
- mountPath: "/data/nginx/html/myserver"
name: myserver-data
volumes:
- name: myserver-data
hostPath:
path: /opt/volume/hostPath/
---
kind: Service
apiVersion: v1
metadata:
name: myserver-myapp-service
namespace: myserver
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
selector:
app: nginx
root@k8s-master-01:/opt/yaml/test/init-container# kubectl apply -f init-container-test.yaml
查看启动过程:
访问测试:
kubernetes pod生命周期和探针
pod lifecycle
Pod 的 status
字段是一个 PodStatus 对象,PodStatus中有一个 phase
字段。
Pod 的相位(phase)是 Pod 在其生命周期中的简单宏观概述。该字段并不是对容器或 Pod 的综合汇总,也不是为了做为综合状态机。
Pod 相位的数量和含义是严格指定的。除了本文档中列举的状态外,不应该再假定 Pod 有其他的 phase
值。
下面是 phase
可能的值:
- 挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
- 运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
- 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
- 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
- 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。
生命周期示意图:
探针
简介
探针是由 kubelet 对容器执行的定期诊断,以保证Pod的状态始终处于运行状态,要执行诊断,kubelet 调用由容器实现的Handler(处理程序)
,也称为Hook(钩子)
。有三种类型的处理程序:
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
- 成功:容器通过了诊断。
- 失败:容器未通过诊断。
- 未知:诊断失败,因此不会采取任何行动。
Pod重启策略
Pod一旦配置探针,在检测失败时候,会基于restartPolicy对Pod进行下一步操作:
restartPolicy (容器重启策略):
- Always:当容器异常时,k8s自动重启该容器,ReplicationController/Replicaset/Deployment,默认为Always
- OnFailure:当容器失败时(容器停止运行且退出码不为0),k8s自动重启该容器。
- Never:不论容器运行状态如何都不会重启该容器,Job或CronJob。
探针类型
-
startupProbe(启动探针): 使用启动探测器来了解应用容器何时启动。 如果配置了这类探测器,你就可以控制容器在启动成功后再进行存活性和就绪态检查, 确保这些存活、就绪探测器不会影响应用的启动。 如果启动探测失败,则kubelet将杀死容器,容器将按照重启策略进行下一步操作,如果容器没有提供启动探测,则默认状态为成功
-
livenessProbe(存活探针):使用存活探测器来控制是否重启pod。检测容器是否正在运行,如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响,如果容器不提供存活探针,则默认状态为 Success。
-
readinessProbe(就绪探针): 使用就绪探测器可以知道容器何时准备好接受请求流量,当一个 Pod 内的所有容器都就绪时,才能认为该 Pod 就绪。 如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址,初始延迟之前的就绪状态默认为Failure(失败),如果容器不提供就绪探针,则默认状态为 Success,就绪探针用于控制pod是否添加至service。
探针通用配置参数
探针有很多配置字段,可以使用这些字段精确的控制存活和就绪检测的行为:
- initialDelaySeconds:初始化延迟时间,告诉kubelet在执行第一次探测前应该等待多少秒,默认是0秒,最小值是0
- periodSeconds:探测周期间隔时间,指定了kubelet应该每多少秒秒执行一次存活探测,默认是 10 秒。最小值是 1
- timeoutSeconds:单次探测超时时间,探测的超时后等待多少秒,默认值是1秒,最小值是1。
- successThreshold:从失败转为成功的重试次数,探测器在失败后被视为成功的最小连续成功数,默认值是1存活探测的这个值必须是1,最小值是 1。
- failureThreshold:从成功转为失败的重试次数,当Pod启动了并且探测到失败,Kubernetes的重试次数,存活探测情况下的放弃就意味着重新启动容器,就绪探测情况下的放弃Pod 会被打上未就绪的标签,默认值是3,最小值是1。
探针http配置参数
HTTP 探测器可以在 httpGet 上配置额外的字段:
host:连接使用的主机名,默认是Pod的 IP,也可以在HTTP头中设置 “Host” 来代替。
scheme:用于设置连接主机的方式(HTTP 还是 HTTPS),默认是 HTTP。
path:访问 HTTP 服务的路径。
httpHeaders:请求中自定义的 HTTP 头,HTTP 头字段允许重复。
port:访问容器的端口号或者端口名,如果数字必须在 1 ~ 65535 之间。
示例:
存活探针使用
root@k8s-master-01:/opt/yaml/test/probe# cat pods-probe-liveness-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-test
namespace: myserver
spec:
containers:
- name: liveness
image: xmtx.harbor.com/baseimages/busybox:1.35.0
#创建文件/tmp/healthy,30秒后删除它。
command: ["/bin/sh","-c","touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"]
livenessProbe:
exec:
#检测/tmp/healthy文件是否存在。
command: ["/bin/sh","-c","cat /tmp/healthy"]
initialDelaySeconds: 5 #等待5秒后开始存活检测
periodSeconds: 5 #每隔5秒执行一次探针检测
httpGet使用
root@k8s-master-01:/opt/yaml/test/probe# cat pods-probe-httpget-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpget-liveness-test
namespace: myserver
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: xmtx.harbor.com/baseimages/nginx:1.9.1
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 5 #等待5秒后开始存活检测
periodSeconds: 3 #间隔3秒
timeoutSeconds: 5 #超时后等待5秒
successThreshold: 1 #1次后转为成功
failureThreshold: 3 #检测失败3次后放弃,打上未就绪的标签
---
apiVersion: v1
kind: Service
metadata:
name: httpget-liveness-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30080
protocol: TCP
type: NodePort
selector:
app: nginx
就绪探针检测失败后会将容器变为未就绪状态
TCP 的存活探针使用
#yaml文件
root@k8s-master-01:/opt/yaml/test/probe# cat pods-probe-tcp-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpget-liveness-test
namespace: myserver
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: xmtx.harbor.com/baseimages/nginx:1.9.1
ports:
- containerPort: 80
livenessProbe:
#readinessProbe:
tcpSocket:
port: 80
#port: 8080
initialDelaySeconds: 5 #等待5秒后开始存活检测
periodSeconds: 3 #间隔3秒
timeoutSeconds: 5 #超时后等待5秒
successThreshold: 1 #1次后转为成功
failureThreshold: 3 #检测失败3次后放弃,重启容器
---
apiVersion: v1
kind: Service
metadata:
name: httpget-liveness-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30080
protocol: TCP
type: NodePort
selector:
app: nginx
#创建
root@k8s-master-01:/opt/yaml/test/probe# kubectl apply -f pods-probe-tcp-test.yaml
#正常结果
root@k8s-master-01:/opt/yaml/test/probe# kubectl get pod -n myserver
NAME READY STATUS RESTARTS AGE
httpget-liveness-test-74bb7448cb-2wgqz 1/1 Running 0 25s
#将检测端口改为错误的
livenessProbe:
#readinessProbe:
tcpSocket:
#port: 80
port: 8080
结果:
存活探针检测失败后会根据容器重启策略对当前容器进行操作
启动探针使用
root@k8s-master-01:/opt/yaml/test/probe# cat pods-probe-startupProbe.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpget-liveness-test
namespace: myserver
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: xmtx.harbor.com/baseimages/nginx:1.9.1
ports:
- containerPort: 80
#livenessProbe:
#readinessProbe:
startupProbe:
httpGet:
#path: /index22.html
path: /index.html
port: 80
initialDelaySeconds: 5 #等待5秒后开始存活检测
periodSeconds: 3 #间隔3秒
failureThreshold: 3 #检测失败3次后放弃,
---
apiVersion: v1
kind: Service
metadata:
name: httpget-liveness-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30080
protocol: TCP
type: NodePort
selector:
app: nginx
#应用
root@k8s-master-01:/opt/yaml/test/probe# kubectl apply -f pods-probe-startupProbe.yaml
deployment.apps/httpget-liveness-test created
service/httpget-liveness-service created
root@k8s-master-01:/opt/yaml/test/probe# kubectl get pod -n myserver
NAME READY STATUS RESTARTS AGE
httpget-liveness-test-55f5877c97-szv9r 1/1 Running 0 47s
#将path改为错误的
path: /index22.html
启动探针检测失败后会根据容器重启策略对当前容器进行操作
三种探针检测结合使用
当启动探针检测成功后才会执行剩下两种探针,如果就绪探针的存活探针检测失败,存活探针会重启容器,就绪探针会将这个pod从service拿掉停止其他访问
root@k8s-master-01:/opt/yaml/test/probe# cat pods-probe-allProbe.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpget-liveness-test
namespace: myserver
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: xmtx.harbor.com/baseimages/nginx:1.9.1
ports:
- containerPort: 80
startupProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 5 #首次检测延迟5s
failureThreshold: 3 #从成功转为失败的次数
periodSeconds: 3 #探测间隔周期
readinessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
postStart 和 preStop
postStart和preStop handlers处理函数
postStart:
Pod被创建后立即执行检测,即不等待pod中的服务启动。
如果postStart执行失败pod不会继续创建
preStop:
在pod被停止前执行
root@k8s-master-01:/opt/yaml/test/events# cat lifecycle-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpget-liveness-test
namespace: myserver
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: xmtx.harbor.com/baseimages/nginx:1.9.1
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
#command: 把自己注册到注册在中心
command: ["/bin/sh", "-c", "echo 'Hello from the postStart handler' > /usr/share/nginx/html/index.html"]
preStop:
exec:
#command: 把自己从注册中心移除
command: ["/usr/local/tomcat/bin/catalina.sh","stop"]
---
apiVersion: v1
kind: Service
metadata:
name: httpget-liveness-service
namespace: myserver
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30080
protocol: TCP
type: NodePort
selector:
app: nginx
#测试
root@k8s-master-01:/opt/yaml/test/events# kubectl get pod -n myserver
NAME READY STATUS RESTARTS AGE
httpget-lifecycle-test-58f57f4946-bslnr 1/1 Running 0 25s
Pod的终止流程
1.创建pod完成调度流程容器启动并执行postStartlivenessProbe进入running状态readinessProbeservice关联pod接受客户端请求
2.删除pod Pod被设置为”Terminating”状态、从service的Endpoints列表中删除并不再接受客户端请求。执行PreStopKubernetes向pod中的容器发送SIGTERM信号(正常终止信号)终止pod里面的主进程,这个信号让容器知道自己很快将会被关闭terminationGracePeriodSeconds: 60 #可选终止等待期,如果有设置删除宽限时间,则等待宽限时间到期,否则最多等待30s,Kubernetes等待指定的时间称为优雅终止宽限期,默认情况下是30秒,值得注意的是等待期与preStop Hook和SIGTERM信号并行执行,即Kubernetes可能不会等待preStop Hook完成(最长30秒之后主进程还没有结束就就强制终止pod)。SIGKILL信号被发送到Pod,并删除Pod。