【k8s系列】驾驭容器化未来:Kubernetes Pod的全面解析与简单实践

一、前言

在当今快速发展的云计算和容器化技术领域,Kubernetes已经崭露头角,成为自动化容器操作的开源平台。在这个生态系统中,Pod作为Kubernetes的最小和最简单的单元,扮演着至关重要的角色。Pod不仅是容器的集合,更是资源共享和协同工作的基础。作为初探容器化技术的爱好者,笔者也是在k8s学习过程中根据自己的理解分享一下这块的具体内容,希望对感兴趣的小伙伴有所帮助~

二、Pod的基本概念

Pod是Kubernetes中的基本构建模块,它封装了一个或多个容器,这些容器共享存储、网络和命名空间,使用 localhost 在不同的端口上相互连接。每个Pod都有一个唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP,使得其中的容器可以无缝通信。Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。咱们也可以将 Pod 视为一个可以将一个或多个容器放在一起的盒子。

Pod的设计理念是促进紧密耦合的容器集合,其中包含一个或多个应用容器,这些容器共同构成一个逻辑上的"主机"。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。

Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP的直接通讯,采用虚拟二层网络技术来实现,一个Pod里的容器与另外主机上的Pod容器能够直接通信。

Pod的特性

  1. 共享网络:Pod内的所有容器共享同一个网络命名空间,这意味着它们可以通过localhost相互通信,简化了容器间的通信复杂性。

  2. 共享存储:Pod可以定义共享存储卷,使得多个容器可以访问和共享相同的数据,这对于需要协同工作的应用尤为重要。

  3. 生命周期管理:Pod的生命周期由Kubernetes管理,包括创建、运行、重启和删除等状态。Kubernetes通过控制器(如Deployment、StatefulSet)来管理Pod的副本和状态。

Pod的创建方式

目前所知的有四种方式创建 Pod:

1、kubectl 命令式命令方式: 主要用于学习和测试目的。命令式命令有其自身的局限性。 比如:

bash 复制代码
kubectl run web-server-pod \
  --image=nginx:1.14.2 \
  --restart=Never \
  --port=80 \
  --labels=app=web-server,environment=production \
  --annotations description="This pod runs the web server"

这个熟悉docker的应该很熟悉。

2、声明式方式:使用 YAML 清单。在处理项目时,YAML 清单用于部署 Pod。这里包括通过yaml文件直接创建Pod,比如:

bash 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

但是实际上,Pod 通常不是直接创建的,而是使用工作负载资源创建的。这是因为 Pod 被设计成了相对临时性的、用后即抛的一次性实体。 当 Pod 间接地由控制器创建时,它被调度在集群中的节点上运行。 Pod 会保持在该节点上运行,直到 Pod 结束执行、Pod 对象被删除、Pod 因资源不足而被驱逐或者节点失效为止。

所以声明式也应用于Deployment 或 Job这类工作负载资源控制器来创建 Pod时需要的yaml文件,比如:

bash 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
        #这里是Pod模版
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

一个YAML文件往往包含Kubernetes Pod对象的组件信息,每个 Kubernetes 对象都有一些通用的参数集,这些值会根据我们正在创建的对象类型而变化。一般包含的参数信息如下:

(1)元数据(Metadata)

  • name:Pod的名称,唯一标识符。

  • namespace:Pod所属的命名空间。

  • labels:键值对标签,用于标识和选择Pod。

  • annotations:非标识性的键值对,用于存储额外的元数据。

(2)规格(Spec)

  • containers

    :Pod中包含的容器列表。

    • name:容器的名称。

    • image:容器使用的镜像。

    • command:容器启动时执行的命令。

    • args:传递给命令的参数。

    • ports

      :容器暴露的端口列表。

      • containerPort:容器端口。

      • protocol:端口协议(TCP或UDP)。

    • env

      :环境变量列表。

      • name:环境变量名称。

      • value:环境变量值。

    • resources

      :资源请求和限制。

      • requests:资源请求(如CPU和内存)。

      • limits:资源限制(如CPU和内存)。

    • volumeMounts

      :挂载到容器中的存储卷。

      • name:存储卷名称。

      • mountPath:挂载路径。

    • livenessProbe:存活探针,用于检查容器是否健康。

    • readinessProbe:就绪探针,用于检查容器是否准备好接收流量。

    • lifecycle:生命周期钩子,定义容器启动和停止时的操作。

  • volumes

    :Pod中定义的存储卷列表。

    • name:存储卷名称。

    • emptyDir:临时存储卷。

    • hostPath:主机路径存储卷。

    • persistentVolumeClaim:持久卷声明。

  • initContainers:初始化容器列表,在主容器启动前执行。

  • restartPolicy:重启策略(Always、OnFailure、Never)。

  • nodeSelector:节点选择器,用于指定Pod调度到特定节点。

  • affinity:亲和性规则,用于更复杂的调度策略。

  • tolerations:容忍度,用于指定Pod可以容忍的污点。

  • imagePullSecrets:用于拉取私有镜像的密钥。

  • securityContext:安全上下文,定义Pod和容器的权限和访问控制。

(3)状态(Status)

  • phase:Pod的当前阶段(Pending、Running、Succeeded、Failed、Unknown)。

  • conditions:Pod的状态条件列表。

  • containerStatuses:容器的状态列表。

  • hostIP:Pod所在节点的IP地址。

  • podIP:Pod的IP地址。

  • startTime:Pod启动时间。

3、使用Helm Charts包管理工具方式,通过Helm Charts可以一键部署复杂应用。 例如:helm install <chart-name>

4、编程式方式:通过编程方式调用Kubernetes API创建Pod。 例如,使用Python客户端:

python 复制代码
from kubernetes import client, config

config.load_kube_config()
v1 = client.CoreV1Api()
pod = client.V1Pod(metadata=client.V1ObjectMeta(name="my-pod"), spec=client.V1PodSpec(containers=[client.V1Container(name="my-container", image="nginx")]))
v1.create_namespaced_pod(namespace="default", body=pod)

相对而言,第二、第三种可能更受欢迎一点。

三、Pod的生命周期

Pod 在 Kubernetes 中就像是一个小团队,里面可以有一个或多个应用容器。这个小团队有自己的生命周期,从"等待"(Pending)开始,如果至少有一个主要容器顺利启动,它就会进入"运行"(Running)状态。之后,如果团队里的容器都顺利完成任务,Pod 就会进入"成功"(Succeeded)状态;如果有容器失败了,Pod 就会进入"失败"(Failed)状态。通常Pod的系统状态包含在PodStatus对象中的phase字段下有如下几种状态:

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

Tips: 当一个 Pod 被删除时,执行一些 kubectl 命令会展示这个 Pod 的状态为 Terminating(终止)。 这个 Terminating 状态并不是 Pod 阶段之一。 Pod 被赋予一个可以体面终止的期限,默认为 30 秒。 我们可以使用 --force 参数来强制终止 Pod。

从 Kubernetes 1.27 开始,除了静态 Pod 和没有 Finalizer 的强制终止 Pod 之外,kubelet 会将已删除的 Pod 转换到终止阶段 (FailedSucceeded 具体取决于 Pod 容器的退出状态),然后再从 API 服务器中删除。

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

(1)Pod的生命期

和单个容器一样,Pod 也是临时的,不是永久的。它们会被创建、分配一个唯一的 ID(UID),然后被安排到一个节点上运行,直到它们完成任务(根据重启策略)或被删除。如果一个节点出现问题,比如死机了,那么在这个节点上的 Pod 也会在一段时间后被计划删除。在 Pod 运行过程中,如果容器出现问题,kubelet 会尝试重启容器来解决问题。Kubernetes 会跟踪 Pod 内部容器的状态,并采取必要的措施让 Pod 恢复健康。

在 Kubernetes 的 API 中,Pod 有两个部分:一个是"规约"部分,描述了 Pod 应该如何运行;另一个是"实际状态"部分,显示了 Pod 当前的运行情况。Pod 的状态还包括了一组"状况"(Conditions),这些状况可以帮助我们了解 Pod 的当前状态。如果需要,我们还可以向 Pod 中添加自定义的"就绪态"信息。

Pod 在它的生命周期中只会被调度一次。将 Pod 分配到特定节点的过程称为"绑定",而选择哪个节点来运行 Pod 的过程称为"调度"。一旦 Pod 被调度并绑定到一个节点上,Kubernetes 就会尝试在这个节点上运行 Pod。Pod 会一直在这个节点上运行,直到 Pod 停止或被终止。如果 Kubernetes 无法在选定的节点上启动 Pod(比如节点在 Pod 启动前崩溃了),那么这个特定的 Pod 将永远不会启动。

我们可以使用"Pod 调度就绪态"来延迟 Pod 的调度,直到所有的调度条件都被满足。比如,我们可能想要创建一组 Pod,但只有当所有 Pod 都被创建完成后,才会开始调度它们。

(2)Pod中的容器状态

Kubernetes 会像跟踪团队的整体状态一样,跟踪每个容器的状态。我们可以通过设置"容器生命周期回调",在容器生命周期的特定时间点触发一些操作。一旦调度器将 Pod 分配给某个节点,kubelet 就会通过容器运行时开始为 Pod 创建容器。容器的状态主要有三种:等待(Waiting)、运行中(Running)和已终止(Terminated)。

要查看 Pod 中容器的状态,我们可以使用 kubectl describe pod <pod 名称> 命令。这个命令的输出会显示 Pod 中每个容器的状态。

每种状态的含义:

  1. Waiting (等待) : 如果容器既不在运行中,也不在已终止状态,那么它就在等待状态。处于等待状态的容器还在进行一些启动所需的操作,比如从镜像仓库拉取镜像,或者应用一些秘密数据。当我们用 kubectl 查询一个包含等待状态容器的 Pod 时,我们会看到一个"原因(Reason)"字段,告诉我们容器为什么在等待。

  2. Running(运行中) : 这个状态表示容器正在正常运行,没有遇到任何问题。如果配置了 postStart 回调,那么这个回调已经执行并且完成了。当我们用 kubectl 查询一个包含运行中状态容器的 Pod 时,我们会看到容器进入运行中的相关信息。

  3. Terminated(已终止) : 处于已终止状态的容器已经开始执行,并且可能正常结束,也可能因为某些原因失败。当我们用 kubectl 查询一个包含已终止状态容器的 Pod 时,我们会看到容器进入这个状态的原因、退出代码,以及容器执行期间的起止时间。

如果容器配置了 preStop 回调,这个回调会在容器进入已终止状态之前执行。

通过这些状态和回调,Kubernetes 能够精细地管理容器的生命周期,确保应用的稳定运行。

(3)Pod中的容器重启策略

Kubernetes 通过在 Pod spec 中定义的 restartPolicy 来管理容器出现故障时的应对措施。这个策略决定了 Kubernetes 如何处理因为错误或其他原因退出的容器。

首先,当容器第一次崩溃时,Kubernetes 会根据 Pod 的"重启策略"立即尝试重新启动它。但如果容器反复崩溃,Kubernetes 会采用一种叫做"指数级回退延迟"的机制。这种机制就像是一个"冷却时间",每次重启失败后,等待的时间会越来越长,这样可以避免快速、重复的重启尝试导致系统过载。

当一个容器陷入崩溃和重启的循环中时,Kubernetes 会进入一个叫做"CrashLoopBackOff"的状态。这个状态表明,对于这个特定的、反复崩溃并重启的容器,"冷却时间"机制正在生效。

如果容器成功运行了一段时间(比如 10 分钟),Kubernetes 会重置这个"冷却时间"机制,把新的崩溃视为第一次崩溃。

在实际操作中,当我们用 kubectl 命令查看或列出 Pod 时,如果看到"CrashLoopBackOff",这意味着 Pod 中的容器无法正常启动,并且陷入了尝试和失败的循环中。

导致"CrashLoopBackOff"的原因可能有很多,比如:

  1. 应用程序本身的错误导致容器退出。

  2. 配置错误,比如环境变量设置不正确或配置文件丢失。

  3. 资源限制,容器可能没有足够的内存或 CPU 来正常启动。

  4. 健康检查失败,如果应用程序没有在预期时间内启动服务。

  5. 容器的存活探针或启动探针返回失败结果。

要找出"CrashLoopBackOff"问题的根本原因,我们可以:

  1. 检查日志:使用 kubectl logs <pod名称> 查看容器的日志,这通常是诊断问题的最直接方法。

  2. 检查事件:使用 kubectl describe pod <pod名称> 查看 Pod 的事件,这可以提供有关配置或资源问题的提示。

  3. 审查配置:确保 Pod 的配置正确无误,包括环境变量和挂载卷,并且所有必需的外部资源都可用。

  4. 检查资源限制:确保容器被分配了足够的 CPU 和内存。有时,增加 Pod 定义中的资源可以解决问题。

  5. 调试应用程序:应用程序代码中可能存在错误或配置不当。在本地或开发环境中运行此容器镜像有助于诊断应用程序的特定问题。

通过这些方法,我们可以更好地理解并解决"CrashLoopBackOff"问题,确保我们的 Pod 能够稳定运行。

Pod的重启策略包括Always、OnFailure和Never,默认值为Always。

  • Always:默认设置。当容器失败时,kubelet 会自动重启该容器,确保它能尽快恢复正常运行。

  • OnFailure:当容器因错误而停止(退出码不为0)时,kubelet 会尝试重启它,这通常用于希望容器在出现错误时自动重试的场景。

  • Never:kubelet 不会尝试重启容器,无论它是如何停止的。这种策略适合于希望容器运行一次并结束的任务。

kubelet重启失效容器的时间间隔以sync-frequency乘以2n来计算,例如1、2、4、8倍等,最长延时5min,并且在成功重启后的10min后重置该时间

Pod的重启策略与控制方式息息相关,当前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通过kubelet管理(静态Pod)。每种控制器对Pod的重启策略要求如下:

  • ReplicationController 和 DaemonSet:需要将重启策略设置为 Always,因为这些控制器需要容器持续运行,以满足服务可用性和容错需求。

  • Job:设置为 OnFailure 或 Never。这个策略确保任务(如批处理作业)在完成或失败后不会重启。

  • Kubelet 直接管理的静态 Pod:即使重启策略被设定为 Never,kubelet 也会尝试在 Pod 失效时重启容器,但它不执行 Pod 级别的健康检查。

四、Pod的基本用法

Kubernetes 集群中的 Pod 主要有两种用法:

  • 运行单个容器的 Pod。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。

  • 运行多个协同工作的容器的 Pod 。 Pod 可以封装由紧密耦合且需要共享资源的多个并置容器组成的应用。 这些位于同一位置的容器构成一个内聚单元。将多个并置、同管的容器组织到一个 Pod 中是一种相对高级的使用场景。 只有在一些场景中,容器之间紧密关联时可以使用这种模式。比如当nginx容器和tomcat容器应用为紧耦合的关系,应该组合成一个整体对外提供服务时,可以这两个容器打包为一个Pod。

这里为了方便咱们以运行单个容器Pod为例进行基本用法说明。比如现在需要创建一个nginx的Pod,我们可以先编写一个YAML配置文件:

bash 复制代码
root@master01:/opt/k8s-study# vi test-pod.yaml 
root@master01:/opt/k8s-study# cat test-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  labels:
    app: test-app
spec:
  containers:
  - name: my-web
    image: nginx:latest
    ports:
    - containerPort: 80

然后使用以下命令创建Pod:

bash 复制代码
root@master01:/opt/k8s-study# kubectl apply -f test-pod.yaml 
pod/test-pod created

创建Pod后,可以使用以下命令查看Pod的状态:

bash 复制代码
root@master01:/opt/k8s-study# kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          31m

此时pod的状态为Pending,然后可以根据pod name查看特定Pod的详细信息:

bash 复制代码
root@master01:/opt/k8s-study# kubectl describe pod test-pod
Name:             test-pod
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01/192.168.1.201
Start Time:       Sun, 25 Aug 2024 21:17:42 +0800
Labels:           app=test-app
Annotations:      <none>
Status:           Running
IP:               10.244.3.11
IPs:
  IP:  10.244.3.11
Containers:
  my-web:
    Container ID:   docker://a1360ae9a522b966abc0ca48e70b1a6b72f81f29a4f3b311ac388499b10dc3d4
    Image:          swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    Image ID:       docker-pullable://swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx@sha256:80550935209dd7f6b2d7e8401b9365837e3edd4b047f5a1a7d393e9f04d34498
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sun, 25 Aug 2024 21:21:03 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-bsv8v (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-bsv8v:
    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               32m                    default-scheduler  Successfully assigned default/test-pod to node01

Pod通常运行在集群内部,无法直接从外部访问。此时需要创建一个Service来暴露Pod:

bash 复制代码
root@master01:/opt/k8s-study# vi test-service.yaml 
root@master01:/opt/k8s-study# cat test-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: test-service
spec:
  selector:
    app: test-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: NodePort

然后使用以下命令创建Service:

bash 复制代码
root@master01:/opt/k8s-study# kubectl apply -f my-service.yaml

查看Service的NodePort:

bash 复制代码
NAME           TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE   SELECTOR
test-service   NodePort   10.1.122.221   <none>        80:31473/TCP   11m   app=test-app

然后在浏览器中访问http://<node-ip>:31473

删除Pod

使用以下命令删除Pod:

bash 复制代码
root@master01:/opt/k8s-study# kubectl delete pod test-pod

或者使用YAML文件删除:

bash 复制代码
root@master01:/opt/k8s-study# kubectl delete -f test-pod.yaml

监控Pod

查看Pod的日志:

bash 复制代码
root@master01:/opt/k8s-study# kubectl logs test-pod
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/08/25 13:21:03 [notice] 1#1: using the "epoll" event method
2024/08/25 13:21:03 [notice] 1#1: nginx/1.27.0
2024/08/25 13:21:03 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) 
2024/08/25 13:21:03 [notice] 1#1: OS: Linux 3.10.0-1160.119.1.el7.x86_64
2024/08/25 13:21:03 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2024/08/25 13:21:03 [notice] 1#1: start worker processes
2024/08/25 13:21:03 [notice] 1#1: start worker process 28
2024/08/25 13:21:03 [notice] 1#1: start worker process 29
10.244.3.1 - - [25/Aug/2024:14:07:45 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" "-"
2024/08/25 14:07:45 [error] 29#29: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.244.3.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.1.201:31473", referrer: "http://192.168.1.201:31473/"
10.244.3.1 - - [25/Aug/2024:14:07:45 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://192.168.1.201:31473/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" "-"

实时查看Pod的日志:

bash 复制代码
root@master01:/opt/k8s-study# kubectl logs -f test-pod

查看Pod的资源使用情况:

bash 复制代码
root@master01:/opt/k8s-study# kubectl top pod test-pod

更新Pod

Pod的更新通常通过更新其配置文件并重新应用来实现。例如,更新容器的镜像:

bash 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  labels:
    app: test-app
spec:
  containers:
  - name: test-web
    image: nginx:1.21.3
    ports:
    - containerPort: 80

保存更新后的内容为my-pod-updated.yaml,然后使用以下命令应用更新:

bash 复制代码
root@master01:/opt/k8s-study# kubectl apply -f my-pod-updated.yaml

五、Pod的健康检查

在 Kubernetes 中,Pod 的健康检查是确保应用稳定运行的重要机制。Kubernetes 提供了三种健康检查方式:存活探针(Liveness Probe)、就绪探针(Readiness Probe)和启动探针(Startup Probe)。这些探针帮助 Kubernetes 了解容器的状态,并在必要时采取行动。要执行诊断,kubelet 既可以在容器内执行代码,也可以发出一个网络请求。

(1)探针的检查机制

使用探针来检查容器有四种不同的方法。 每个探针都必须准确定义为这四种机制中的一种:

  • exec

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

  • grpc

    使用 gRPC执行一个远程过程调用。 目标应该实现 gRPC 健康检查。 如果响应的状态是 "SERVING",则认为诊断成功。

  • httpGet

    对容器的 IP 地址上指定端口和路径执行 HTTP GET 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。http探针配置说明如下:

    Http Get 说明
    host 要连接的主机名,默认为pod IP。您可能希望在httpHeaders中设置"主机"
    scheme 用于连接主机(HTTP或HTTPS)的方案。默认为HTTP
    path HTTP服务器上的访问路径
    httpHeaders 要在请求中设置的自定义标头。HTTP允许重复标头
    port 容器上要访问的端口的名称或编号。数字必须在1到65535的范围内
  • tcpSocket

    对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。 如果远程系统(容器)在打开连接后立即将其关闭,这算作是健康的。

注意: 和其他机制不同,exec 探针的实现涉及每次执行时创建/复制多个进程。 因此,在集群中具有较高 pod 密度、较低的 initialDelaySecondsperiodSeconds 时长的时候, 配置任何使用 exec 机制的探针可能会增加节点的 CPU 负载。 这种场景下,请考虑使用其他探针机制以避免额外的开销。

(2)探针的类型

针对运行中的容器,kubelet 可以选择是否执行以下三种探针,以及如何针对探测结果作出反应:

  • livenessProbe(存活)

    指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略决定未来。如果容器不提供存活探针, 则默认状态为 Success

  • readinessProbe(就绪)

    指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success

  • startupProbe(准备)

    指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器, 而容器依其重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success

(3)探针的使用时机

何时使用存活态探针(Liveness Probe)?

  • 不需要存活态探针的情况

    • 如果我们的容器能够在遇到问题或不健康时自行崩溃,那么可能不需要存活态探针。Kubernetes 会根据 Pod 的 restartPolicy 自动处理容器的重启。
  • 需要存活态探针的情况

    • 如果我们希望在探测失败时杀死容器并重新启动,那么可以指定一个存活态探针,并将 restartPolicy 设置为 "Always" 或 "OnFailure"。

何时使用就绪态探针(Readiness Probe)?

  • 仅在探测成功时接收流量

    • 如果我们希望只有在探测成功时才开始向 Pod 发送请求流量,可以指定就绪态探针。就绪态探针可以与存活态探针相同,但它的存在意味着 Pod 在启动阶段不会接收任何数据,只有在探针探测成功后才开始接收数据。
  • 进入维护状态

    • 如果我们希望容器能够自行进入维护状态,也可以指定一个就绪态探针,检查某个特定于就绪态的端点,这可能与存活态探针不同。
  • 严格依赖后端服务

    • 如果我们的应用程序对后端服务有严格依赖性,可以同时实现存活态和就绪态探针。存活态探针确保应用程序本身健康,而就绪态探针会额外检查每个所需的后端服务是否可用,避免将流量导向只能返回错误信息的 Pod。

何时使用启动探针(Startup Probe)?

  • 启动时间较长

    • 对于需要较长时间才能启动就绪的 Pod,启动探针是有用的。它可以允许我们设置一个较长的探测时间,而不需要增加存活态探针的时间间隔。
  • 避免死锁

    • 如果我们的容器启动时间通常超出 initialDelaySeconds + failureThreshold × periodSeconds 的总值,应该设置一个启动探针,对存活态探针所使用的同一端点执行检查。将 failureThreshold 设置得足够高,以便容器有充足的时间完成启动,避免死锁状况的发生。

注意

删除 Pod 时的自动处理:如果我们只是想在 Pod 被删除时能够排空请求,不一定需要使用就绪态探针。在删除 Pod 时,Pod 会自动将自身置于未就绪状态,无论就绪态探针是否存在。等待 Pod 中的容器停止期间,Pod 会一直处于未就绪状态。

(4)探测方法测试

为了方便咱们初步理解探针检查容器的方法,下面针对LivenessProbe探针来诊断容器的健康状况的方法分别进行测试说明。

方式一:定义存活命令

首先需要创建一个 Pod,其中运行一个基于 nginx 镜像的容器。 下面是这个 Pod 的配置文件。

bash 复制代码
root@master01:/opt/k8s-study# vi liveness-exec.yaml
root@master01:/opt/k8s-study# cat liveness-exec.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness-nginx
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    args:
    - /bin/sh
    - -c
    - touch /opt/k8s-study/healthy; sleep 30; rm -f /opt/k8s-study/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /opt/k8s-study/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

在这个配置文件中,可以看到 Pod 中只有一个 ContainerperiodSeconds 字段指定了 kubelet 应该每 5 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 5 秒。 kubelet 在容器内执行命令 cat /opt/k8s-study/healthy 来进行探测。 如果命令执行成功并且返回值为 0,kubelet 就会认为这个容器是健康存活的。 如果这个命令返回非 0 值,kubelet 会杀死这个容器并重新启动它。

当容器启动时,执行其中添加的exec命令。这个容器生命的前 30 秒,/opt/k8s-study/healthy 文件是存在的。 所以在这最开始的 30 秒内,执行命令 cat /opt/k8s-study/healthy 会返回成功代码。 30 秒之后,执行命令 cat /opt/k8s-study/healthy 就会返回失败代码。创建 Pod:

bash 复制代码
root@master01:/opt/k8s-study# kubectl apply -f liveness-exec.yaml 
pod/liveness-exec created

输出结果表明还没有存活探针失败:

bash 复制代码
root@master01:/opt/k8s-study# kubectl describe pod liveness-exec
Name:             liveness-exec
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01/192.168.1.201
Start Time:       Mon, 26 Aug 2024 12:25:03 +0800
Labels:           test=liveness
Annotations:      <none>
Status:           Pending
IP:               
IPs:              <none>
Containers:
  liveness-nginx:
    Container ID:  
    Image:         swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    Image ID:      
    Port:          <none>
    Host Port:     <none>
    Args:
      /bin/sh
      -c
      touch /opt/k8s-study/healthy; sleep 30; rm -f /opt/k8s-study/healthy; sleep 600
    State:          Waiting
      Reason:       ContainerCreating
    Ready:          False
    Restart Count:  0
    Liveness:       exec [cat /opt/k8s-study/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5c552 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  kube-api-access-5c552:
    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  37s   default-scheduler  Successfully assigned default/liveness-exec to node01
  Normal  Pulling    36s   kubelet            Pulling image "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0"

35 秒之后,再来看 Pod 的事件:

bash 复制代码
root@master01:/opt/k8s-study# kubectl describe pod liveness-exec

在输出结果的最下面,有信息显示存活探针失败了,这个失败的容器被杀死并且被重建了。

bash 复制代码
root@master01:/opt/k8s-study# kubectl describe pod liveness-exec
Name:             liveness-exec
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01/192.168.1.201
Start Time:       Mon, 26 Aug 2024 12:25:03 +0800
Labels:           test=liveness
Annotations:      <none>
Status:           Running
IP:               10.244.3.12
IPs:
  IP:  10.244.3.12
Containers:
  liveness-nginx:
    Container ID:  docker://c912fc0f3fe3931dd23e8ee2800042c27d7a7337aeed2000a20d4957a27427e2
    Image:         swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    Image ID:      docker-pullable://swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx@sha256:80550935209dd7f6b2d7e8401b9365837e3edd4b047f5a1a7d393e9f04d34498
    Port:          <none>
    Host Port:     <none>
    Args:
      /bin/sh
      -c
      touch /opt/k8s-study/healthy; sleep 30; rm -f /opt/k8s-study/healthy; sleep 600
    State:          Running
      Started:      Mon, 26 Aug 2024 12:26:11 +0800
    Ready:          True
    Restart Count:  0
    Liveness:       exec [cat /opt/k8s-study/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5c552 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-5c552:
    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  105s               default-scheduler  Successfully assigned default/liveness-exec to node01
  Normal   Pulling    104s               kubelet            Pulling image "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0"
  Normal   Pulled     38s                kubelet            Successfully pulled image "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0" in 1m6.343s (1m6.343s including waiting)
  Normal   Created    37s                kubelet            Created container liveness-nginx
  Normal   Started    37s                kubelet            Started container liveness-nginx
  Warning  Unhealthy  19s (x3 over 29s)  kubelet            Liveness probe failed: cat: /opt/k8s-study/healthy: No such file or directory
  Normal   Killing    19s                kubelet            Container liveness-nginx failed liveness probe, will be restarted

再等 30 秒,确认这个容器被重启了:

bash 复制代码
root@master01:/opt/k8s-study# kubectl get pod liveness-exec
NAME            READY   STATUS    RESTARTS      AGE
liveness-exec   1/1     Running   1 (20s ago)   2m16s

输出结果显示 RESTARTS 的值增加了 1。 请注意,一旦失败的容器恢复为运行状态,RESTARTS 计数器就会增加 1。

方式二:定义存活态HTTP请求

bash 复制代码
root@master01:/opt/k8s-study# vi liveness-http.yaml
root@master01:/opt/k8s-study# cat liveness-http.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness-nginx
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
    livenessProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 5
      timeoutSeconds: 1

在这个配置文件中periodSeconds 字段指定了 kubelet 每隔 5秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 10 秒。 kubelet 会向容器内运行的服务(服务在监听 80 端口)发送一个 HTTP GET 请求来执行探测。 如果服务器上 /healthz 路径下的处理程序返回成功代码,则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码,则 kubelet 会杀死这个容器并将其重启。

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

bash 复制代码
root@master01:/opt/k8s-study# kubectl get pod liveness-http
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   1/1     Running   0          7s
root@master01:/opt/k8s-study# kubectl describe pod liveness-http
Name:             liveness-http
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01/192.168.1.201
Start Time:       Mon, 26 Aug 2024 12:49:45 +0800
Labels:           test=liveness
Annotations:      <none>
Status:           Running
IP:               10.244.3.15
IPs:
  IP:  10.244.3.15
Containers:
  liveness-nginx:
    Container ID:   docker://8343ea34f93366a62918d8b9e7af2e3f9a3e97cf588741c08453cf238ef2e16f
    Image:          swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    Image ID:       docker-pullable://swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx@sha256:80550935209dd7f6b2d7e8401b9365837e3edd4b047f5a1a7d393e9f04d34498
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 26 Aug 2024 12:49:46 +0800
    Ready:          True
    Restart Count:  0
    Liveness:       http-get http://:80/healthz delay=10s timeout=1s period=5s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hg7f2 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-hg7f2:
    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  13s   default-scheduler  Successfully assigned default/liveness-http to node01
  Normal   Pulled     12s   kubelet            Container image "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0" already present on machine
  Normal   Created    12s   kubelet            Created container liveness-nginx
  Normal   Started    12s   kubelet            Started container liveness-nginx
  Warning  Unhealthy  2s    kubelet            Liveness probe failed: HTTP probe failed with statuscode: 404

这里由于/healthz路径不存在,所以容器报错404并进行重启。

方式三:定义 TCP 的存活探测

第三种类型的存活探测是使用 TCP 套接字。 使用这种配置时,kubelet 会尝试在指定端口和容器建立套接字链接。 如果能建立连接,这个容器就被看作是健康的,如果不能则这个容器就被看作是有问题的。

bash 复制代码
root@master01:/opt/k8s-study# vi liveness-tcp.yaml
root@master01:/opt/k8s-study# cat liveness-tcp.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: liveness
  labels:
    app: liveness-tcp
spec:
  containers:
  - name: liveness-nginx
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    ports:
    - containerPort: 80
    readinessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 5
    livenessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 5

这里我们同时使用就绪探针和存活探针。kubelet 会在容器启动 10秒后运行第一次存活探测。 此探测会尝试连接nginx端口。如果探测成功,则该pod将标记为就绪。 如果此存活探测失败,容器将被重启。kubelet 将继续每隔 5秒运行一次这种探测。

除了存活探针,这个配置还包括一个就绪探针。 kubelet 会在容器启动 10秒后运行第一次就绪探测。 与存活探测类似,就绪探测会尝试连接 nginx 容器的 80 端口。 如果就绪探测失败,Pod 将被标记为未就绪,且不会接收来自任何服务的流量。

bash 复制代码
root@master01:/opt/k8s-study# kubectl apply -f liveness-tcp.yaml 
pod/liveness-tcp created
root@master01:/opt/k8s-study# kubectl get pod liveness-tcp -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
liveness-tcp   1/1     Running   0          33s   10.244.3.19   node01   <none>           <none>
root@master01:/opt/k8s-study# kubectl describe pod liveness-tcp
Name:             liveness-tcp
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01/192.168.1.201
Start Time:       Mon, 26 Aug 2024 13:23:41 +0800
Labels:           app=liveness-tcp
Annotations:      <none>
Status:           Running
IP:               10.244.3.19
IPs:
  IP:  10.244.3.19
Containers:
  liveness-nginx:
    Container ID:   docker://6733f48c70bd2aacaec81c2bc44b3dcdcb86af018c7615dbe575710dd08bb142
    Image:          swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    Image ID:       docker-pullable://swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx@sha256:80550935209dd7f6b2d7e8401b9365837e3edd4b047f5a1a7d393e9f04d34498
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 26 Aug 2024 13:23:42 +0800
    Ready:          True
    Restart Count:  0
    Liveness:       tcp-socket :80 delay=10s timeout=1s period=5s #success=1 #failure=3
    Readiness:      tcp-socket :80 delay=10s timeout=1s period=5s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hgsfg (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-hgsfg:
    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  38s   default-scheduler  Successfully assigned default/liveness-tcp to node01
  Normal  Pulled     37s   kubelet            Container image "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0" already present on machine
  Normal  Created    37s   kubelet            Created container liveness-nginx
  Normal  Started    37s   kubelet            Started container liveness-nginx

如果定义的其他端口检测不通过,那么就会进入到未就绪状态:

bash 复制代码
#Readiness尝试连接6379
root@master01:/opt/k8s-study# kubectl describe pod liveness-tcp
Name:             liveness-tcp
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01/192.168.1.201
Start Time:       Mon, 26 Aug 2024 13:12:41 +0800
Labels:           app=liveness-tcp
Annotations:      <none>
Status:           Running
IP:               10.244.3.18
IPs:
  IP:  10.244.3.18
Containers:
  liveness-nginx:
    Container ID:   docker://b27bb8c8e530aa4dd26436f883b57ab9ecfc6e84870346b79ceff1d0cd779da0
    Image:          swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
    Image ID:       docker-pullable://swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx@sha256:80550935209dd7f6b2d7e8401b9365837e3edd4b047f5a1a7d393e9f04d34498
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 26 Aug 2024 13:12:41 +0800
    Ready:          False
    Restart Count:  0
    Liveness:       tcp-socket :80 delay=10s timeout=1s period=5s #success=1 #failure=3
    Readiness:      tcp-socket :6379 delay=10s timeout=1s period=5s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-tgrmt (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  kube-api-access-tgrmt:
    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  24s               default-scheduler  Successfully assigned default/liveness-tcp to node01
  Normal   Pulled     24s               kubelet            Container image "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0" already present on machine
  Normal   Created    24s               kubelet            Created container liveness-nginx
  Normal   Started    24s               kubelet            Started container liveness-nginx
  Warning  Unhealthy  4s (x3 over 14s)  kubelet            Readiness probe failed: dial tcp 10.244.3.18:6379: connect: connection refused

方式四:定义gRPC存活探针

Kubernetes 中使用 gRPC 存活探针(Liveness Probe)来测试 etcd Pod,我们需要确保 etcd 容器能够处理 gRPC 健康检查请求。etcd 本身支持 gRPC 健康检查,因此我们可以直接配置存活探针来使用 gRPC 机制。首先仍然是配置etcd的yaml文件:

bash 复制代码
root@master01:/opt/k8s-study# vi liveness-grpc.yaml 
root@master01:/opt/k8s-study# cat liveness-grpc.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: etcd-grpc
spec:
  containers:
  - name: etcd
    image: registry.aliyuncs.com/google_containers/etcd:3.5.3-0
    command:
    - /usr/local/bin/etcd
    - --listen-client-urls
    - http://0.0.0.0:2379
    - --advertise-client-urls
    - http://0.0.0.0:2379
    ports:
    - containerPort: 2379
    livenessProbe:
      grpc:
        port: 2379
        service: ""
      initialDelaySeconds: 10
      periodSeconds: 20

要使用 gRPC 探针,必须配置 port 属性。这里配置说明如下:

  • command: 启动 etcd 并配置监听客户端 URL。

  • ports: 暴露 etcd 的客户端端口 2379。

  • livenessProbe : 配置 gRPC 存活探针,使用端口 2379 进行健康检查。initialDelaySeconds 设置为 10 秒,表示在 Pod 启动后 10 秒开始进行健康检查;periodSeconds 设置为 20 秒,表示每 20 秒进行一次健康检查。

bash 复制代码
root@master01:/opt/k8s-study# vi liveness-grpc.yaml
root@master01:/opt/k8s-study# kubectl apply -f liveness-grpc.yaml 
pod/etcd-grpc created
root@master01:/opt/k8s-study# kubectl describe pod 
Name:             etcd-grpc
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01/192.168.1.201
Start Time:       Mon, 26 Aug 2024 13:36:27 +0800
Labels:           <none>
Annotations:      <none>
Status:           Running
IP:               10.244.3.20
IPs:
  IP:  10.244.3.20
Containers:
  etcd:
    Container ID:  docker://ff41855c8b2232fe4bfd7702f925d73a2bcedeb15f156beaf6a5b192efa89099
    Image:         registry.aliyuncs.com/google_containers/etcd:3.5.3-0
    Image ID:      docker-pullable://registry.aliyuncs.com/google_containers/etcd@sha256:13f53ed1d91e2e11aac476ee9a0269fdda6cc4874eba903efd40daf50c55eee5
    Port:          2379/TCP
    Host Port:     0/TCP
    Command:
      /usr/local/bin/etcd
      --listen-client-urls
      http://0.0.0.0:2379
      --advertise-client-urls
      http://0.0.0.0:2379
    State:          Running
      Started:      Mon, 26 Aug 2024 13:36:28 +0800
    Ready:          True
    Restart Count:  0
    Liveness:       grpc <pod>:2379  delay=10s timeout=1s period=20s #success=1 #failure=3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-54ckd (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-54ckd:
    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  18s   default-scheduler  Successfully assigned default/etcd-grpc to node01
  Normal  Pulled     17s   kubelet            Container image "registry.aliyuncs.com/google_containers/etcd:3.5.3-0" already present on machine
  Normal  Created    17s   kubelet            Created container etcd
  Normal  Started    17s   kubelet            Started container etcd

当使用 gRPC 探针时,需要注意以下一些技术细节:

  • 这些探针运行时针对的是 Pod 的 IP 地址或其主机名。 请一定配置我们的 gRPC 端点使之监听于 Pod 的 IP 地址之上。

  • 这些探针不支持任何身份认证参数(例如 -tls)。

  • 对于内置的探针而言,不存在错误代码。所有错误都被视作探测失败。

  • 如果 ExecProbeTimeout 特性门控被设置为 false,则 grpc-health-probe 不会考虑 timeoutSeconds 设置状态(默认值为 1s), 而内置探针则会在超时时返回失败。

当然,pod的使用点并不仅只有这点而已,更多具体的使用方式,大家可参考官方文档-探针的配置和使用

相关推荐
Code_Artist2 小时前
使用Portainer来管理并编排Docker容器
docker·云原生·容器
Eternal-Student2 小时前
【docker 保存】将Docker镜像保存为一个离线的tar归档文件
运维·docker·容器
码农小丘2 小时前
一篇保姆式centos/ubuntu安装docker
运维·docker·容器
灼烧的疯狂4 小时前
K8S + Jenkins 做CICD
容器·kubernetes·jenkins
wenyue11215 小时前
Revolutionize Your Kubernetes Experience with Easegress: Kubernetes Gateway API
容器·kubernetes·gateway
梅见十柒6 小时前
wsl2中kali linux下的docker使用教程(教程总结)
linux·经验分享·docker·云原生
Python私教7 小时前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes
运维&陈同学8 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
O&REO9 小时前
单机部署kubernetes环境下Overleaf-基于MicroK8s的Overleaf应用部署指南
云原生·容器·kubernetes
politeboy9 小时前
k8s启动springboot容器的时候,显示找不到application.yml文件
java·spring boot·kubernetes