一、概述
1、当一个 pod 被创建的时候,会启动第一个容器 pause。
作用:挂载可能存在的存储卷,初始化网络栈,后来僵尸进程的杀死。维护。
2、pause 容器启动后,就会启动另一个部分,不是mainC,而是 initC(初始化容器,initC>=0)
initC初始化容器的特性:
- 线性启动
阻塞特性,前一个 initC-1 必须退出,后面的 initC-2 才会运行。执行退出命令的返回码为 0,代表成功退出。如果 initC 启动过程中失败,出现错误,那么 pause 会重新开始创建 initC-1,initC-2,initC-3 等等。只有所有 initC 全部成功启动退出,才会继续往下运行。 - 独立于应用容器
Init 容器可以有自己的独立镜像,这与应用容器使用的镜像可以完全不同。因此,它们具有其特殊的依赖和工具,不会影响应用容器的镜像构成。 - 运行到完成
Init 容器必须在终止前运行到完成。它们不是用来启动长期运行的进程的。一旦它们成功执行了启动命令,它们就会终止。 - 重新启动策略
如果 Init 容器失败,Kubernetes 默认的重新启动策略是 'Always',它会一直重试直到容器成功为止。这与应用容器的启动失败策略是独立的。
二、init容器
2.1、概述
Pod 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 Init 容器。
Init 容器与普通的容器非常像,除了如下两点:
1、Init 容器总是运行到成功完成为止。
2、每个 Init 容器都必须在下一个 Init 容器启动之前成功完成。
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 为 Never,它不会重新启动。
2.2、init容器作用
因为 Init 容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:
1、可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
2、应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
3、Init 容器使用 Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用程序容器则不能。
4、它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。
2.3、InitC 容器示例
initC-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.35.0
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.35.0
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.35.0
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
操作
kubectl apply -f initC-pod.yaml
kubectl get pod
kubectl describe pod myapp-pod
#因为这里无法解析myservice的dns地址,所以才会报错
kubectl logs myapp-pod -c init-myservice
kubectl create svc clusterip myservice --tcp=80:80
kubectl get svc
#这里只加载好一个是因为,只解析了myservice的DNS,找不到mydb的DNS,所以无法加载
kubectl get pod
kubectl create svc clusterip mydb --tcp=80:80
#稍等一会再次查看,就会加载完成
kubectl get pod
三、容器探针
3.1、探针概述
探针是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 Handler。有三种类型的处理程序:
ExecAction
在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。TCPSocketAction
对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。HTTPGetAction
对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的
3.2、探针类型
K8s 中存在两种类型的探针:liveness probe
和 readiness probe
。
- livenessProbe:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为 Success。
- readinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。
四、liveness probe(存活探针)
用于判断容器是否存活,即 Pod 是否为 running 状态,如果 LivenessProbe 探针探测到容 器不健康,则 kubelet 将 kill 掉容器,并根据容器的重启策略是否重启。如果一个容器不包含 LivenessProbe 探针,则 Kubelet 认为容器的LivenessProbe 探针的返回值永远成功。有时应用程序可能因为某些原因(后端服务故障等)导致暂时无法对外提供服务,但应用软件没有终止,导致 K8S 无法隔离有故障的 pod,调用者可能会访问到有故障的 pod,导致业务不稳定。K8S 提供 livenessProbe 来检测应用程序是否正常运行,并且对相应状况进行相应的补救措施。
五、readiness probe(就绪探针)
用于判断容器是否启动完成,即容器的 Ready 是否为 True,可以接收请求,如果 ReadinessProbe 探测失败,则容器的 Ready 将为 False,控制器将此 Pod 的 Endpoint 从对 应的 service 的 Endpoint 列表中移除,从此不再将任何请求调度此 Pod 上,直到下次探测成功。通过使用 Readiness 探针,Kubernetes 能够等待应用程序完全启动,然后才允许服务将流量发送到新副本。
比如使用 tomcat 的应用程序来说,并不是简单地说 tomcat 启动成功就可以对外提供服务的,还需要等待 spring 容器初始化,数据库连接没连上等等。对于 spring boot 应用,默认的 actuator 带有 /health 接口,可以用来进行启动成功的判断。
六、每类探针都支持三种探测方法:
exec
通过执行命令来检查服务是否正常,针对复杂检测或无 HTTP 接口的服务,命令返回值为 0 则表示容器健康。httpGet
通过发送 http 请求检查服务是否正常,返回 200-399 状态码则表明容器健康。tcpSocket
通过容器的 IP 和 Port 执行 TCP 检查,如果能够建立 TCP 连接,则表明容器健康。
七、探针探测的结果
Success
Container 通过了检查。Failure
Container 未通过检查。Unknown
未能执行检查,因此不采取任何措施。
八、Pod 重启策略:
Always
总是重启OnFailure
如果失败就重启Never
永远不重启
七、示例
7.1、readinessProbe-就绪检测示例
readiness-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
labels:
app: myapp
env: test
spec:
containers:
- name: readiness-httpget-container
image: nginx:latest
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1 #延迟的间隔是一秒
periodSeconds: 3 #检测的间隔时间是3秒
timeoutSeconds: 3 #超时时间是3秒
操作
kubectl create -f readiness-pod.yaml
#未就绪状态,因为请求不到index1.html文件
kubectl get pod
# 进入 pod 容器
kubectl exec -it readiness-httpget-pod -- /bin/sh
#pod中添加index1.html文件
cd /usr/share/nginx/html/
echo "123" > index1.html
exit
#就绪状态,可以正常对外提供访问
kubectl get pod
7.2、livenessProbe-存活检测示例
livenessProbe-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
restartPolicy: Never
containers:
- name: liveness-exec-container
image: busybox:1.35.0
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 #检测的间隔时间是3秒
timeoutSeconds: 3 #超时时间是3秒
操作
kubectl apply -f livenessProbe-pod.yaml
kubectl get pod
#再次查看,已处于error状态。
#文件被删除,存活探测失败
kubectl get pod
7.3、livenessProbe-tcp--检测端口模板
apiVersion: v1
kind: Pod
metadata:
name: probe-tcp
spec:
containers:
- name: nginx
image: nginx:latest
livenessProbe: #存活探测
initialDelaySeconds: 5 #初始化间隔时间时5秒
timeoutSeconds: 1 #超时时间是1秒
periodSeconds: 3 #检测间隔是3秒
tcpSocket:
port: 80 #检测的端口是80
说明:这种方式不太好,检测端口是否存在,不代表服务能正常响应。
7.4、其他示例
apiVersion: v1
kind: Pod
metadata:
name: goproxy
labels:
app: goproxy
spec:
containers:
- name: goproxy
image: k8s.gcr.io/goproxy:0.1
ports:
- containerPort: 8080
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
探针(Probe) 有许多可选字段,可以用来更加精确的控制 Liveness 和 Readiness 两种探针的行为。这些参数包括:
initialDelaySeconds
容器启动后第一次执行探测是需要等待多少秒。periodSeconds
执行探测的频率。默认是 10 秒,最小 1 秒。timeoutSeconds
探测超时时间。默认 1 秒,最小 1 秒。successThreshold
探测失败后,最少连续探测成功多少次才被认定为成功。默认是 1。对于 liveness 必须是 1。最小值是 1。failureThreshold
探测成功后,最少连续探测失败多少次才被认定为失败。默认是 3。最小值是 1。
八、钩子
8.1、概述
Pod hook(钩子)是由 Kubernetes 管理的 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为 Pod 中的所有容器都配置 hook。
Hook 的类型包括两种:
exec
:执行一段命令。HTTP
:发送 HTTP 请求。
启动后钩子可以编译软件,挂载存储。关闭前钩子可以保存文件,解除存储。
8.2、yaml模板
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx:latest
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 preStop handler > /usr/share/message"]
8.3、示例
lifecycle-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx:latest
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 preStop handler > /usr/share/message"]
操作
kubectl apply -f lifecycle-pod.yaml
kubectl get pod
# 进入容器
kubectl exec -it lifecycle-demo -- /bin/sh
#pod中执行
while 2>1;do cat /usr/share/message;done
#再开一个终端删除pod,然后观察原终端的返回信息
kubectl delete pod --all
评论