除錯 Knative 事件¶
這是一份關於如何除錯無法運作的 Knative 事件設定的演進文件。
對象¶
本文檔適用於熟悉 Knative 事件物件模型的人員。您不需要是專家,但確實需要大致了解事物如何組合在一起。
先決條件¶
範例¶
本指南使用一個範例,其中包含一個將事件傳送到函式的事件來源。
請參閱 example.yaml 以取得完整的 YAML。若要讓本指南中的任何命令正常運作,您必須套用 example.yaml
kubectl apply --filename example.yaml
觸發事件¶
每當 Kubernetes Event
在 knative-debug
命名空間中發生時,就會發生 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
依賴其後端的頻道實作
,並且在某種程度上依賴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
產生的 Pod。
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
。
Service
¶
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 控制器超出本文檔的範圍。
服務控制器¶
Kubernetes Service 控制器,負責控制 svc
,不在本文檔的討論範圍內。
通道控制器 (Channel Controller)¶
並沒有單一的 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 Controller)¶
每個來源 (Source) 都會有自己的控制器。 src
是一個 ApiServerSource
,因此其控制器為
kubectl --namespace knative-eventing get pod -l app=sources-controller
這實際上是一個單一的二進制檔,運行多個來源控制器,其中重要的是 ApiServerSource 控制器。
ApiServerSource 控制器¶
ApiServerSource
控制器與 Eventing 的其他一些來源控制器在同一個二進制檔中運行。它是
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 Controller)¶
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
的行。
資料平面 (Data Plane)¶
整個 控制平面 看起來都很正常,但我們仍然沒有收到任何事件。現在我們需要調查資料平面。
Knative 事件的傳輸路徑如下
-
事件由
src
產生。 -
在這個案例中,它是由於 Kubernetes
Event
觸發的,但就 Knative 而言,Source
是從頭 (denovo,無中生有) 產生事件。 -
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)¶
通道分發器是接收 POST 將事件推送到 Channel
,然後在接收到事件時 POST 到這些 Channel
的訂閱者的組件。對於本範例中使用的 in-memory-channel
,有一個單一的二進制檔處理所有 in-memory-channel
Channel
的接收和分發端。
首先,我們將檢查分發器的日誌,看看是否有任何明顯的問題
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
,它正在返回 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"}
那麼我們就知道發佈到 http://svc.knative-debug.svc.cluster.local/
時出現了問題。