联 系 我 们
售前咨询
售后咨询
微信关注:星环科技服务号
更多联系方式 >
9.3.4 Pod 异常
更新时间:5/29/2023, 7:55:25 AM

Pod 异常是指数据库运行的容器实例(Pod)出现了不正常的状态或无法正常运行的情况。这些异常可能导致数据库服务的中断、数据不一致或性能下降等问题。下面主要就以下几个方面向您介绍 Pod 异常处理的相关内容:

  • Pod 生命周期:向您介绍 Pod 的整个生命周期中,一般都会存在哪些状态以及原因。

  • Pod 异常场景排查:Pod 在其生命周期中,一般都会出现哪些异常的场景及定位关键信息。

  • Pod 异常案例:整理部分 Pod 异常的故障排查及解决案例。

Pod 生命周期
查看 Pod 状态

除了必要的集群和应用监控,一般还需要通过 kubectl 命令搜集异常状态信息。

查看某个资源
kubectl get pod|node|deploy|rs|ns [<source_name>] [-o wide|yaml|json] [-n defalt|kube-system] [|grep <filter_info>]
复制
  • pod|node|deploy|rs|ns:需要查看的资源类型。该资源可以是 pod、node、deployment、replicaset、namespace 等。

  • <source_name>:资源(如 Pod)名称,不指定则输出集群中的所有知道类型资源。

  • -o:选择输出的格式,不指定则安装:

    • wide:以宽输出格式展示 Pod 的详细信息,包括资源(如 Pod)所在的节点 node 和 IP 地址等。

    • yaml|json:以 yaml 或 json 形式展示资源(如 Pod)的信息。

  • -n:选择命名空间,不指定则默认输出 default 中的资源(如 Pod)信息。

  • |grep:对输出信息进行筛选。

pod unhealthy
图 6.3.1:查看 Pod 状态

输出结果说明:

  • NAME:第一列展示了 Pod 的名称 ID。

  • READY:第二列表示一个 Pod 中有多少个容器被认为是就绪的。假设值为 m/n,若 m < n,Pod 中准备好的容器(m)将少于它们的总数(n),因此整个 Pod 不会被认为是就绪的。

  • STATUS:展示了 Pod 的状态,具体含义请参考 Pod 状态汇总

  • RESTART:Pod 的重启次数。

  • AGE:该 Pod 距今创建了多长时间。

获取 Pod 当前对象描述文件
kubectl get pod <pod_name> -o yaml
复制
获取资源(如 Pod)的详细信息和事件(Events)
kubectl describe {pod|node|deploy|rs} <source_name>
复制
获取 Pod 容器日志
kubectl logs <pod_name> [<container_name>] [-f]
复制
  • <container_name>:当 Pod 中含有多个容器时,需要指定容器名称。

  • -f:表示实时动态展示指定 pod 的 pod 日志。

在容器中执行命令
kubectl exec <pod_name> -n <name_space> -c <container_name> #<CMD> <ARGS>
复制
Pod 状态汇总

在整个生命周期中,Pod 会出现 5 种阶段(Phase),Pod 的 5 个阶段是 Pod 在其生命周期中所处位置的简单宏观概述,并不是对容器或 Pod 状态的综合汇总。下面向您介绍 Pod 和容器的生命周期以及基本状态:

在异常诊断过程中,容器的退出状态是至关重要的信息。

表 6.3.1:Pod 状态
分类 状态 说明

Pod 生命周期阶段(Phase)

Pending

Pod 被 K8s 创建出来后,起始于 Pending 阶段。在 Pending 阶段,Pod 将经过调度,被分配至目标节点开始拉取镜像、加载依赖项、创建容器。

Running

当 Pod 所有容器都已被创建,且至少一个容器已经在运行中,Pod 将进入 Running 阶段。

Succeeded

当 Pod 中的所有容器都执行完成后终止,并且不会再重启,Pod 将进入 Succeeded 阶段。

Failed

若 Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止,也就是说容器以非 0 状态异常退出或被系统终止,Pod将进入Failed阶段。

Unkonwn

因为某些原因无法取得 Pod 状态,这种情况 Pod 将被置为 Unkonwn 状态。

Pod 细分状态(PodConditions,用于描述造成 Pod 所处阶段的具体成因是什么)

Ready/NotReady

描述 Pod 是否准备好接收网络流量。Ready 表示 Pod 可以接收流量,NotReady 表示 Pod 尚未准备好接收流量。

Initialized

描述 Pod 是否已完成初始化过程,包括创建容器、加载镜像等步骤。

PodScheduled

表示 Pod 已经被调度到节点上运行。

Unschedulable

表示 Pod 无法被调度到节点上运行。

容器生命周期状态(State)

Waiting

描述容器当前处于等待状态,可能是因为依赖其他资源、容器启动时间较长等待等原因。

Running

描述容器正在正常运行中

Terminated

描述容器已经终止或完成运行。

容器状态原因(Reason)

ContainerCreating

表示容器正在创建过程中。

Error

表示容器发生错误,无法正常启动或运行。

OOMKilled

表示容器因为内存不足被系统终止。

CrashLoopBackOff

表示容器在启动后立即崩溃并持续重启。

Completed

表示容器已经成功完成任务并终止。

pod lifecycle
图 6.3.2:Pod 生命周期
  • 一般来说,对于 Job 类型的负载,Pod 在成功执行完任务之后将会以 Succeeded 状态为终态。

  • 而对于 Deployment 等负载,一般期望 Pod 能够持续提供服务,直到 Pod 因删除消失,或者因异常退出/被系统终止而进入 Failed 阶段。

Pod 异常排查

Pod 在其生命周期的许多时间点可能发生不同的异常,按照 Pod 容器是否运行为标志点,我们将异常场景大致分为两类:

  • 在 Pod 进行调度并创建容器过程中发生异常,此时 Pod 将卡 在 Pending 阶段。

  • Pod 容器运行中发生异常,此时 Pod 按照具体场景处在不同阶段。

pod error type details
图 6.3.3:Pod 异常场景

对于不同的异常场景,Pod 会有不同的错误状态,您可以根据相关报错信息中的状态关键词快速锁定 Pod 异常原因:

表 6.3.2:Pod 异常关键词参考
异常场景 常见错误状态

调度失败

Unschedulable

镜像拉取失败

ImagePullBackOff

依赖项错误

Error

容器创建失败

Error

初始化失败

CrashLoopBackOff

回调失败

FailedPostStartHook 或 FailedPreStopHook 事件

就绪探针失败

容器已经全部启动,但是 Pod 处于 NotReady 状态,服务流量无法从 Service 达到 Pod

存活探针失败

CrashLoopBackOff

容器退出

CrashLoopBackOff

OOMKilled

OOMKilled

Pod 驱逐

Pod Evicted

Pod 失联

Unkonwn

无法被删除

卡在Terminating

调度失败

Pod 被创建后进入调度阶段,K8s 调度器依据 Pod 声明的资源请求量和调度规则,为 Pod 挑选一个适合运行的节点。当集群节点均不满足 Pod 调度需求时,Pod 将会处于 Pending 状态。造成调度失败的典型原因如下:

节点资源不足

K8s 将节点资源(CPU、内存、磁盘等)进行数值量化,定义出节点资源容量(Capacity)和节点资源可分配额(Allocatable)。

  • 资源容量是指 Kubelet 获取的计算节点当前的资源信息,

  • 资源可分配额是 Pod 可用的资源。

    Pod 容器有两种资源额度概念:请求值 Request 和限制值 Limit,容器至少能获取请求值大小、至多能获取限制值的资源量。

    • Pod 的资源请求量是 Pod 中所有容器的资源请求之和;

    • Pod 的资源限制量是 Pod 中所有容器的资源限制之和。

    K8s 默认调度器按照较小的请求值作为调度依据,保障可调度节点的资源可分配额一定不小于 Pod 资源请求值。当集群没有一个节点满足 Pod 的资源请求量,则 Pod 将卡在 Pending 状态。

Pod 因为无法满足资源需求而被 Pending,可能是因为集群资源不足,需要进行扩容,也有可能是集群碎片导致。

以一个典型场景为例,用户集群有十几个 4 核 8GB 内存的节点,整个集群资源使用率在 60% 左右,每个节点都有碎片,但因为碎片太小导致扩不出来一个 2c4g(2 核 4G 内存)的 Pod。

一般来说,小节点集群会更容易产生资源碎片,而碎片资源无法供 Pod 调度使用。如果想最大限度地减少资源浪费,使用更大的节点可能会带来更好的结果。

超过 Namespace 资源配额

K8s 用户可以通过资源配额(Resource Quota)对 Namespace 进行资源使用量限制,包括两个维度:

  • 限定某个对象类型(如 Pod)可创建对象的总数。

  • 限定某个对象类型可消耗的资源总数。

如果在创建或更新 Pod 时申请的资源超过了资源配额,则 Pod 将调度失败。此时需要检查 Namespace 资源配额状态,做出适当调整。

不满足 NodeSelector 节点选择器

Pod 通过 NodeSelector 节点选择器指定调度到带有特定 Label 的节点,若不存在满足 NodeSelector 的可用节点,Pod 将无法被调度,需要对 NodeSelector 或节点 Label 进行合理调整。

不满足亲和性

节点亲和性(Affinity)和反亲和性(Anti-Affinity)用于约束 Pod 调度到哪些节点,而亲和性又细分为软亲和(Preferred)和硬亲和(Required)。对于软亲和规则,K8s 调度器会尝试寻找满足对应规则的节点,如果找不到匹配的节点,调度器仍然会调度该 Pod。而当硬亲和规则不被满足时,Pod 将无法被调度,需要检查 Pod 调度规则和目标节点状态,对调度规则或节点进行合理调整。

节点存在污点

K8s 提供污点(Taints)和容忍(Tolerations)机制,用于避免 Pod 被分配到不合适的节点上。假如节点上存在污点,而 Pod 没有设置相应的容忍,Pod 将不会调度到该节点。此时需要确认节点是否有携带污点的必要,如果不必要的话可以移除污点;若 Pod 可以分配到带有污点的节点,则可以给 Pod 增加污点容忍。

没有可用节点

节点可能会因为资源不足、网络不通、Kubelet 未就绪等原因导致不可用(NotReady)。当集群中没有可调度的节点,也会导致 Pod 卡在 Pending 状态。此时需要查看节点状态,排查不可用节点问题并修复,或进行集群扩容。

镜像拉取失败

Pod 经过调度后分配到目标节点,节点需要拉取 Pod 所需的镜像为创建容器做准备。拉取镜像阶段可能存在以下几种原因导致失败:

镜像名字拼写错误或配置了错误的镜像

出现镜像拉取失败后首先要确认镜像地址是否配置错误。

私有仓库的免密配置错误

集群需要进行免密配置才能拉取私有镜像。自建镜像仓库时需要在集群创建免密凭证 Secret,在 Pod 指定 ImagePullSecrets,或者将 Secret 嵌入 ServiceAccount,让 Pod 使用对应的 ServiceAccount。而对于 ACR 等镜像服务云产品一般会提供免密插件,需要在集群中正确安装免密插件才能拉取仓库内的镜像。免密插件的异常包括:集群免密插件未安装、免密插件 Pod 异常、免密插件配置错误,需要查看相关信息进行进一步排查。

网络不通

网络不通的常见场景有三个:

  • 集群通过公网访问镜像仓库,而镜像仓库未配置公网的访问策略。

    • 对于自建仓库,可能是端口未开放,或是镜像服务未监听公网 IP;

    • 对于 ACR 等镜像服务云产品,需要确认开启公网的访问入口,配置白名单等访问控制策略。

  • 集群位于专有网络,需要为镜像服务配置专有网络的访问控制,才能建立

镜像拉取超时

常见于带宽不足或镜像体积太大,导致拉取超时。可以尝试在节点上手动拉取镜像,观察传输速率和传输时间,必要时可以对集群带宽进行升配,或者适当调整 Kubelet 的 --image-pull-progress-deadline 和 --runtime-request-timeout

同时拉取多个镜像,触发并行度控制

常见于用户弹性扩容出一个节点,大量待调度 Pod 被同时调度上去,导致一个节点同时有大量 Pod 启动,同时从镜像仓库拉取多个镜像。而受限于集群带宽、镜像仓库服务稳定性、容器运行时镜像拉取并行度控制等因素,镜像拉取并不支持大量并行。这种情况可以手动打断一些镜像的拉取,按照优先级让镜像分批拉取。

依赖项错误

在 Pod 启动之前,Kubelet 将尝试检查与其他 K8s 元素的所有依赖关系。主要存在的依赖项有三种:PersistentVolume、ConfigMap 和 Secret。

当这些依赖项不存在或者无法读取时,Pod 容器将无法正常创建,Pod 会处于 Pending 状态直到满足依赖性。当这些依赖项能被正确读取,但出现配置错误时,也会出现无法创建容器的情况。比如将一个只读的持久化存储卷 PersistentVolume 以可读写的形式挂载到容器,或者将存储卷挂载到 /proc 等非法路径,也会导致容器创建失败。

容器创建失败

Pod容器创建过程中出现了错误。常见原因包括:

  • 违反集群的安全策略,比如违反了 PodSecurityPolicy 等。

  • 容器无权操作集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 配置角色绑定。

  • 缺少启动命令,Pod 描述文件和镜像 Dockerfile 中均未指定启动命令。

  • 启动命令配置错误。Pod 配置文件可以通过 command 字段定义命令行,通过 args 字段给命令行定义参数。启动命令配置错误的情况非常多见,要格外注意命令及参数的格式。

初始化失败

K8s 提供 Init Container 特性,用于在启动应用容器之前启动一个或多个初始化容器,完成应用程序所需的预置条件。Init container 与应用容器本质上是一样的,但它们是仅运行一次就结束的任务,并且必须在执行完成后,系统才能继续执行下一个容器。如果 Pod 的 Init Container 执行失败,将会 block 业务容器的启动。通过查看 Pod 状态和事件定位到 Init Container 故障后,需要查看 Init Container 日志进一步排查故障点。

回调失败

K8s 提供 PostStart 和 PreStop 两种容器生命周期回调,分别在容器中的进程启动前或者容器中的进程终止之前运行。PostStart 在容器创建之后立即执行,但由于是异步执行,无法保证和容器启动命令的执行顺序相关联。PreStop 在容器终止之前被同步阻塞调用,常用于在容器结束前优雅地释放资源。如果 PostStart 或者 PreStop 回调程序执行失败,容器将被终止,按照重启策略决定是否重启。当出现回调失败,会出现 FailedPostStartHook 或 FailedPreStopHook 事件,进一步结合容器打出的日志进行故障排查。

就绪探针失败

K8s 使用 Readiness Probe(就绪探针)来确定容器是否已经就绪可以接受流量。只有当 Pod 中的容器都处于就绪状态时,K8s 才认定该Pod 处于就绪状态,才会将服务流量转发到该容器。

一般就绪探针失败分为几种情况:

  • 容器内应用原因:健康检查所配置规则对应的端口或者脚本,无法成功探测,如容器内应用没正常启动等。

  • 针配置不当:写错检查端口导致探测失败;

    检测间隔和失败阈值设置不合理,例如每次检查间隔 1 秒,一次不通过即失败;

    启动延迟设置太短,例如应用正常启动需要 15 秒,而设置容器启动10s后启用探针。

  • 系统层问题:节点负载高,导致容器进程异常。

  • CPU 资源不足:CPU 资源限制值过低,导致容器进程响应慢。

存活探针失败

K8s 使用 Liveness Probe(存活探针)来确定容器是否正在运行。

  • 如果存活态探测失败,则容器会被杀死,随之按照重启策略决定是否重启。存活探针失败的原因与就绪探针类似,然而存活探针失败后容器会被 kill 消失。

    一个典型的用户场景是,用户在压测期间通过 HPA 弹性扩容出多个新 Pod,然而新 Pod 一启动就被大流量阻塞,无法响应存活探针,导致 Pod 被 kill。kill 后又重启,重启完又挂掉,一直在 Running 和 CrashLoopBackOff 状态中振荡。

  • 微服务场景下可以使用延迟注册和服务预热等手段,避免瞬时流量打挂容器。

  • 如果是程序本身问题导致运行阻塞,建议先将 Liveness 探针移除,通过 Pod 启动后的监控和进程堆栈信息,找出流量涌入后进程阻塞的根因。

容器退出

容器退出分为两种场景:

  • 启动后立即退出,可能原因是:

    • 启动命令的路径未包含在环境变量PATH中。

    • 启动命令引用了不存在的文件或目录。

    • 启动命令执行失败,可能因为运行环境缺少依赖,也可能是程序本身原因。

    • 启动命令没有执行权限。

    • 容器中没有前台进程。容器应该至少包含一个long-running的前台进程,不能后台运行,比如通过nohup这种方式去启动进程,或是用tomcat的startup.sh脚本。

    对于容器启动后立即退出的情况,通常因为容器直接消失,无法获取其输出流日志,很难直接通过现场定位问题。一个简易的排查方式是,通过设置特殊的启动命令卡住容器(比如使用tail -f /dev/null),然后进到容器中手动执行命令看看结果,确认问题原因。

  • 运行一段时间后退出: 这种情况一般是容器内 1 进程 Crash 或者被系统终止导致退出。此时首先查看容器退出状态码,然后进一步查看上下文信息进行错误定位。这种情况发生时容器已经删除消失,无法进入容器中查看日志和堆栈等现场信息,所以一般推荐用户对日志、错误记录等文件配置持久化存储,留存更多现场信息。几种常见的状态码如下:

    表 6.3.3:容器退出状态码
    状态码 含义 分析

    0

    正常退出

    容器的启动程序不是一个 long-running 的程序。如果正常退出不符合预期,需要检查容器日志,对程序的执行逻辑进行调整。

    137

    外部终止

    137 表示容器已收到来自主机操作系统的 SIGKILL 信号。该信号指示进程立即终止,没有宽限期。可能原因包含:容器运行时将容器 kill,例如 docker kill 命令;Linux 用户向进程发送 kill -9 命令触发;K8s尝试终止容器,超过优雅下线窗口期后直接 kill 容器;由节点系统触发,比如遭遇了 OOM。

    139

    段错误

    139 表示容器收到了来自操作系统的 SIGSEGV 信号。这表示分段错误——内存违规,由容器试图访问它无权访问的内存位置引起。

    143

    优雅终止

    143 表示容器收到来自操作系统的 SIGTERM 信号,该信号要求容器正常终止。该退出码可能的原因是:容器引擎停止容器,例如使用 docker stop 停止了容器;K8s 终止了容器,比如缩容行为将 Pod 删除。

OOMKilled

K8s 中有两种资源概念:可压缩资源(CPU)和不可压缩资源(内存,磁盘 )。当 CPU 这种可压缩资源不足时,Pod 不会退出;而当内存和磁盘 IO 这种不可压缩资源不足时,Pod 会被 kill 或者驱逐。因为内存资源不足/超限所导致的 Pod 异常退出的现象被称为 Pod OOMKilled。

K8s存在两种导致 Pod OOMKilled 的场景:

  • Container Limit Reached,容器内存用量超限

    Pod 内的每一个容器都可以配置其内存资源限额,当容器实际占用的内存超额,该容器将被 OOMKilled 并以状态码 137 退出。OOMKilled 往往发生在 Pod 已经正常运行一段时间后,可能是由于流量增加或是长期运行累积的内存逐渐增加。这种情况需要查看程序日志以了解为什么 Pod 使用的内存超出了预期,是否出现异常行为。如果发现程序只是按照预期运行就发生了 OOM,就需要适当提高 Pod 内存限制值。

    例如 JAVA 容器设置了内存资源限制值 Limit,然而 JVM 堆大小限制值比内存 Limit 更大,导致进程在运行期间堆空间越开越大,最终因为 OOM 被终止。对于JAVA容器来说,一般建议容器内存限制值 Limit 需要比 JVM 最大堆内存稍大一些。

  • Limit Overcommit,节点内存耗尽

    K8s 有两种资源额度概念:请求值 Request 和限制值 Limit,默认调度器按照较小的请求值作为调度依据,保障节点的所有 Pod 资源请求值总和不超过节点容量,而限制值总和允许超过节点容量,这就是 K8s 资源设计中的 Overcommit(超卖)现象。超卖设计在一定程度上能提高吞吐量和资源利用率,但会出现节点资源被耗尽的情况。当节点上的 Pod 实际使用的内存总和超过某个阈值,K8s 将会终止其中的一个或多个 Pod。

    为避免这种情况,建议在创建 Pod 时选择大小相等或相近的内存请求值和限制值,也可以利用调度规则将内存敏感型 Pod 打散到不同节点。

Pod 驱逐

当节点内存、磁盘这种不可压缩资源不足时,K8s 会按照 QoS 等级对节点上的某些 Pod 进行驱逐,释放资源保证节点可用性。当 Pod 发生驱逐后,上层控制器例如 Deployment 会新建 Pod 以维持副本数,新 Pod 会经过调度分配到其他节点创建运行。对于内存资源,前文已经分析过可以通过设置合理的请求值和限制值,避免节点内存耗尽。而对于磁盘资源,Pod 在运行期间会产生临时文件、日志,所以必须对 Pod 磁盘容量进行限制,否则某些 Pod 可能很快将磁盘写满。类似限制内存、CPU 用量的方式,在创建 Pod 时可以对本地临时存储用量(ephemeral-storage)进行限制。同时,Kubelet 驱逐条件默认磁盘可用空间在 10% 以下,可以调整云监控磁盘告警阈值以提前告警。

Pod 失联

Pod处于 Unkonwn 状态,无法获取其详细信息,一般是因为所在节点 Kubelet 异常,无法向 APIServer 上报 Pod 信息。首先检查节点状态,通过 Kubelet 和容器运行时的日志信息定位错误,进行修复。如果无法及时修复节点,可以先将该节点从集群中删除。

无法被删除

当一个 Pod 被执行删除操作后,却长时间处于 Terminating 状态,这种情况的原因有几种:

  • Pod关联的 finalizer 未完成。首先查看 Pod 的 metadata 字段是否包含 finalizer,通过一些特定上下文信息确认 finalizer 任务具体是什么,通常 finalizer 的任务未完成可能是因为与 Volume 相关。如果 finalizer 已经无法被完成,可以通过 patch 操作移除对应的 Pod 上的 finalizer 完成删除操作。

  • Pod 对中断信号没有响应。Pod 没有被终止可能是进程对信号没有响应,可以尝试强制删除Pod。

  • 节点故障。通过查看相同节点上的其他 Pod 状态确认是否节点故障,尝试重启 Kubelet 和容器运行时。如果无法修复,先将该节点从集群中删除。

Pod 异常案例
Pod Pending

问题描述

TOS 集群中的 Pod 长期处于 Pending 状态。

问题分析

此问题一般是由于 TOS 集群的某种类似的资源不足或是不符合调度规则导致。

排查思路

引发此问题的原因可能是:调度器自身问题,调度节点资源问题及 pod 的亲和性污点(taint)问题。

  1. 查看 TOS 或 K8s 集群的 kube-scheduler 组件是否正常运行(running):

    kubectl get po -n kube-system | grep scheduler
    复制

    若是这个 pod 状态不是 Running,可以执行以下命令重启 scheduler 尝试恢复:

    kubectl delete po tos-scheduler-tos-xxx ##其中“xxx”一般为节点的 hostname
    复制

    scheduler 恢复后查看 pending pod 状态是否正常。

  2. 查看 pending pod 的 describe 日志:

    kubectl describe pods <pending_pod_name>
    复制

    在最后的 Events 会有 pod 调度失败的原因。

解决方案

资源不足

集群中节点的 CPU/内存/GPU 资源不够

  1. 添加更多节点到集群,或者终止不需要的 pod 为 pending 中的 pod 提供空间。

  2. 检查该 pod 请求的资源是否小于节点(node)可申请的资源:查看 node 资源使用情况

    kubectl get nodes   ##查看集群节点
    kubectl describe node <node1>   ##查看节点描述
    复制
    • Allocatable 为此节点能够申请的资源总和;

    • Allocated resources 为此节点已经分配的资源;

    • 前者与后者相减,为剩余可以申请的资源。

不满足 nodeSelector 或 Affinity

若是 describe pod 的 FailedScheduling 的报错中含有 MatchNodeSelector,pod affinity,pod anti-affinity 或是 node affinity 等字眼的报错,可以通过如下命令查看 pod 或是 node affinity 相关定义部分:

kubectl get po <pod_name> -oyaml | grep 'nodeSelector:'     ## nodeSelector 相关部分
kubectl get po <pod_name> -oyaml | grep -A 20 'affinity:'     ## affinity 相关部分
复制
Node 存在 Pod 没有容忍的污点

如果节点上存在污点(Taints),而 Pod 没有相应的容忍(Tolerations),Pod 将无法调度成功。

  1. 通过 describe node 可以看下 Node 有哪些 Taints:

    kubectl describe nodes <node> | grep Taints:
    复制
  2. 若是有污点,即输出内容不是 <none>,解决方法有如下 2 个:

    • 删除污点:

      kubectl taint nodes <node1> <key>-
      复制
    • (推荐)给 Pod 加上这个污点的容忍:

      1. 进入 Pod 编辑页面(谨慎操作,建议联系星环科技工程师确认):

        kubectl edit pod <pod_name>
        复制
      2. 找到 tolerations,并添加如下信息

        tolerations:
        - key: "master"    ##根据 key 的值自行修改
        operator: "Equal"   ##根据 key 的值自行修改
        value: "true"
        effect: "NoSchedule"
        复制
Pod 健康状态与 Manager 页面不一致

问题描述

Manager 页面上服务角色报黄提示 running with problem,后台查看的 pod 状态,都是 0/1 running

问题分析

Manager的health 包括两部分: DAEMON_CHECK和VITAL_SIGN_CHECK。前者检查 pod 状态,后者检查服务状态,出现上述情况时候基本可以确定是后者检查问题。

解决方案

重启 Manager 和 Agent:

如果 Manager 开启了高可用(HA),那么需要重启所有 Manager 节点

HA 数据不同步

如果 Manager 开启了高可用,当节点上数据不同步时候也可能导致该问题。

解决方案:停掉所有的 Manager,然后只启动最初始的那个 Manager 节点,观察服务状态是否正常。

浏览器本身的问题

可以清理浏览器缓存、尝试使用无痕模式、更换其他浏览器(谷歌/火狐)

尝试后台使用 health check 命令验证状态

此时需要了解各个组件的 health check 原理才行

  • 如果检查结果同样报错了,说明服务确实有问题,需要去对应组件的日志中寻找错误原因;

  • 如果检查结果中服务是健康的,说明可能是 health check 的误报,是 Manager 有问题。

重启问题服务

在业务场景以及客户允许的情况下,尝试重启该服务。

客户的环境自身问题

网络环境做过一些特殊的限制等,影响了 health check 的探查。

扩容节点 Pod 无法查看日志

问题描述

集群做过扩容节点操作,扩容后新添加的节点中的所有 Pos 均无法查看日志信息。

问题分析

出现该情况的原因是 apiserver 所对应容器里的 /etc/hosts 信息记录不完全。

解决方案

  1. 确认 apiserver 所在的 server 信息,查看 TOS 角色信息能得知部署了 apiserver 的 pod 的对应节点:

    kubectl get pods -owide -n kube-system | grep apiserver
    复制
  2. 分别 ssh 登录每个节点服务器,执行以下命令查看 apiserver 容器信息:

    #分别登录部署了 apiserver 的节点
    ssh  <user_name>@<server_ip> # 然后输入 yes 确认连接操作之后,输入用户密码即可
    
    # 列出所有在运行的 apiserver 容器信息,输出结果第一列为 container_id
    docker ps | grep apiserver
    复制
    ssh and docker apiserver container
    图 6.3.4:查看 apiserver 容器
  3. 分别进入相关的 container 内,查看 /etc/hosts 信息

    docker exec -it <container_id> bash
    cat /etc/hosts
    复制
  4. 对比正常的 /etc/hosts 信息可以看出 apiserver 的 container 内 /etc/hosts 信息有很多缺失,且缺失部分所在节点均无法正常查看 pod 日志。

  5. 在 apiserver 的 container 内直接修改 hosts 信息:

    docker exec -it <container_id> bash
    
    vi /etc/hosts
    复制

    /etc/hosts 文件添加缺失节点的 ip 和 hostname 映射

  6. 经过验证,在 container 内修改后,即使重启该 container,/etc/hosts 信息仍然会保留。