K8s: 在Pod里面创建init容器与健康检查

发布于:2024-04-27 ⋅ 阅读:(29) ⋅ 点赞:(0)

pod中init容器的创建


1 )概述

  • 每个 Pod 中可以包含多个容器, 应用运行在这些容器里面
  • 同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器
  • Init 容器与普通的容器非常像,除了如下两点
    • a. 它们总是运行到完成。
    • b. 每个都必须在下一个启动之前成功完成
  • 如果 Pod 的 Init 容器失败,K8s 会不断地重启该 Pod,直到 Init 容器成功为止
  • 然而,如果 Pod 对应的 restartPolicy 值为 Never,K8s 不会重新启动 Pod
  • 与普通容器的不同之处如下
    • a. Init 容器支持应用容器的全部属性和特性,包括资源限制、数据卷和安全设置。
    • b. 同时 Init 容器不支持 lifecycle、livenessProbe、readinessProbe 和 startupProbe, 因为它们必须在 Pod 就绪之前运行完成

2 )Init Pod 的创建

  • 下面的例子定义了一个有 init 容器和一个业务容器

  • 创建 init-pod.yaml

    apiVersion: v1
    kind: Pod
    metadata:
     name: init-pod-demo
     labels:
       name: init-pod
    spec:
     containers:
     - name: busybox-container
       image: busybox:latest
       command: ['sh', '-c', 'date && sleep 3600']
       resources:
         limits:
           memory: "128Mi"
           cpu: "500m"
       ports:
       - containerPort: 80
     initContainers:
     - name: init-container
       image: busybox:latest
       command: ['sh', '-c', "date && sleep 10"]
    
  • $ kubectl apply -f init-pod.yaml 创建 pod

    pod/init-pod-demo created
    
  • $ kubectl get po -w 查看pod的创建过程

    init-pod-demo    0/1     Init:0/1          0          16s
    init-pod-demo    0/1     PodInitializing   0          17s
    init-pod-demo    1/1     Running           0          27s
    
  • $ kubectl logs init-pod-demo 查看 pod 日志

    Thu Apr 18 07:31:59 UTC 2024
    
  • $ kubectl logs init-pod-demo -c init-container 进入init容器查看日志

    Thu Apr 18 07:31:39 UTC 2024
    
  • 从上面一系列输出中可以看到,在 PodInitializing 和 Running 两个阶段用了 10s

    • 这个对应着在init容器中运行的脚本中打印时间后,睡了 10s
  • 同时pod中和容器中打印的时间相差 20s,这两个相差的时间一定是 大于 睡了的10s的

  • 也就是说,业务容器运行之前必须启动完成init容器

pod的健康检查


1 )探针的作用

  • 探针 是由 kubelet 对容器执行的定期诊断
  • 要执行诊断,kubelet 调用由容器实现的 Handler (处理程序),有三种类型的处理程序:
    • ExecAction
      • 在容器内执行指定命令
      • 如果命令退出时返回码为 0 则认为诊断成功
    • TCPSocketAction
      • 对容器的 IP 地址上的指定端口执行 TCP 检查
      • 如果端口打开,则诊断被认为是成功的
    • HTTPGetAction
      • 对容器的 IP 地址上指定端口和路径执行 HTTP Get 请求
      • 如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的
  • 每次探测都将获得以下三种结果之一
    • Success(成功):容器通过了诊断
    • Failure(失败):容器未通过诊断
    • Unknown(未知):诊断失败,因此不会采取任何行动

2 ) 使用启动探针

  • 对于所包含的容器需要较长时间才能启动就绪的 Pod 而言,启动探针是有用的
  • 你不再需要配置一个较长的存活态探测时间间隔,只需要设置另一个独立的配置选定
  • 对启动期间的容器执行探测,从而允许使用远远超出存活态时间间隔所允许的时长
  • 如果你的容器启动时间通常超出 initialDelaySeconds + failureThreshold × periodSeconds 总值
  • 你应该设置一个启动探测,对存活态探针所使用的同一端点执行检查
  • periodSeconds 的默认值是 30 秒
  • 你应该将其 failureThreshold 设置得足够高, 以便容器有充足的时间完成启动
  • 并且避免更改存活态探针所使用的默认值, 这一设置有助于减少死锁状况的发生

3 ) 创建一个 HTTP 请求的探针

  • 创建一个 liveness.yaml 文件

    apiVersion: v1
    kind: Pod
    metadata:
      name: liveness-http
      labels:
        test: liveness
    spec:
      containers:
      - name: liveness
        image: mirrorgooglecontainers/liveness
        args:
        - /server
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
            httpHeaders:
            - name: Custom-Header
              value: Awesome
          initialDelaySeconds: 3
          periodSeconds: 3
    
  • 这是官方曾经提供的一个案例

  • 在这个配置文件中,可以看到 Pod 也只有一个容器

  • periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测

  • initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒

  • kubelet会向容器内运行的服务(服务会监听 8080 端口)发送一个 HTTP GET 请求来执行探测

  • 如果服务器上 /healthz 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的

  • 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并且重新启动它

  • 任何大于或等于 200 并且小于 400 的返回代码标示成功,其它返回代码都标示失败。

  • 可以有容器内运行服务的源码 server.go

    http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    	 duration := time.Now().Sub(started)
    	 if duration.Seconds() > 10 {
    		 w.WriteHeader(500)
    		 w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
    	 } else {
    		 w.WriteHeader(200)
    		 w.Write([]byte("ok"))
    	 }
    })
    
  • 容器存活的最开始 10 秒中, /healthz 处理程序返回一个 200 的状态码

  • 之后处理程序返回 500 的状态码

  • $ kubectl apply -f liveness.yaml 创建 pod

    pod/liveness-http created
    
  • $ kubectl get po -w | grep live 监控 pod

    liveness-http    0/1     ContainerCreating   0          2s
    liveness-http    1/1     Running             0          5s
    liveness-http    1/1     Running             1 (4s ago)   26s
    liveness-http    1/1     Running             2 (3s ago)   46s
    liveness-http    1/1     Running             3 (3s ago)   67s
    liveness-http    1/1     Running             4 (3s ago)   88s
    liveness-http    0/1     CrashLoopBackOff    4 (0s ago)   106s
    liveness-http    1/1     Running             5 (56s ago)   2m42s
    liveness-http    0/1     CrashLoopBackOff    5 (0s ago)    2m58s
    liveness-http    1/1     Running             6 (95s ago)   4m33s
    liveness-http    0/1     CrashLoopBackOff    6 (0s ago)    4m52s
    
    • 可见一直在重启
  • $ kubectl describe pod liveness-http 查看 pod 详细问题

    Name:         liveness-http
    Namespace:    default
    Priority:     0
    Node:         node1.k8s/10.211.55.11
    Start Time:   Thu, 18 Apr 2024 16:45:57 +0800
    Labels:       test=liveness
    Annotations:  <none>
    Status:       Running
    IP:           10.244.1.27
    IPs:
      IP:  10.244.1.27
    Containers:
      liveness:
        Container ID:  docker://0bde3a8c2ab79d2fd389659354771da10edbdfd29e3bb3d5c87fcbcb44f918b1
        Image:         mirrorgooglecontainers/liveness
        Image ID:      docker-pullable://mirrorgooglecontainers/liveness@sha256:854458862be990608ad916980f9d3c552ac978ff70ceb0f90508858ec8fc4a62
        Port:          <none>
        Host Port:     <none>
        Args:
          /server
        State:          Waiting
          Reason:       CrashLoopBackOff
        Last State:     Terminated
          Reason:       Error
          Exit Code:    2
          Started:      Thu, 18 Apr 2024 16:47:19 +0800
          Finished:     Thu, 18 Apr 2024 16:47:36 +0800
        Ready:          False
        Restart Count:  4
        Liveness:       http-get http://:8080/healthz delay=3s timeout=1s period=3s #success=1 #failure=3
        Environment:    <none>
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-nv6lw (ro)
    Conditions:
      Type              Status
      Initialized       True
      Ready             False
      ContainersReady   False
      PodScheduled      True
    Volumes:
      kube-api-access-nv6lw:
        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  114s                default-scheduler  Successfully assigned default/liveness-http to node1.k8s
      Normal   Pulled     111s                kubelet            Successfully pulled image "mirrorgooglecontainers/liveness" in 2.298827654s
      Normal   Pulled     92s                 kubelet            Successfully pulled image "mirrorgooglecontainers/liveness" in 1.281083837s
      Normal   Created    74s (x3 over 111s)  kubelet            Created container liveness
      Normal   Started    74s (x3 over 111s)  kubelet            Started container liveness
      Normal   Pulled     74s                 kubelet            Successfully pulled image "mirrorgooglecontainers/liveness" in 1.048779521s
      Warning  Unhealthy  58s (x9 over 100s)  kubelet            Liveness probe failed: HTTP probe failed with statuscode: 500
      Normal   Killing    58s (x3 over 94s)   kubelet            Container liveness failed liveness probe, will be restarted
      Normal   Pulling    57s (x4 over 114s)  kubelet            Pulling image "mirrorgooglecontainers/liveness"
    
    • 这里可以看到
      • Liveness probe failed: HTTP probe failed with statuscode: 500
      • Container liveness failed liveness probe, will be restarted
    • 返回 500 之后,进行了重启
  • 这样,通过探针的健康检查,可以判断pod的运行健康状态