Pod生命周期
官方:https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/
1 探针的介绍
探针是由 kubelet 对容器执行的定期诊断:
ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
成功:容器通过了诊断。
失败:容器未通过诊断。
未知:诊断失败,因此不会采取任何行动。
Kubelet 可以选择是否执行在容器上运行的三种探针执行和做出反应:
- livenessProbe(存活探针):指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略
的影响。如果容器不提供存活探针,则默认状态为 Success。 - readinessProbe(就绪探针):指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为Success。
- startupProbe(启动探针): 指示容器中的应用是否已经启动。如果提供了启动探测(startup probe),则禁用所有其他探测,直到它成功为止。如果启动探测失败,kubelet将杀死容器,容器服从其重启策略进行重启。如果容器没有提供启动探测,则默认状态为成功Success。
重启策略:PodSpec 中有一个 restartPolicy 字段,可能的值为 Always、OnFailure 和 Never。默认为 Always。
2 探针的使用
2.1 存活探针的使用
kubelet 使用存活探测器来知道什么时候要重启容器。 例如,存活探测器可以捕捉到死锁(应用程序在运行,但是无法继续执行后面的步骤)
(1)存活探针的定义
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: myapp:v1
args: ## 当容器启动时,执行的命令,,新建文件/tmp/healthy,30s后删除,休眠600s
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe: ## 存活探测 /tmp/healthy是否存在
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5 ## 告诉kubelet在执行第一次探测前应该等待 5 秒
periodSeconds: 5 ## 指定了kubelet每5秒执行一次存活探测
应用资源清单文件:kubectl create -f live.yml
kubelet 在容器内执行命令cat /tmp/healthy来进行探测。如果命令执行成功并且返回值为0,kubelet就会认为这个容器是健康存活的;如果这个命令返回非 0值,kubelet会杀死这个容器并重新启动它
(1)在 30 秒内,查看 Pod 的事件:
- 显示pod的信息:
kubectl get pod -w
- 查看pod的详细信息:
kubectl describe pod liveness-exec
- 输出结果表明存活探测器还未失败
(2)30s后:查看pod的信息
kubectl get pod
kubectl describe pod liveness-exec
- 有信息显示存活探测器失败
- 存活探测器失败了,这个容器被杀死并且被重建
(3)容器重启30s后,再次执行命令cat /tmp/healthy来进行探测,失败,会再次重启
- 查看pod的信息:
kubectl describe pod liveness-exec
- 删除pod:
kubectl delete -f live.yml
2.2 定义HTTP的就绪探测
kubelet 使用就绪探测器可以知道容器什么时候准备好了并可以开始接受请求流量, 当一个 Pod 内的所有容器都准备好了,才能把这个 Pod 看作就绪了。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 在 Pod 还没有准备好的时候,会从 Service 的负载均衡器中被剔除的
下面这个例子同时使用就绪和存活探测器
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: myapp:v1
## kubelet会在容器启动5秒后进行第一次存活探测,尝试连接myapp容器的80端口,如果存活探测失败,这个容器会被重新启动
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
periodSeconds: 5
## kubelet会在容器启动3秒后发送第一个就绪探测,判断hello.html是否存在;如果探测成功,这个Pod会被标记为就绪状态,kubelet将继续每隔3秒运行一次检测
readinessProbe:
httpGet:
path: /hello.html ## 文件不存在
port: 80
initialDelaySeconds: 3
periodSeconds: 3
(1)应用文件:kubectl create -f live.yml
- 查看pod的状态:
kubectl get pod
- 因为探测就绪的条件不成立,所以程序一直处于就绪状态
- 查看pod的信息:
kubectl describe pod liveness-exec
,Ready失败
(2)进入容器的交互环境,使就绪的条件成立:kubectl exec liveness-exec -it -- sh
- 查看pod的状态:
kubectl get pod
- 查看pod的详细信息:
kubectl describe pod liveness-exec
2.3 TCP 的存活探测和就绪检测
使用 TCP 套接字进行存活探测。 kubelet 会尝试在指定端口和容器建立套接字链接。 如果能建立连接,这个容器就被看作是健康的,如果不能则这个容器就被看作是有问题的
(1)应用文件:kubectl create -f live.yml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: myapp:v1
## 存活探测:kubelet在容器启动5秒后进行第一次存活探测。尝试连接liveness容器的8080 端口。 如果存活探测失败,这个容器会被重新启动。
livenessProbe:
tcpSocket:
port: 8080 ## 端口错误
initialDelaySeconds: 5
periodSeconds: 5 ## 5s执行一次
## kubelet在容器启动3秒后发送第一个就绪探测。判断myapp默认页面hostname.html是否存在,尝试连接liveness的80端口。如果探测成功,这个Pod会被标记为就绪状态,kubelet将继续每隔3秒运行一次检测
readinessProbe:
httpGet:
path: /hostname.html
port: 80
initialDelaySeconds: 3
periodSeconds: 3 ### 3s探测一次
(2)查看pod的详细信息:kubectl get pod
- 查看pod的详细信息:
kubectl describe pod liveness-exec
,存活检测失败,容器重启
- 查看pod的信息:
kubectl get pod
,发现pod一直处于就绪状态
- 查看pod的详细信息:
kubectl describe pod liveness-exec
,存活检测失败后容器重启
3 Init 容器
3.1 Init 容器的介绍
除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器
每个 Pod 中可以包含多个容器, 应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。
Init 容器与普通的容器非常像,除了如下两点:
它们总是运行到完成。
每个都必须在下一个启动之前成功完成。
- 如果 Pod 的 Init 容器失败,kubelet 会不断地重启该 Init 容器直到该容器成功为止。 然而,如果 Pod 对应的
restartPolicy 值为 “Never”,Kubernetes 不会重新启动 Pod。 - 为 Pod 设置 Init 容器需要在 Pod 的 spec 中添加 initContainers 字段, 该字段以 Container类型对象数组的形式组织,和应用的 containers 数组同级相邻。 Init容器的状态在status.initContainerStatuses 字段中以容器状态数组的格式返回 (类似status.containerStatuses 字段)
- Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 然而,Init容器对资源请求和限制的处理稍有不同,在下面资源节有说明。
- 同时 Init 容器不支持 lifecycle、livenessProbe、readinessProbe 和 startupProbe,因为它们必须在 Pod 就绪之前运行完成。
- 如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的
Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行
3.2 Init 容器的作用
(1)Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。
(2)Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
(3)Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。
(4)由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。
3.3 Service定义
kubernetes中的service是一种逻辑概念。它定义了一个pod逻辑集合以及访问它们的策略,service与pod的关联同样是通过label完成的。service的目标是提供一种桥梁,他会为访问者提供一个固定的访问IP地址,用于在访问时重定向到相应的后端,这可以使一些非kubernetes原生应用程序,在无需为kubernetes编写特定代码的前提下轻松访问后端
- 创建pod:
kubectl run demo --image=busyboxplus -it
- 登陆容器:
kubectl attach demo -it
nslookup myservice ## 不能解析myservice
解决方法:
- 编辑Service 的配置文件:
vim service.yml
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP ## 协议
port: 80
targetPort: 80
- 创建pod:
kubectl create -f service.yml
- 显示运行中的Pod、Service、Deployment以及ReplicaSet的关键信息:
kubectl get all
- 查看myservice的详细信息:
kubectl describe svc myservice
一个 Service 由一组 backend Pod 组成,这些 Pod 通过 endpoints 暴露出来
- 进入容器:虽然Endpoints的信息为空,但是可以正常解析
kubectl attach demo -it
nslookup myservice
- 删除service.yml生成的pod后不能正常解析servvice
3.4 Init 容器的使用
下面的例子定义了一个具有 Init 容器的简单 Pod。只有Init的myservicet容器启动完成,Pod 将启动 spec 节中的应用容器
(1)编辑文件:vim init.yml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: myapp:v1
initContainers:
- name: init-myservice
image: busyboxplus
command: ['sh', '-c', "until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
## 只要nslookup myservice.default.svc.cluster.local不成功解析就会一直执行这一句
(2)创建pod:kubectl create -f init.yml
- 查看pod的信息:
kubectl get pod
,init未完成
- 查看 Pod 内 Init 容器的日志:
kubectl logs myapp-pod init-myservice
,出错的原因是nslookup myservice.default.svc.cluster.local未解析,myservicet容器启动完成
(3)创建myservers的:kubectl create -f service.yml
,能解析myservers
- 查看服务:
kubectl get svc
- 查看pod的信息:
kubectl get pod
,Init的myservicet容器启动完成,Pod 将启动 spec 节中的应用容器
- 查看 Pod 内 Init 容器的日志:
kubectl logs myapp-pod init-myservice
,myservice可以正常解析