上图主要描述在容器环境初始化完成之后,pod创建到退出的中间这段过程:
从大的方向上看,pod生命周期分两个阶段:
在 Kubernetes 中,每个 Pod 都可以包括多个容器。pause 容器是 Kubernetes 系统自带的一个容器,它是每个 Pod 中必须存在的一个容器。pause 容器没有实际的业务逻辑,它的作用是作为所有其他容器的父进程。当 Pod 中的其他容器启动时,它们会与 pause 容器共享网络和存储空间。pause 容器会先启动并进入等待状态,等待其他容器加入进来。整个 Pod 中的所有容器都共享同一个 Linux namespace 和同一个网络栈,而 pause 容器则提供了这个 namespace 和网络栈。这种设计在 Kubernetes 中被称为 Pod 共享模型。
对于Init Container来说,一个pod中可以定义多个初始化容器,他们必须是串行执行,只有当所有的初始化容器执行完后,对应的主容器才会启动
如上图所示,会按顺序把1、2、3的InitC都执行完成之后,才进入Main Container阶段
Main Container生命周期又分为三个阶段:
对于容器的健康状态检查和就绪状态检查,我们也可以定义开始检查的延迟时长;因为有些容器存在容器显示running状态,但内部程序还没有初始化,如果立即做健康状态检查,可能存在健康状态为不健康,从而导致容器重启的状况;
Pending(挂起):Pod已被创建,但还未被调度至任何节点上。
Running(运行中):Pod已经被调度至节点上,并且Pod中的所有容器都在运行中。
Succeeded(成功):Pod中的所有容器都已经成功退出,并且不会再次启动。
Failed(失败):Pod中的一个或多个容器已经失败并且已经退出。
Unknown(未知):Pod的状态无法被获取,通常是由于控制器无法连接到Pod所在节点。
除了Pod的相位,还有以下几种状态值,可以通过kubectl get pods查看以下的状态:
ContainerCreating(容器创建):Pod中的一个或多个容器正在创建中。
PodInitializing(pod正在初始化):Pod中的一个或多个init容器正在初始化中。
Terminating(停止):Pod正在被删除,但是Pod中的容器仍在运行中。
Running(运行中):所有容器都已经成功启动并正在运行中。
Succeeded(成功):所有容器都已经成功退出,并且不会再次启动。
Failed(失败):Pod中存在至少一个容器已经失败,并且容器无法重启。
Unknown(未知):由于某种原因,Pod的状态无法被获取。
在Kubernetes中,Init Container是一种特殊类型的容器,它在Pod中的其他容器启动之前运行。Init Container的目的是在Pod中的其他容器启动之前执行一些预处理任务,例如初始化某些数据、检查依赖项是否可用等。Init Container和普通容器一样,可以使用Docker镜像,并且可以使用Kubernetes提供的各种资源和功能。
在一个Pod中可以定义多个Init Container,它们将按照定义的顺序依次运行。如果任何一个Init Container失败,Kubernetes将立即停止Pod中的所有容器,并将整个Pod标记为失败。
注意:Init Container和普通容器不同,它们的生命周期是独立的,即Init Container的生命周期结束后,Pod中的其他容器才会开始启动。因此,在编写Init Container时,需要确保它们的生命周期不会太长,否则会影响整个Pod的启动速度。
vim init-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp-container
image: busybox:1.32
command: ['sh', '-c', 'echo The app is running && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.32
command: ['sh', '-c','until nslookup myservice; do echo waiting myservice; sleep 2;done;']
- name: init-mydb
image: busybox:1.32
command: ['sh', '-c', 'until nslookup mydb; do echo waiting mydb; sleep 2;done;']
kubectl apply -f init-pod.yaml
[root@master1 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
xiaoyu-pod 0/1 Init:0/2 0 71s
此处补充个小知识点,便是Linux中until的用法。
until跟while类似,都是一个固定循环。
但是until跟while又有不同,则是它们的条件满足不同。
until是直到条件为真时,打破循环。而while是条件为真时一直循环,条件为假时打破循环。
kubectl logs myapp-pod -n default -c init-myservice
vim init-service.yaml
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
[root@master1 ~]# kubectl apply -f init-service.yaml
service/myservice created
[root@master1 test]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.10.0.1 <none> 443/TCP 350d
myservice ClusterIP 10.10.42.207 <none> 80/TCP 43s
[root@master1 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 9m39s ----可以看的出来2个init c 已经有一个恢复正常了。
vim init-db.yaml
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
[root@master1 test]# kubectl apply -f init-db.yaml
service/mydb created
[root@master1 test]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.10.0.1 <none> 443/TCP 350d
mydb ClusterIP 10.10.102.245 <none> 80/TCP 70s
myservice ClusterIP 10.10.42.207 <none> 80/TCP 12m
[root@master1 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 16m ----可以看的出来pod已经变为Running
容器探针是用于监测容器内部状态的一种机制,可以帮助容器管理器(如 Kubernetes)了解容器内部是否正常运行,并在容器出现异常时采取适当的措施。容器探针包括两种类型:存活探针(LivenessProbe)和就绪探针(readinessProbe)。
存活探针(LivenessProbe):检测容器是否正在运行,如果检测到容器不可用,则kubelet会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为Success。
就绪探针(readinessProbe):指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与pod匹配的所有Service的端点中删除该pod的IP地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success。
容器探针是由kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler。有三种类型的处理程序:
1. ExecAction:在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
2. TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查。如果端口打开,则诊断被认为是成功的。
3. HTTPGetAction:对指定的端口和路径上的容器的IP地址执行HTTP Get请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
每次探测都将获得以下三种结果之一:
1. 成功:容器通过了诊断。
2. 失败:容器未通过诊断。
3. 未知:诊断失败,因此不会采取任何行动。
[root@master1 test]# vim readinessProbe-httget.yaml
apiVersion: v1 #API版本号,例如,Deployment资源的API版本是apps/v1,而Service资源的API版本是v1
kind: Pod #类型/控制器
metadata: #这个对象包含了一些元数据,例如 Pod 的名称、标签、注释等等
name: readiness-httpget-pod #pod名称
namespace: default #指定pod在哪个命名空间创建
spec: # 这个对象包含了 Pod 的规格,例如 Pod 中包含的容器、容器的镜像、容器的端口号、容器的环境变量、资源限制等等。
containers:
- name: readiness-httpget-container #容器名称
image: nginx:latest #指定容器镜像
imagePullPolicy: IfNotPresent #指定容器策略为IfNotPresent,只有在本地不存在该镜像时才从镜像仓库拉取,否则使用本地缓存的镜像。
readinessProbe: #定义了就绪探针的配置选项
httpGet: #就绪探针使用 httpGet 来检查容器的状态
port: 80 #检查的端口为 http
path: /index1.html #检查路径为 /index1.html
initialDelaySeconds: 1 #表示容器启动后1秒开始进行探测
periodSeconds: 3 #表示每隔3秒进行一次探测
##进入容器查看/usr/share/nginx/html/是否有index1.html
[root@master1 test]# kubectl exec readiness-httpget-pod -it /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@readiness-httpget-pod:/# cd /usr/share/nginx/html/
root@readiness-httpget-pod:/usr/share/nginx/html# ls
50x.html index.html ---可以看的出来没有index1.html文件
root@readiness-httpget-pod:/usr/share/nginx/html# echo "123" > index1.html
root@readiness-httpget-pod:/usr/share/nginx/html# exit
exit
[root@master1 test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget-pod 1/1 Running 0 5m8s
---可以看得出来问题解决了。
vim livenessProbe-exec.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: nginx:latest
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
kubectl apply -f livenessProbe-exec.yaml
[root@master1 test]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
liveness-exec-pod 1/1 Running 0 2m43s
readiness-httpget-pod 1/1 Running 0 27m
liveness-exec-pod 1/1 Running 1 2m58s
liveness-exec-pod 1/1 Running 2 4m36s
vim livenessProbe-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
#表示存活探针的超时时间是 10 秒。
#如果在这个时间内没有收到来自容器的响应,就会认为存活探针失败,并且 Kubernetes 将会根据容器的重启策略进行容器的重启。
#如果这个值设置得太小,可能会导致存活探针误判为失败,从而触发不必要的容器重启;而如果设置得太大,则可能会延迟容器故障的检测和处理。
#因此,一般需要根据具体的应用情况进行调整。
timeoutSeconds: 10
[root@master1 test]# kubectl apply -f livenessProbe-httpget.yaml
pod/liveness-httpget-pod created
[root@master1 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
liveness-httpget-pod 1/1 Running 0 7s
[root@master1 test]# kubectl exec liveness-httpget-pod -it /bin/bash
root@liveness-httpget-pod:/# cd /usr/share/nginx/html/
root@liveness-httpget-pod:/usr/share/nginx/html# ls
50x.html index.html
root@liveness-httpget-pod:/usr/share/nginx/html# rm -rf index.html --删除index.html
root@liveness-httpget-pod:/usr/share/nginx/html# exit
exit
[root@master1 test]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
liveness-httpget-pod 1/1 Running 0 6m23s
liveness-httpget-pod 1/1 Running 1 6m24s --可以看的出来删除掉index.html文件后触发存活探针条件重启。
vim livenessProbe-tcp.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcp-pod
namespace: default
spec:
containers:
- name: liveness-tcp-container
image: nginx:latest
imagePullPolicy: IfNotPresent
livenessProbe:
tcpSocket:
prot: 8080
initialDelaySeconds: 5
periodSeconds: 3
timeoutSeonds: 1
[root@master1 test]# kubectl apply -f livenessProbe-tcp.yaml
pod/liveness-tcp-pod created
[root@master1 test]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
liveness-tcp-pod 1/1 Running 0 11s
liveness-tcp-pod 1/1 Running 1 14s
liveness-tcp-pod 1/1 Running 2 26s
[root@master1 test]# vim init-start.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
namespace: default
spec:
containers:
- name: lifecycle-demo-container
image: nginx:latest
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo Hello from the postStart handler >>/usr/share/message"]
preStop:
exec:
command: ["/bin/sh","-c","echo Hello from the poststop handler >> /usr/share/message"]
[root@master1 test]# kubectl exec lifecycle-demo -it /bin/bash
root@lifecycle-demo:/# cat /usr/share/message
Hello from the postStart handler