调试 Knative Eventing¶
这是一份关于如何调试无法正常工作的 Knative Eventing 设置的不断更新的文档。
受众¶
本文档适用于熟悉 Knative Eventing 对象模型的人。您无需成为专家,但需要大致了解各部分如何协同工作。
先决条件¶
示例¶
本指南使用了一个示例,该示例由一个向函数发送事件的事件源组成。

请参阅 example.yaml 获取完整的 YAML。要使本指南中的任何命令生效,您必须应用 example.yaml
kubectl apply --filename example.yaml
触发事件¶
每当 knative-debug 命名空间中发生 Kubernetes Event 时,Knative 事件就会发生。我们可以使用以下命令触发此操作
kubectl --namespace knative-debug run to-be-deleted --image=image-that-doesnt-exist --restart=Never
# 5 seconds is arbitrary. We want K8s to notice that the Pod needs to be scheduled and generate at least one event.
sleep 5
kubectl --namespace knative-debug delete pod to-be-deleted
然后我们可以看到 Kubernetes Event(请注意,这些不是 Knative 事件!)
kubectl --namespace knative-debug get events
这应该会产生类似以下内容的输出
LAST SEEN FIRST SEEN COUNT NAME KIND SUBOBJECT TYPE REASON SOURCE MESSAGE
20s 20s 1 to-be-deleted.157aadb9f376fc4e Pod Normal Scheduled default-scheduler Successfully assigned knative-debug/to-be-deleted to gke-kn24-default-pool-c12ac83b-pjf2
我的事件在哪里?¶
您已应用 example.yaml 并且正在检查 fn 的日志
kubectl --namespace knative-debug logs -l app=fn -c user-container
但您没有看到任何事件到达。问题出在哪里?
检查已创建的资源¶
首先要检查的是所有已创建的资源,它们的状态是否包含 ready true?
我们将尝试从最基本的部件开始确定原因
fn-Deployment在 Knative 内部没有依赖项。svc-Service在 Knative 内部没有依赖项。chan-Channel依赖于其支持的channel implementation,并且在某种程度上依赖于sub。src-Source依赖于chan。sub-Subscription依赖于chan和svc。
fn¶
kubectl --namespace knative-debug get deployment fn -o jsonpath='{.status.availableReplicas}'
我们希望看到 1。如果您没有看到,那么您需要调试 Deployment。status 中是否有任何明显的错误?
kubectl --namespace knative-debug get deployment fn --output yaml
如果错误不明显,那么您需要调试 Deployment,这超出了本文档的范围。
验证 Pod 是否 Ready
kubectl --namespace knative-debug get pod -l app=fn -o jsonpath='{.items[*].status.conditions[?(@.type == "Ready")].status}'
这应该返回 True。如果不是,请尝试使用 Kubernetes 应用程序调试 指南调试 Deployment。
svc¶
kubectl --namespace knative-debug get service svc
我们只想确保此项存在并且名称正确。如果它不存在,那么您可能需要重新应用 example.yaml。
验证它指向预期的 Pod。
svcLabels=$(kubectl --namespace knative-debug get service svc -o go-template='{{range $k, $v := .spec.selector}}{{ $k }}={{ $v }},{{ end }}' | sed 's/.$//' )
kubectl --namespace knative-debug get pods -l $svcLabels
这应该返回一个 Pod,如果您检查,它是由 fn 生成的。
chan¶
chan 使用 in-memory-channel。这是一个非常基本的通道,其故障模式很少会在 chan 的 status 中体现出来。
kubectl --namespace knative-debug get channel.messaging.knative.dev chan -o jsonpath='{.status.conditions[?(@.type == "Ready")].status}'
这应该返回 True。如果不是,请获取完整资源
kubectl --namespace knative-debug get channel.messaging.knative.dev chan --output yaml
如果 status 完全缺失,则表示 in-memory-channel 控制器有问题。请参阅 通道控制器。
接下来验证 chan 是否可寻址
kubectl --namespace knative-debug get channel.messaging.knative.dev chan -o jsonpath='{.status.address.hostname}'
这应该返回一个 URI,可能以“.cluster.local”结尾。如果不是,则意味着在协调过程中出现了问题。请参阅 通道控制器。
我们将验证 chan 创建的两个资源是否存在并处于 Ready 状态。
服务¶
chan 创建了一个 K8s Service。
kubectl --namespace knative-debug get service -l messaging.knative.dev/role=in-memory-channel
它的规范完全不重要,因为 Istio 会忽略它。它只需要存在,以便 src 可以向其发送事件。如果它不存在,则表示在 chan 协调过程中出现了问题。请参阅 通道控制器。
src¶
src 是一个 ApiServerSource。
首先我们将验证 src 是否正在写入 chan。
kubectl --namespace knative-debug get apiserversource src -o jsonpath='{.spec.sink}'
这应该返回 map[apiVersion:messaging.knative.dev/v1 kind:Channel name:chan]。如果不是,则 src 设置不正确,需要修复其 spec。修复应该像更新其 spec 以具有正确的 sink 一样简单(请参阅 example.yaml)。
现在我们知道 src 正在发送到 chan,让我们验证它是否 Ready。
kubectl --namespace knative-debug get apiserversource src -o jsonpath='{.status.conditions[?(.type == "Ready")].status}'
sub¶
sub 是从 chan 到 fn 的 Subscription。
验证 sub 是否 Ready
kubectl --namespace knative-debug get subscription sub -o jsonpath='{.status.conditions[?(.type == "Ready")].status}'
这应该返回 True。如果不是,请查看所有状态条目。
kubectl --namespace knative-debug get subscription sub --output yaml
控制器¶
每个资源都有一个控制器在监视它。截至目前,它们在写入失败状态消息和事件方面做得不好,因此我们需要查看控制器的日志。
注意
控制 fn 的 Kubernetes Deployment 控制器超出了本文档的范围。
服务控制器¶
控制 svc 的 Kubernetes Service 控制器超出了本文档的范围。
通道控制器¶
没有一个单一的 Channel 控制器。相反,每个 Channel CRD 都有一个控制器。chan 使用 InMemoryChannel Channel CRD,其控制器是
kubectl --namespace knative-eventing get pod -l messaging.knative.dev/channel=in-memory-channel,messaging.knative.dev/role=controller --output yaml
使用以下命令查看其日志
kubectl --namespace knative-eventing logs -l messaging.knative.dev/channel=in-memory-channel,messaging.knative.dev/role=controller
特别注意日志级别为 warning 或 error 的任何行。
源控制器¶
每个 Source 都将拥有自己的控制器。src 是一个 ApiServerSource,因此其控制器是
kubectl --namespace knative-eventing get pod -l app=sources-controller
这实际上是一个运行多个 Source 控制器的单一二进制文件,其中包括 ApiServerSource 控制器。
ApiServerSource 控制器¶
ApiServerSource 控制器与 Eventing 中的一些其他 Source 控制器在同一个二进制文件中运行。它是
kubectl --namespace knative-debug get pod -l eventing.knative.dev/sourceName=src,eventing.knative.dev/source=apiserver-source-controller
使用以下命令查看其日志
kubectl --namespace knative-debug logs -l eventing.knative.dev/sourceName=src,eventing.knative.dev/source=apiserver-source-controller
特别注意日志级别为 warning 或 error 的任何行。
订阅控制器¶
Subscription 控制器控制 sub。它尝试解析 Channel 应将事件发送到的地址,一旦解析,就将这些地址注入到 Channel 的 spec.subscribable 中。
kubectl --namespace knative-eventing get pod -l app=eventing-controller
使用以下命令查看其日志
kubectl --namespace knative-eventing logs -l app=eventing-controller
特别注意日志级别为 warning 或 error 的任何行。
数据平面¶
整个 控制平面 看起来很健康,但我们仍然没有收到任何事件。现在我们需要调查数据平面。
Knative 事件遵循以下路径
-
事件由
src生成。 -
在这种情况下,它是由于 Kubernetes
Event触发的,但就 Knative 而言,Source正在从头(从无到有)生成事件。 -
src将事件 POST 到chan的地址,即http://chan-kn-channel.knative-debug.svc.cluster.local。 -
Channel Dispatcher 接收请求并内省 Host 头部以确定它对应于哪个
Channel。它看到它对应于knative-debug/chan,因此将请求转发给sub中定义的订阅者,特别是svc,它由fn支持。 -
fn接收请求并记录下来。
我们将按照事件应传播的顺序调查组件。
通道调度器¶
Channel Dispatcher 是接收将事件推送到 Channel 的 POST 请求,然后在收到事件时将 POST 请求发送给这些 Channel 的订阅者的组件。对于此示例中使用的 in-memory-channel,有一个单一的二进制文件处理所有 in-memory-channel Channel 的接收和调度两端。
首先我们将检查 Dispatcher 的日志,看看是否有任何明显的问题
kubectl --namespace knative-eventing logs -l messaging.knative.dev/channel=in-memory-channel,messaging.knative.dev/role=dispatcher -c dispatcher
理想情况下,我们会看到类似以下内容的行
{"level":"info","ts":"2019-08-16T13:50:55.424Z","logger":"inmemorychannel-dispatcher.in-memory-channel-dispatcher","caller":"provisioners/message_receiver.go:147","msg":"Request mapped to channel: knative-debug/chan-kn-channel","knative.dev/controller":"in-memory-channel-dispatcher"}
{"level":"info","ts":"2019-08-16T13:50:55.425Z","logger":"inmemorychannel-dispatcher.in-memory-channel-dispatcher","caller":"provisioners/message_dispatcher.go:112","msg":"Dispatching message to http://svc.knative-debug.svc.cluster.local/","knative.dev/controller":"in-memory-channel-dispatcher"}
{"level":"info","ts":"2019-08-16T13:50:55.981Z","logger":"inmemorychannel-dispatcher.in-memory-channel-dispatcher","caller":"provisioners/message_receiver.go:140","msg":"Received request for chan-kn-channel.knative-debug.svc.cluster.local","knative.dev/controller":"in-memory-channel-dispatcher"}
这表明请求正在被接收并发送到 svc,svc 返回 2XX 响应代码(可能是 200、202 或 204)。
但是如果我们看到类似以下内容
{"level":"info","ts":"2019-08-16T16:10:16.859Z","logger":"inmemorychannel-dispatcher.in-memory-channel-dispatcher","caller":"provisioners/message_receiver.go:140","msg":"Received request for chan-kn-channel.knative-debug.svc.cluster.local","knative.dev/controller":"in-memory-channel-dispatcher"}
{"level":"info","ts":"2019-08-16T16:10:16.859Z","logger":"inmemorychannel-dispatcher.in-memory-channel-dispatcher","caller":"provisioners/message_receiver.go:147","msg":"Request mapped to channel: knative-debug/chan-kn-channel","knative.dev/controller":"in-memory-channel-dispatcher"}
{"level":"info","ts":"2019-08-16T16:10:16.859Z","logger":"inmemorychannel-dispatcher.in-memory-channel-dispatcher","caller":"provisioners/message_dispatcher.go:112","msg":"Dispatching message to http://svc.knative-debug.svc.cluster.local/","knative.dev/controller":"in-memory-channel-dispatcher"}
{"level":"error","ts":"2019-08-16T16:10:38.169Z","logger":"inmemorychannel-dispatcher.in-memory-channel-dispatcher","caller":"fanout/fanout_handler.go:121","msg":"Fanout had an error","knative.dev/controller":"in-memory-channel-dispatcher","error":"Unable to complete request Post http://svc.knative-debug.svc.cluster.local/: dial tcp 10.4.44.156:80: i/o timeout","stacktrace":"knative.dev/eventing/pkg/provisioners/fanout.(*Handler).dispatch\n\t/Users/xxxxxx/go/src/knative.dev/eventing/pkg/provisioners/fanout/fanout_handler.go:121\nknative.dev/eventing/pkg/provisioners/fanout.createReceiverFunction.func1.1\n\t/Users/i512777/go/src/knative.dev/eventing/pkg/provisioners/fanout/fanout_handler.go:95"}
那么我们知道在 POST 到 http://svc.knative-debug.svc.cluster.local/ 时出现了问题。