Kubernetes Pod 生命周期详解 之 探针
1.探针
deployment pod控制器
如果创建一个pod 如果销毁了 那就是销毁了
deployment 创建可以定义几个pod 或者 怎么创建pod
按照我们要求去创建
kubernetes 提供了一个 负载均衡 更简化的 操作
service
service 创建的时候需要我们指定一个东西 就是我们标签选择器
label 标签选择 label app=myapp
就绪探测
如果 pod 内部的 C 不添加就绪探测,默认就绪。如果添加了就绪探测, 只有就绪通过以后,才标记修改为就绪状态。当前 pod 内的所有的 C 都就绪,才标记当前 Pod 就绪
成功:将当前的 C 标记为就绪
失败:静默
未知:静默
或者服务没准备好,并且是下线的状态,他不采取动作,也就是他和存活探测不一样的点是,他不会杀死容器,而是单纯的控制容器加入或者退出负载均衡的这么一个机制
那这个就绪探测,可以理解为专门给服务提供上线和下线的作用,服务准备好了,他提供服务上线,服务没准备好,他提供下线,
2.怎么删除pod
kubectl delete pod [pod名]
--all 可以删除当前资源的所有pod
3.小实验
apiVersion: v1
kind: Pod
metadata:
name: pod-1
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp-1
image: wangyanglinux/myapp:v1.0
apiVersion: v1
kind: Pod
metadata:
name: pod-2
namespace: default
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp-1
image: wangyanglinux/myapp:v1.0
kubectl create -f 1.pod.yaml
kubectl create -f 2.pod.yaml
1.创建service
kubectl create svc myapp
这样他会有一个默认值 ,那么它默认就回去匹配 app=myapp的标签的pod 所以service的名字 建议不要乱写
所以我们执行下面的命令
kubectl create svc clusterip myapp --tcp=80:80
用户只需要访问 10.5.251.92:80端口 就可以负载均衡访问 后台两个 pod里80端口对应的两台服务器
service 名字叫 myapp 默认匹配标签 app=myapp 的pod
负载均衡的方式下访问我们的pod
这个获取主机名其实是pod名 默认为主机名
我们再加一个pod 这个app改成 test 看看service还能负载均衡到这个主机名吗
没有办法匹配 pod-3
4.就绪探测
1.基于httpGet方式
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
labels:
app: myapp
env: test
spec:
containers:
- name: readiness-httpget-container
image: wangyanglinux/myapp:v1.0
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
imagePulPolicy: 镜像拉取策略 如果本地存在 就不会去远程拉取镜像 而是本地直接使用
readinessProbe: 代表就绪探测
方案
通过 http请求的 Get 方法 访问 80端口 下的 /index1.html 注意当前镜像下是没有这个文件的 所以访问不通
initialDelaySeconds: 延迟检测时间 1秒以后的探测
periodSeconds :每三秒一次的间隔做重复探测 比如第一次我失败了 那我三秒再测一次 直到成功
该pod虽然再running 但是 未就绪 因为就绪探针不通过
虽然 它由 app=myapp 的标记 已经被我们service匹配了 但是
始终没有出现 就是因为 就绪探针没有通过 不会负载均衡给用户去使用未就绪的 pod 即使标签匹配在 service的子集
这就是我们就绪探针存在的意义
想要恢复就绪
我们进入容器去添加这么一个文件
kubectl exec -it readiness-httpget-pod -- /bin/bash
将“” 字符串 写入 index1.html 文件中 不存在就创建出来
echo "jmj daociyiyou" >> index1.html
退出当前容器
exit
kubectl get pod
启动了
正常被负载均衡里面访问
2.基于EXEC方式
apiVersion: v1
kind: Pod
metadata:
name: readiness-exec-pod
namespace: default
spec:
containers:
- name: readiness-exec-container
image: wangyanglinux/tools:busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","touch /tmp/live ; sleep 60; rm -rf /tmp/live; sleep 3600"]
readinessProbe:
exec:
command: ["test","-e","/tmp/live"]
initialDelaySeconds: 1
periodSeconds: 3
定义命令: command: 创建 /tmp/live 休眠60秒 递归删除 /tmp/live 再休眠 3600秒
readinessProbe 就绪探测
test -e 加路径 :判断路径下的文件存不存在 如果存在代表就绪通过
经过60 秒后 文件被删除 然后发送就绪探测的时候 文件就不存在了 就绪就不通过了
新版的就绪探测 是从开始 到容器死亡 都一直重复去做
kubectl create -f 5.pod.yaml
kubectl get pod -w
代表监视看pod状态
发现60 秒后进入未就绪 是因为 我们60秒就把文件删除了 所以就绪探测检测到文件不存在了 就标记为未就绪
3.基于TCP Check 方式
apiVersion: v1
kind: Pod
metadata:
name: readiness-tcp-pod
namespace: default
spec:
containers:
- name: readiness-tcp-container
image: wangyanglinux/myapp:v1.0
readinessProbe:
initialDelaySeconds: 1
periodSeconds: 3
tcpSocket:
port: 80
timeoutSeconds 超时时间 1秒
tcp 检测 端口 是 80 端口
只有当前应用的 80端口 能和我 TCP 连接 成功 那么代表就绪探测成功 ,否则就是失败
不常用 因为如果把里面的进程杀死 就代表 这个容器本身就会死 所以我们不常用
5.存活探针 livenessProbe
kubectl get pod pod-1 -o yaml
[root@k8s-master01 6]# kubectl get pod pod-1 -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
cni.projectcalico.org/containerID: 5652c8888a94c29892490e163738d9ceffe0a662b948abe3f8fee2b3bd8cb522
cni.projectcalico.org/podIP: 10.244.85.200/32
cni.projectcalico.org/podIPs: 10.244.85.200/32
creationTimestamp: "2025-03-10T12:28:40Z"
labels:
app: myapp
name: pod-1
namespace: default
resourceVersion: "110369"
uid: 0478da02-c28d-4852-882c-bdad5cad9870
spec:
containers:
- image: wangyanglinux/myapp:v1.0
imagePullPolicy: IfNotPresent
name: myapp-1
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-wf2df
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: k8s-node01
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: kube-api-access-wf2df
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2025-03-11T11:14:06Z"
status: "True"
type: PodReadyToStartContainers
- lastProbeTime: null
lastTransitionTime: "2025-03-10T12:28:40Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2025-03-11T11:14:06Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2025-03-11T11:14:06Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2025-03-10T12:28:40Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: docker://2d7d387b24baf5155244a6a001afa4e45101558281a1eed832bfe5d07a04bfea
image: wangyanglinux/myapp:v1.0
imageID: docker-pullable://wangyanglinux/myapp@sha256:77d7ec4cd4c00f79304ee9e53ca3d72e0aba22fbaf7a86797528649e3fc66e41
lastState:
terminated:
containerID: docker://85cc85a7ae1abd19ec04688fee7202616bb976e85b77d6cd2e16ed79cadaca6b
exitCode: 0
finishedAt: "2025-03-11T11:10:06Z"
reason: Completed
startedAt: "2025-03-10T12:28:41Z"
name: myapp-1
ready: true
restartCount: 1
started: true
state:
running:
startedAt: "2025-03-11T11:14:05Z"
hostIP: 192.168.72.12
hostIPs:
- ip: 192.168.72.12
phase: Running
podIP: 10.244.85.200
podIPs:
- ip: 10.244.85.200
qosClass: BestEffort
startTime: "2025-03-10T12:28:40Z"
当前资源对象存储在kubernetes 集群里的具体的默认参数信息
这么多东西 我们定义的时候没写这么多啊 ,但是很多的都是默认值
重启策略
restartPolicy:Always 只要容器死了不管是以 0的方式死亡 还是非0的方式死亡 我都会进行重建动作
1.基于 exec 的方式
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: wangyanglinux/tools:busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","touch /tmp/live ; sleep 60; rm -rf /tmp/live;sleep 3600"]
livenessProbe:
exec:
command: ["test","-e","/tmp/live"]
initialDelaySeconds: 1
periodSeconds: 3
重启了 又开始等待60秒 删除 然后又会重建
2.基于HTTP Get 方式
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: wangyanglinux/tools:busybox
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 1
ports 对于单独一个pod 定义是毫无意义 的 因为 在这个容器 内网 80端口都是能够互相访问通的
只要我们进入容器吧 index.html 删除 如果它启动能恢复的话 说明我们的猜测是真的
把我踢掉了
因为容器没有通过存货探测
我们重新进入容器 发现容器里面 已经没有我们之前建的.back 而是原始镜像里默认目录 ,说明它重新创建了容器
在node02 运行
结构
k8s_容器名_pod名_命名空间_MD5值_重启次数
当容器损坏的时候 我们能利用 重启策略来达到一个 自愈的机制
3.基于TCP check方式
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcp-pod
spec:
containers:
- name: liveness-tcp-container
image: wangyanglinux/myapp:v1.0
livenessProbe:
initialDelaySeconds: 5
timeoutSeconds: 3
tcpSocket:
port: 80
一般不用
探测地址 就是 localhost 也就是本地的pod地址
存活探测保证了 pod运行 一定是能让用户访问的 除非你的存活探测设置的有问题
6.启动探针 startupProbe
如果不定义启动探针,那存活探针和就绪探针的执行时机将不确定 ,可能导致容器还没起来 ,就检测为不存活又被杀死重建 所以启动探针很重要
apiVersion: v1
kind: Pod
metadata:
name: startupprobe-1
namespace: default
spec:
containers:
- name: myapp-container
image: wangyanglinux/myapp:v1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index2.html
initialDelaySeconds: 1
periodSeconds: 3
startupProbe:
httpGet:
path: /index1.html
port: 80
failureThreshold: 30
periodSeconds: 10
把就绪探测的条件满足 ,但是发现还是未就绪 是因为,启动探测未成功 不会执行就绪探测
我们把启动探测满足了
就绪了
7.钩子
分为启动后钩子 和关闭前钩子
但是启动后钩子其实是在初始化之后启动之前运行的 别搞混了
并且启动钩子还有可能在启动钩子命令还没有执行完成 我们的容器启动命令就开始执行了
但是关闭前钩子 一定是关闭前钩子执行完了 才执行容器关闭信号
1.基于exec的方式
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-exec-pod
spec:
containers:
- name: lifecycle-exec-container
image: wangyanglinux/myapp:v1
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo postStart > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh", "-c", "echo preStop > /usr/share/message"]
看到我们启动后钩子 已经把字符串写进文件里了
执行脚本 循环看这个文件内容 开启另一个终端来让 关闭前钩子执行
将pod杀死
发现 关闭前钩子执行了
2.基于HTTPGET方式
开启一个测试webServer服务
docker run -it --rm -p 1234:80 wangyanglinux/myapp:v1.0
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-httpget-pod
labels:
name: lifecycle-httpget-pod
spec:
containers:
- name: lifecycle-httpget-container
image: wangyanglinux/myapp:v1.0
ports:
- containerPort: 80
lifecycle:
postStart:
httpGet:
host: 192.168.72.11
path: index.html
port: 1234
preStop:
httpGet:
host: 192.168.72.11
path: hostname.html
port: 1234
后置请求
8.关于preStop的延伸话题
如果30秒没退出 那么kubernetes将会发出 -9 级别的强制杀死
可以通过上面关键字定义我的容忍信息 也可以通过 --grace-period 定义覆盖pod 中的配置
9.终极整合实验
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-pod
labels:
app: lifecycle-pod
spec:
containers:
- name: busybox-container
image: wangyanglinux/tools:busybox
command: ["/bin/sh","-c","touch /tmp/live ; sleep 600; rm -rf /tmp/live; sleep 3600"]
livenessProbe:
exec:
command: ["test","-e","/tmp/live"]
initialDelaySeconds: 1
periodSeconds: 3
lifecycle:
postStart:
httpGet:
host: 192.168.72.11
path: index.html
port: 1234
preStop:
httpGet:
host: 192.168.72.11
path: hostname.html
port: 1234
- name: myapp-container
image: wangyanglinux/myapp:v1.0
livenessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 3
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
initContainers:
- name: init-myservice
image: wangyanglinux/tools:busybox
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: wangyanglinux/tools:busybox
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
我们发现没有起来 是因为 初始化容器检测 没有对应的service 域名解析 所以初始化不成功
kubectl create svc clusterip myservice --tcp=80:80
创建一个 service 类型 为 clusterip --tcp=80:80 访问这个域名的80端口 会负载均衡访问这个service所揽住的 pod 的容器内部 80端口
这时候我们第一个初始化容器通过了
kubectl create svc clusterip mydb --tcp=80:80
pod进入初始化状态
存活探针给杀了
这时候它又被重新创建了 ,但是由于由 就绪探针 没有 index1.html 所以无法变成就绪了
启动后钩子执行了
但是如果是存活探针杀死的 容器他不会执行 preStop 钩子