pod生命周期

和一个个独立的应用容器一样,Pod 也被认为是相对临时性(而不是长期存在)的实体。 Pod 会被创建、赋予一个唯一的 ID(UID),并被调度到节点,并在终止(根据重启策略)或删除之前一直运行在该节点。

如果一个节点死掉了,调度到该节点 的 Pod 也被计划在给定超时期限结束后删除。

Pod 自身不具有自愈能力。如果 Pod 被调度到某节点 而该节点之后失效,或者调度操作本身失效,Pod 会被删除;与此类似,Pod 无法在节点资源 耗尽或者节点维护期间继续存活。Kubernetes 使用一种高级抽象,称作控制器,来管理这些相对而言可随时丢弃的 Pod 实例。

任何给定的 Pod (由 UID 定义)从不会被“重新调度(rescheduled)”到不同的节点; 相反,这一 Pod 可以被一个新的、几乎完全相同的 Pod 替换掉。 如果需要,新 Pod 的名字可以不变,但是其 UID 会不同。

如果某物声称其生命期与某 Pod 相同,例如存储卷, 这就意味着该对象在此 Pod (UID 亦相同)存在期间也一直存在。 如果 Pod 因为任何原因被删除,甚至某完全相同的替代 Pod 被创建时, 这个相关的对象(例如这里的卷)也会被删除并重建。

我们一般将Pod对象从创建到终止的这段时间范围称为Pod的生命周期,它主要包含下面的过程:

​ 1)Pod创建过程;

​ 2)运行初始化容器(init container)过程;

​ 3)运行主容器(main container):

​ ① 容器启动后钩子函数(post start)、容器终止前钩子函数(pre stop)

​ ②容器存活性探测(liveness probe)、就绪性探测(readiness probe)

​ 4) Pod终止过程。

pod在生命周期内的五种状态

取值 描述
Pending(挂起) Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
Running(运行中) Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
Succeeded(成功) Pod 中的所有容器都已成功终止,并且不会再重启。
Failed(失败) Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。
Unknown(未知)

因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

 

如果某节点死掉或者与集群中其他节点失联,Kubernetes 会实施一种策略,将失去的节点上运行的所有 Pod 的取值设置为 Failed。

pod的创建过程

1、kubectl向apiserver发送一个创建pod的请求

2、apiserver收到请求后生成一个包含创建信息的yaml文件并写入etcd。

3、scheduler发现有新的pod要创建,经过计算再找出最适合创建的node进行创建。

4、node节点的kubelet接收到创建pod的信息后调用docker启动容器,然后将结果发送给apiserver

5、apiserver将接收到pod的信息存入etcd

Pod 状况查看

Pod 有一个 PodStatus 对象,其中包含一个 PodConditions 数组。Pod 可能通过也可能未通过其中的一些状况测试。

  • PodScheduled:Pod 已经被调度到某节点;
  • ContainersReady:Pod 中所有容器都已就绪;
  • Initialized:所有的 Init 容器 都已成功完成;
  • Ready:Pod 可以为请求提供服务,并且应该被添加到对应服务的负载均衡池中。
字段名称 描述
type Pod 状况的名称
status 表明该状况是否适用,可能的取值有 "True", "False" 或 "Unknown"
lastProbeTime 上次探测 Pod 状况时的时间戳
lastTransitionTime Pod 上次从一种状态转换到另一种状态时的时间戳
reason 机器可读的、驼峰编码(UpperCamelCase)的文字,表述上次状况变化的原因
message 人类可读的消息,给出上次状态转换的详细信息

初始化容器(init c)

初始化容器Init Container是在Pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,可以是一个 它具有两大特征:

初始化容器必须运行完成直至结束,如果某个初始化容器运行失败,那么Kubernetes需要重启它直至成功完成。

初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面一个才能运行。

初始化容器有很多应用场景,下面列出的是最常见的几种:

提供主容器镜像中不具备的工具程序或自定义代码。
初始化容器要先于应用容器串行启动并运行完成;因此可用于延后应用容器的启动直至其依赖的条件得到满足。

例:

我们先创建一个init-pod.yml 文件

apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-containers
image: busybox
command: ['sh' ,'-c','echo the app is running && sleep 600s']
initContainers:
- name: init-myservice
image: busybox
command: ['sh','-c', 'until nslookup myservice; do echo waiting from myservice; sleep 2s ;done ']
- name: mydb-containers
image: busybox
command: ['sh','-c','until nslookup mydb; do echo waiting from mydb; sleep 2s; done']

然后创建pod并查看: kubectl create -f init-pod.yml

[root@master ~]# kubectl create -f init-pod.yml
pod/myapp-pod created
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 23s
nginx-6799fc88d8-648cn 1/1 Running 0 48d

此时myapp-pod显示正在init初始化,我们describe看一下这个pod状态

[root@master ~]# kubectl describe pods myapp-pod
Name: myapp-pod
Namespace: default
Priority: 0
Node: node1/192.168.248.128
Start Time: Mon, 27 Jun 2022 15:49:59 +0800
Labels: app=myapp
Annotations: cni.projectcalico.org/containerID: bdead7238a0b177ce59049c3d13a180dadd5c867ad6eb3f0aa06710585eac8c5
cni.projectcalico.org/podIP: 10.101.149.3/32
cni.projectcalico.org/podIPs: 10.101.149.3/32
Status: Pending
IP: 10.101.149.3
IPs:
IP: 10.101.149.3
Init Containers:
init-myservice:
Container ID: docker://b2bcc9e7e88702bdf2fbd53fdfc5e70063d5fc3419338770f14b8b48804e4800
Image: busybox
Image ID: docker-pullable://busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
Port: <none>
Host Port: <none>
Command:
sh
-c
until nslookup myservice; do echo waiting from myservice; sleep 2s ;done
State: Running
Started: Mon, 27 Jun 2022 15:50:25 +0800
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-trqgw (ro)
mydb-containers:
Container ID:
Image: busybox
Image ID:
Port: <none>
Host Port: <none>
Command:
sh
-c
until nslookup mydb; do echo waiting from mydb; sleep 2s; done
State: Waiting
Reason: PodInitializing
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-trqgw (ro)
Containers:
myapp-containers:
Container ID:
Image: busybox
Image ID:
Port: <none>
Host Port: <none>
Command:
sh
-c
echo the app is running && sleep 600s
State: Waiting
Reason: PodInitializing
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-trqgw (ro)
Conditions:
Type Status
Initialized False
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-trqgw:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 6m12s default-scheduler Successfully assigned default/myapp-pod to node1
Normal Pulling 6m11s kubelet Pulling image "busybox"
Normal Pulled 5m46s kubelet Successfully pulled image "busybox" in 24.671646739s
Normal Created 5m46s kubelet Created container init-myservice
Normal Started 5m46s kubelet Started container init-myservice

此时正在启动init-myservice,由于我们还没没有创建myservice,所以init容器就一直在重启,我们看一下日志

[root@master ~]# kubectl logs myapp-pod -c init-myservice
Server: 10.96.0.10
Address: 10.96.0.10:53 ** server can't find myservice.default.svc.cluster.local: NXDOMAIN *** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer waiting from myservice
Server: 10.96.0.10
Address: 10.96.0.10:53 ** server can't find myservice.default.svc.cluster.local: NXDOMAIN *** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer waiting from myservice
Server: 10.96.0.10
Address: 10.96.0.10:53 ** server can't find myservice.default.svc.cluster.local: NXDOMAIN *** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer waiting from myservice
Server: 10.96.0.10
Address: 10.96.0.10:53 ** server can't find myservice.default.svc.cluster.local: NXDOMAIN *** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer
*** Can't find myservice.default.svc.cluster.local: No answer
*** Can't find myservice.svc.cluster.local: No answer
*** Can't find myservice.cluster.local: No answer
*** Can't find myservice.localdomain: No answer waiting from myservice

通过日志发现myservice没有启动,所以init-myservice一直在重启,我们再将myservice创建启动后再看

[root@master ~]# cat myservice.yml
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
[root@master ~]# kubectl create -f myservice.yml
service/myservice created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 22m
nginx-6799fc88d8-648cn 1/1 Running 0 49d

此时发现STATUS变成了 Init:1/2 ,说明init-myservice初始化已经完成,我们再创建mydb启动看一下

[root@master ~]# cat mydb.yml
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
[root@master ~]# kubectl create -f mydb.yml
service/mydb created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 PodInitializing 0 29m
nginx-6799fc88d8-648cn 1/1 Running 0 49d

这次init容器都已经初始化完成并正在启动

[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 32m
nginx-6799fc88d8-648cn 1/1 Running 0 49d

init初始化完成并启动容器成功

init初始化特殊说明:

在pod的启动过程中,init容器会按顺序在网络和数据卷启动之后启动,每个容器启动必须在上个容器成功退出后执行。

如果pod重启,那init容器必须重新执行

对init容器的spec修改被限制在image字段,修改其他字段不会生效,更改init容器的image字段,等于重启该pod。

探针

为什么要有探针,因为探针可以探测pod当中的容器是否正常运行,我们知道容器启动,业务程序未必正常,因此,我们可以用livenessProbe探针来探测业务是否正常,而对于我们新建的pod如果不做就绪性探测,会被前端的service立刻关联,这样有可能导致部分客户端无法正常访问,所欲对于k8s探针主要分为两种:

  • 一种为存活性探测(livenessProbe)
  • 一种为就绪性探测(readinessProbe)
探针是由kubelet对容器执行的定期诊断,有三种类型的处理程序:

1、ExecAction:在容器内执行指定命令,如果命令退出时返回码为0则认为诊断成功。

2、TCPsocketAction:对执定端口上的容器的IP地址进行tcp检查,如果端口打开则认为是诊断成功的。

3、HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP get请求。如果响应的状态码大于200且小于400,则被诊断认为是成功的。

每次探测都将获得以下三种结果之一:

Success(成功): 容器通过了诊断。

Failuer(失败):  容器未通过诊断。

Unknown(未知):诊断失败,因此不会采取任何行动。

livenessProbe:指容器是否正在运行。如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响。

例1:ExecAction

[root@master ~]# cat livenessprobe-exec.yaml
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe-pod
namespace: default
labels:
app: liveness
spec:
containers:
- name: livenessprobe-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","touch /tmp/test.txt;sleep 20; rm -rf /tmp/test.txt;sleep 3600"]
livenessProbe:
exec:
command: ["test","-e","/tmp/test.txt"]
initialDelaySeconds: 2
periodSeconds: 2
failureThreshold: 3 验证:可以看到由于文件被删除已经crash了,并且重启了6次
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
livenessprobe-pod 0/1 CrashLoopBackOff 6 10m

例2:HttpGetAction

[root@master ~]# cat livenessprobe-gethttp.yaml
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe-gethttp-pod
namespace: default
labels:
app: liveness-gethttp
spec:
containers:
- name: livenessprobe-gethttp-container
image: nginx
imagePullPolicy: IfNotPresent
livenessProbe:
initialDelaySeconds: 2
periodSeconds: 2
failureThreshold: 3
httpGet:
port: 80
path: /index.html
容器跑起来之后删除/usr/share/nginx/html/index.html文件,然后稍等片刻


验证:可以看到容器被重启了一次然后就一直正常运行
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
livenessprobe-gethttp-pod 1/1 Running 1 14m

readinessProbe:指示容器是否准备好请求服务,如果就绪探测失败,端点控制器将从pod匹配的所有service的端点中删除该pod的ip地址。

 
[root@master ~]# cat readinessprobe-gethttp.yaml
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe-gethttp-pod
namespace: default
labels:
app: liveness-gethttp
spec:
containers:
- name: livenessprobe-gethttp-container
image: nginx
imagePullPolicy: IfNotPresent
readinessProbe:
initialDelaySeconds: 2
periodSeconds: 2
failureThreshold: 3
httpGet:
port: 80
path: /index.html 验证:
1.连入容器删除index.html文件
[root@master ~]# kubectl exec -it livenessprobe-gethttp-pod -- /bin/bash
root@livenessprobe-gethttp-pod:/# cd /usr/share/nginx/html/
root@livenessprobe-gethttp-pod:/usr/share/nginx/html# ls
50x.html index.html
root@livenessprobe-gethttp-pod:/usr/share/nginx/html# rm -rf index.html
root@livenessprobe-gethttp-pod:/usr/share/nginx/html# exit
2.查看pod状态
[root@master ~]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
livenessprobe-gethttp-pod 1/1 Running 0 6s 10.244.1.38 node1 <none> <none>
livenessprobe-gethttp-pod 0/1 Running 0 24s 10.244.1.38 node1 <none> <none>
3.随后我们在在容器里创建出index.html文件,然后在观察pod
[root@master ~]# kubectl get pods -o wide -w
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
livenessprobe-gethttp-pod 1/1 Running 0 6s 10.244.1.38 node1 <none> <none>
livenessprobe-gethttp-pod 0/1 Running 0 24s 10.244.1.38 node1 <none> <none>
livenessprobe-gethttp-pod 1/1 Running 0 2m48s 10.244.1.38 node1 <none> <none>

pod的终止过程

1. 用户向apiserver发送删除pod对象的命令

2. apiserver中的pod对象信息会随着时间的推移而更新,在宽限期内(默认是30s),pod被视为dead

3. 将pod标记为terminating(正在删除)状态

4. kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程

5. 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除

6. 如果当前pod对象定义了 preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行

7. pod对象中的容器进程收到停止信号

8. 宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号

9. kubelet请求apiserver将此pod资源的宽限期设置为0,从而完成删除操作,此时pod对于用户已不可见

最新文章

  1. jquery mobile 问问多多
  2. Eclipse部署项目的原理简介eclipse,wtpwebapps,tomcat
  3. :before :after
  4. Hosting socket.io WebSocket apps in IIS using iisnode
  5. 实现easyui datagrid在没有数据时显示相关提示内容
  6. spring读取prperties配置文件(1)
  7. CoreProfiler/NanoProfiler
  8. Nova 无法向虚机注入密钥
  9. EasyList China国内镜像
  10. 【Time系列五】个性时钟与秒表升级版
  11. 初码-Azure系列-迁移PHP应用至Azure的一些实践记录和思考
  12. MongoDB自学(4)
  13. Linux keepalived+lvs实现高可用负载均衡
  14. Mac_Sublime Text3(mac)一些插件和快捷键
  15. sqlserver操作geography方法
  16. Python中使用operator模块实现对象的多级排序
  17. SQL的六种约束
  18. 21、bootstrap框架
  19. saltstack 初始化LINUX系统
  20. 03--css形状--css揭秘

热门文章

  1. MongoDB从入门到实战之MongoDB快速入门
  2. Redis数据结构与对象
  3. 分享一个项目中在用的图片处理工具类(图片缩放,旋转,画布格式,字节,image,bitmap转换等)
  4. 一文详解RocketMQ的存储模型
  5. elasticsearch实现简单的脚本排序(script sort)
  6. 字节输出流的续写和换行-字节输入流_inputS Stream类
  7. docker搭建maven私服(nexus3),整合springboot上传下载依赖
  8. Linux密钥认证
  9. ChatGPT:让程序开发更轻松
  10. 重定向Kubernetes pod中的tcpdump输出