网易轻舟云原生故障自动诊断系统实践
Kubernetes 是一个生产级的容器编排引擎,但是 Kubernetes 仍然存在系统复杂、故障诊断成本高等问题。网易内部在基于 Kubernetes 落地轻舟云原生体系时遇到了不少问题,主要包括以下几个维度:
- 由 Kubernetes 以及 Docker 的 Bug 引起的故障。
- 内核 Bug 导致的故障。
- 基础设施抖动产生的问题。
- 用户在容器化以及使用 Kubernetes 过程中遇到的问题。
- 用户在容器化后遇到的业务相关问题。
Kubernetes 故障诊断恢复平台是基于 Kubernetes 云原生基础设施能力打造的框架,旨在解决云原生体系中故障诊断、运维恢复的自动化问题,帮助用户更加平滑地完成容器化落地。
目标
Kubernetes 故障诊断恢复平台的设计目标包括:
- 通用性:平台依赖通用技术实现,平台组件可以在绝大部分的 Linux 系统下运行并且能够对 Linux 下运行遇到的故障进行诊断和运维。
- 可扩展性:平台组件之间的交互为松耦合接口设计并且整个框架是可插拔式的。
- 可维护性:框架逻辑简洁明了,维护成本与功能数量为线性关系,不同故障的分析和恢复逻辑具有独立性。
架构
故障诊断恢复平台 Agent 组件可以监听 APIServer 获取 Abnormal CRD 资源,Abnormal CRD 资源是对故障状态机的抽象。故障诊断恢复平台 Agent 组件可以通过 Event、Prometheus 报警、系统日志中的关键条目产生相对应的 Abnormal CRD 并送入故障诊断恢复的流水线。故障诊断恢复平台 Agent 组件使用 DaemonSet 部署在集群中:
---------------------
Watch (Event, CRD) | |
--------------------->| APIServer |
| | |
| |-------------------|
| | |
-------------- --------- | Etcd |
| | Monitor | | Monitor | |
| Prometheus |<----------------| Agent |---------------->|-------------------|
| | | | | |
-------------- --------- | ControllerManager |
| | |
| |-------------------|
| | |
| | Scheduler |
| | |
| ---------------------
\|/
---------------------
| |
| Kernel |
| Docker |
| Kubelet |
| Cgroup |
| ...... |
| |
---------------------
故障诊断恢复平台 Agent 组件由下列部分组成:
- 故障事件源(AbnormalSource)
- 故障分析链(DiagnoserChain)
- 信息管理器(InformationManager)
- 故障恢复链(RecovererChain)
------------------ ---------------------- ------------------ ------------------
| | Abnormal | | Abnormal | | Abnormal | |
| AbnormalSource |------------>| InformationManager |------------>| DiagnoserChain |------------>| RecovererChain |
| | | | | | | |
------------------ ---------------------- ------------------ ------------------
| | |
| | |
| | |
\|/ \|/ \|/
-------------------------- --------------- ---------------
| | | | | |
| InformationCollector 1 | | Diagnoser 1 | | Recoverer 1 |
| | | | | |
-------------------------- --------------- ---------------
| | |
| | |
| | |
\|/ \|/ \|/
-------------------------- --------------- ---------------
| | | | | |
| InformationCollector 2 | | Diagnoser 2 | | Recoverer 2 |
| | | | | |
-------------------------- --------------- ---------------
| | |
| | |
| | |
\|/ \|/ \|/
....... ....... .......
功能
故障诊断恢复平台 Agent 组件功能如下:
- 获取 Event、Prometheus 报警、系统日志作为故障源。
- 监听故障诊断 Abnormal CRD 资源并进行处理和状态同步。
- 对本节点故障进行诊断和恢复。
- 通过 Abnormal CRD 以及 InformationCollector CRD 进行监控扩展和增强。
故障诊断恢复平台中 Abnormal 的状态迁移流程如下:
- 故障事件源监听到 Event、Prometheus 报警、系统日志等异常,故障诊断恢复平台 Agent 或用户自行创建 Abnormal CRD 资源。
- 将 Abnormal 发送至信息管理器,标记 Abnormal 的状态为 InformationCollecting 并采集故障诊断恢复的信息。
- 如果信息能够被成功收集则记录 InformationCollected 状况并继续。
- 将 Abnormal 发送至故障分析链,标记 Abnormal 的状态为 Diagnosing 并对故障进行分析。
- 如果故障能够被成功识别则记录 Identified 状况并继续。
- 如果故障无法被成功识别则将 Abnormal 的状态标记为 Failed 并终止故障诊断恢复流程。
- 将 Abnormal 发送至故障恢复链,标记 Abnormal 的状态为 Recovering 并对故障进行恢复。
- 如果故障能够被成功恢复则记录 Recovered 状况并标记 Abnormal 的状态为 Succeeded。
- 如果故障无法被成功恢复则标记 Abnormal 的状态为 Failed 并终止故障诊断恢复流程。
故障诊断恢复平台中 Abnormal 的状态迁移图如下:
----------
| |
----------------------------------------------------------->| Failed |
/|\ /|\ | |
| | ----------
Failed | Failed |
| |
----------- ------------------------- -------------- -------------- -------------
| | | | | | | | | |
| Created |------------------>| InformationCollecting |------------------>| Diagnosing |------------------>| Recovering |------------------>| Succeeded |
| | | | /|\ | | /|\ | | /|\ | |
----------- ------------------------- | -------------- | -------------- | -------------
| | | | | |
Successfully | | Successfully | | Successfully | |
| | | | | |
\|/ | \|/ | \|/ |
------------------------ | -------------- | ------------- |
| | | | | | | | |
| InformationCollected |--------- | Identified |--------- | Recovered |---------
| | | | | |
------------------------ -------------- -------------
Abnormal CRD
Abnormal 是故障诊断恢复平台中故障事件源、故障分析链、故障恢复链之间通信的接口。故障事件的详情记录在 Spec 中,故障事件源、故障分析链和故障恢复链对 Abnormal 进行处理并通过变更 Status 字段进行通信。故障诊断恢复平台通过 Abnormal 提供以下功能:
- 记录故障现象和来源,故障事件源会在接收到故障事件后将现象和来源写入 AbnormalSpec 中。
- 维护故障恢复的状态机,故障事件源、故障分析链、故障恢复链会在对故障恢复后将结果更新到 AbnormalStatus 中。
- 在节点上或容器内执行探测指令,如运行命令或者发送 HTTP 请求,并将结果输出到 AbnormalStatus 中。
- 故障分析链将 Abnormal 逐个发送至故障分析器,故障分析器分析后输出 Abnormal,故障分析链对输出的 Abnormal 进行验证后决定下一步流程。如果 Abnormal 被成功识别则更新 AbnormalStatus 并将 Abnormal 发往故障恢复链。如果无法识别或者发生错误则更新 AbnormalStatus 并等待人工干预。
- 故障恢复链将 Abnormal 逐个发送至故障恢复器,故障恢复器恢复后输出 Abnormal,故障恢复链对输出的 Abnormal 进行验证后决定下一步流程。如果 Abnormal 被成功恢复则更新 AbnormalStatus。如果无法恢复或者发生错误则更新 AbnormalStatus 并等待人工干预。
Abnormal
Abnormal 是故障诊断恢复平台中故障事件源、故障分析链、故障恢复链之间通信的接口,用于描述故障。
Field | Description | Scheme | Required |
---|---|---|---|
metadata | API 资源元数据。 | metav1.ObjectMeta | false |
spec | 故障的来源和现象说明。支持用户自定义字段。 | AbnormalSpec | true |
status | 故障当前的状态。由故障事件源、故障分析链、故障恢复链维护,用户无法自行修改。 | AbnormalStatus | true |
AbnormalSpec
Field | Description | Scheme | Required |
---|---|---|---|
source | 故障的来源。该字段支持 Log、KubernetesEvent、PrometheusAlert、Probe 和 Custom。 | string | true |
log | 表示故障的日志详细信息,对应 source 字段的 Log。 | Log | false |
kubernetesEvent | 表示故障的 Kubernetes Event 详细信息,对应 source 字段的 KubernetesEvent。 | corev1.Event | false |
prometheusAlert | 表示故障的 Prometheus Alert 详细信息,对应 source 字段的 PrometheusAlert。 | PrometheusAlert | false |
nodeProbe | 用户自定义的节点故障探测 Probe,支持 Probe 类型故障。 | NodeProbe | false |
podProbe | 用户自定义的容器故障探测 Probe,支持 Probe 类型故障。 | PodProbe | false |
skipDiagnosis | 跳过故障分析步骤。 | bool | false |
skipRecovery | 跳过故障恢复步骤。 | bool | false |
nodeName | Abnormal 所在节点名。 | string | false |
assignedDiagnosers | 指定进行诊断的故障诊断器列表。 | []NamespacedName | false |
assignedRecoverers | 指定进行恢复的故障恢复器列表。 | []NamespacedName | false |
assignedInformationCollectors | 指定进行信息采集的信息采集器列表。 | []NamespacedName | false |
context | 用于扩展的上下文信息,支持 Custom 类型故障。 | runtime.RawExtension | false |
Log
Field | Description | Scheme | Required |
---|---|---|---|
filePath | 日志文件的绝对路径。 | string | true |
logEntry | 日志中表示故障的条目。 | string | true |
PrometheusAlert
Field | Description | Scheme | Required |
---|---|---|---|
labels | Alert 的标签。 | labels.Labels | true |
annotations | Alert 的注解。 | labels.Labels | true |
startsAt | 告警的开始时间 | metav1.Time | false |
endsAt | 告警的结束时间 | metav1.Time | false |
generatorURL | 告警生成者的 URL | string | false |
NodeProbe
Field | Description | Scheme | Required |
---|---|---|---|
name | 执行 Probe 的 Node。 | string | true |
timeoutSeconds | Probe 执行超时时间。 | int32 | false |
exec | Exec 命令。 | corev1.ExecAction | false |
httpGet | HTTP 请求。 | corev1.HTTPGetAction | false |
tcpSocket | TCP 探活。 | corev1.TCPSocketAction | false |
PodProbe
Field | Description | Scheme | Required |
---|---|---|---|
namespace | 执行 Probe 的 Pod 命名空间。 | string | true |
name | 执行 Probe 的 Pod。 | string | true |
container | 执行 Probe 的容器。 | string | true |
timeoutSeconds | Probe 执行超时时间。 | int32 | false |
exec | Exec 命令。 | corev1.ExecAction | false |
httpGet | HTTP 请求。 | corev1.HTTPGetAction | false |
tcpSocket | TCP 探活。 | corev1.TCPSocketAction | false |
AbnormalStatus
Field | Description | Scheme | Required |
---|---|---|---|
identifiable | 表示该故障为可以被故障分析器识别的故障。 | bool | true |
recoverable | 表示该故障为可以被故障恢复器恢复的故障。 | bool | true |
conditions | 描述故障恢复流程中关键点的状况。 | []AbnormalCondition | false |
phase | 故障的当前阶段。该字段支持 InformationCollecting、Diagnosing、Recovering、Succeeded、Failed、Unknown。 | string | false |
message | 表示当前故障恢复阶段的可读信息。用于输出故障原因、故障恢复建议等。 | string | false |
reason | 表示当前故障恢复阶段的简短信息。 | string | false |
output | Exec 命令、HTTP 请求、TCP 探活的输出。 | string | false |
startTime | 表示当前故障开始被诊断的时间。 | metav1.Time | false |
diagnoser | 成功执行的故障诊断器。 | NamespacedName | false |
recoverer | 成功执行的故障恢复器。 | NamespacedName | false |
context | 用于扩展的上下文信息,支持 Custom 类型故障。 | runtime.RawExtension | false |
AbnormalCondition
Field | Description | Scheme | Required |
---|---|---|---|
type | 故障状况的类型。 | string | true |
status | 故障状况的状态。该字段支持 True、False、Unknown。 | string | true |
lastTransitionTime | 上一次状况的状态变化时间。 | metav1.Time | false |
message | 表示当前状况的状态变化原因的可读信息。 | string | false |
reason | 表示当前状况的状态变化原因的简短信息。 | string | false |
NamespacedName
Field | Description | Scheme | Required |
---|---|---|---|
namespace | API 资源的命名空间。 | string | false |
name | API 资源的名称。 | string | true |
故障事件源
故障事件源是获取故障事件的接口,大致可分为以下几类,每一类都需要实现故障事件源接口:
- 日志:日志是获悉集群发生故障的重要手段,通过监听内核、Kubernetes 以及 Docker 日志中的异常字段可以在第一时间发现故障并进行处理。
- Prometheus:Prometheus 满足云原生体系中绝大部分组件的监控需求,大部分组件的内部异常可由 Prometheus 接口暴露。
- Event:Kubernetes 中的事件支持更细致的故障上报机制。
- CRD:CRD 用于自定义故障,用户可以自定义进行扩展。
故障事件源在消费日志、Prometheus 报警和 Event 后会生成 Abnormal 故障事件并发往故障分析链。用户也可以直接通过 CRD 来创建故障事件。
故障分析链
故障分析链是一个调用链框架,本身并不包含故障分析的逻辑,用户需要实现故障分析的具体逻辑并注册到故障分析链中。故障分析链从故障事件源接收故障事件并将故障事件逐一传入被注册的故障分析器中,当故障事件能够被某个故障分析器识别则中止调用并交由该逻辑进行处理。如果故障无法被任何故障分析器识别则直接获取相关排障信息并报警。故障分析器一般是一个 HTTP 服务器。用户可以将自定义故障诊断分析的脚本放入特定路径,故障分析链会动态的获取自定义故障诊断分析文件。
故障分析器在无法识别 Abnormal 故障事件时返回错误,故障分析器在成功识别 Abnormal 故障事件后变更 Status 字段。故障分析链在某个故障分析器成功识别 Abnormal 故障事件后将 Abnormal 故障事件发往故障恢复链。故障分析器在执行诊断时可以通过调用信息采集器获取更多信息。
信息管理器
当故障分析或恢复流程较复杂时,需要从其他接口获取更多信息用于故障的诊断和确认。此时故障分析器或故障恢复器可以调用信息采集器获取更多信息。常用的信息采集器包括 eBPF、Golang 剖析文件、Java 虚拟机工具等。信息采集器一般是一个 HTTP 服务器。故障分析器或故障恢复器需要保证能够正确处理从信息采集器获取的信息。信息管理器用于管理多个信息采集器,用户通过请求信息管理器获取额外信息,信息管理器在接收到请求后会转发到相应的信息采集器中。
故障恢复链
和故障分析链相似,故障恢复链也是一个调用链框架,本身并不包含故障恢复的逻辑,用户需要实现故障恢复的具体逻辑并注册到故障恢复链中。故障恢复链从故障分析链接收故障事件并将故障事件逐一传入被注册的故障恢复器中,当故障能够被某个故障恢复器识别则中止调用并交由该逻辑进行处理。如果故障无法被任何故障恢复器识别则报错中止。故障恢复器一般是一个 HTTP 服务器。用户可以将自定义故障恢复的脚本放入特定路径,故障恢复链会动态的获取自定义故障恢复文件。
典型用例
社区 Issue 3529 中记录的 Bug 会导致 Docker 18.06 及以下版本因为 Shim 的死锁而无法正常终止容器。当该故障出现时可以通过以下步骤实现该故障的诊断恢复:
- 实现故障事件源:获取当前 Terminating 状态的 Pod,当该类 Pod 存在时创建表示该故障的 CRD,标记
.spec.nodeName
字段为该 Pod 所处节点。 - 实现故障分析器:首先通过进程树查找到该容器对应的 Shim 进程。然后向该 Shim 进程发送 SIGUSR1 信号获取栈信息,在栈信息中查找
reaper.go
相关函数以确定问题原因。 - 实现故障恢复器:杀死该容器对应的 Shim 进程进行恢复。
作者简介:
黄久远,网易杭州研究院轻舟云原生资深研发工程师。专注于云原生以及分布式系统等领域,作为核心成员参与了网易集团内部容器化落地以及网易轻舟容器平台产品化。目前主要负责网易轻舟云原生故障自动诊断系统的设计、开发以及商业化产品输出等工作。