kubernetes 核心技术-init容器&探针&钩子

kubernetes 核心技术-init容器&探针&钩子

一、概述


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 probereadiness 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

评论

暂无

添加新评论