在上一篇文章中,我討論了Knative用於快速部署和自動調整無伺服器容器。如果您希望您的服務由HTTP調用同步觸發,那麼Knative服務是很好的選擇。然而,在沒有伺服器的微服務世界中,異步觸發器更加常見和有用。這時,Knative三項賽就開始發揮作用了。
在Knative系列的第2部分中,我將介紹Knative事件並展示一些來自我的Knative教程的示例,這些示例介紹了如何將它與各種服務集成在一起。
什麼是Knative Eventing?
Knative事件處理與Knative服務密切相關,它為鬆散耦合的事件驅動服務提供了基元。典型的Knatives事件架構是這樣的:
主要有4個組成部分:
Source(也稱為Producer)從實際的源中讀取事件,並將事件向下轉發到一個通道,或者直接轉發到一個服務,這種情況比較少見。Channel從源接收事件,保存到其底層存儲(稍後詳細介紹),並向所有訂閱者展開。訂閱連接一個通道和一個服務(或另一個通道)。服務(也稱為消費者)是使用事件流的Knative服務。讓我們更詳細地看看這些。
來源,渠道和訂閱
Knative事件的最終目標是將事件從源路由到服務,這是通過我前面提到的原語實現的:源、通道和訂閱。
Source從實際源讀取事件並將它們轉發到下遊。到目前為止,Knative支持從Kubernetes、GitHub、谷歌雲發布/訂閱、AWS SQS主題、容器和CronJobs讀取事件。
一旦事件被拉入Knative,它就需要保存到內存中,或者保存到更持久的地方,比如Kafka或谷歌雲發布/訂閱。這發生在通道上。它有多個實現來支持不同的選項。
從Channel將事件傳遞給所有感興趣的Knative服務或其他通道。這可以是一對一的,也可以是扇出的。訂閱決定了這種交付的性質,並充當通道和Knative服務之間的橋梁。
現在我們已經了解了Knative三項賽的基礎知識,讓我們來看一個具體的例子。
Hello World事件
對於Hello World事件,讓我們讀取來自谷歌雲發布/訂閱的消息並在Knative服務中註銷它們。我的你好世界三項賽教程有所有的細節,但在這裡重述,這是我們需要設置:
從谷歌雲發布/訂閱讀取消息的GcpPubSubSource。將消息保存在內存中的通道。連結頻道到Knative服務的訂閱。接收消息並註銷的Knative服務。gcp-pubsub-source。yaml定義了GcpPubSubSource。它指向一個名為測試的發布/訂閱主題,它有訪問發布/訂閱的憑證,並指定應該像這樣轉發哪個頻道事件:
apiVersion: sources.eventing.knative.dev/v1alpha1kind: GcpPubSubSourcemetadata:name: testing-sourcespec:gcpCredsSecret: # A secret in the knative-sources namespacename: google-cloud-keykey: key.jsongoogleCloudProject: knative-atamel # Replace thistopic: testingsink:apiVersion: eventing.knative.dev/v1alpha1kind: Channelname: pubsub-test
接下來,我們使用Channel .yaml定義通道。在這種情況下,我們只是在內存中保存消息:
apiVersion: eventing.knative.dev/v1alpha1kind: Channelmetadata:name: pubsub-testspec:provisioner:apiVersion: eventing.knative.dev/v1alpha1kind: ClusterChannelProvisionername: in-memory-channel
繼續創建源和通道:
kubectl apply -f gcp-pubsub-source.yamlkubectl apply -f channel.yaml
你可以看到源和通道被創建,有一個源pod也被創建:
kubectl get gcppubsubsource NAME AGE testing-source 1mkubectl get channel NAME AGE pubsub-test 1mkubectl get pods NAME READY STATUS gcppubsub-testing-source-qjvnk-64fd74df6b-ffzmt 2/2 Running
最後,我們可以創建Knative服務,並使用訂閱伺服器中的訂閱將其連結到subscriber.yaml文件:
apiVersion: serving.knative.dev/v1alpha1 kind: Servicemetadata: name: message-dumper-csharp spec: runLatest: configuration: revisionTemplate: spec: container: # Replace {username} with your actual DockerHub image: docker.io/{username}/message-dumper-csharp:v1--- apiVersion: eventing.knative.dev/v1alpha1 kind: Subscription metadata: name: gcppubsub-source-sample-csharp spec: channel: apiVersion: eventing.knative.dev/v1alpha1 kind: Channel name: pubsub-test subscriber: ref: apiVersion: serving.knative.dev/v1alpha1 kind: Service name: message-dumper-csharp
如您所見,message-dump -csharp只是一個普通的Knative服務,但它是通過其訂閱的Knative事件異步觸發的。
kubectl apply -f subscriber.yamlservice.serving.knative.dev "message-dumper-csharp" created subscription.eventing.knative.dev "gcppubsub-source-sample-csharp" configured
一旦你kubectl apply所有的yaml文件,你可以使用gcloud發送消息到發布/訂閱主題:
gcloud pubsub topics publish testing --message="Hello World"
你應該可以看到pods 的服務創建:
kubectl get podsNAME READYgcppubsub-testing-source-qjvnk-64fd74df6b-ffzmt 2/2 Running 0 3mmessage-dumper-csharp-00001-deployment-568cdd4bbb-grnzq 3/3 Running 0 30s
服務將Base64編碼的消息記錄在Data下面:
info: message_dumper_csharp.Startup[0]C# Message Dumper received message: {"ID":"198012587785403","Data":"SGVsbG8gV29ybGQ=","Attributes":null,"PublishTime":"2019-01-21T15:25:58.25Z"}info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]Request finished in 29.9881ms 200
查看我的Hello World事件教程,了解更多關於步驟和實際代碼的細節。
與雲存儲和Vision API集成
當您試圖以無縫的方式連接完全不相關的服務時,Knative事件就會真正地發揮作用。在我的集成與視覺API教程中,我展示了如何使用Knative事件連接谷歌雲存儲和谷歌雲視覺API。
雲存儲是一種全球可用的數據存儲服務。可以將bucket配置為在保存映像時發出發布/訂閱消息。然後,我們可以使用Knative事件偵聽這些發布/訂閱消息,並將它們傳遞給Knative服務。在服務中,我們使用圖像進行一個Vision API調用,並使用機器學習從中提取標籤。所有的細節都在教程中進行了解釋,但是我想在這裡指出一些事情。
首先,在Knative中,所有的出站流量在預設情況下都會被阻塞。這意味著在默認情況下,您甚至不能從Knative服務調用Vision API。這最初讓我感到驚訝,所以請確保配置了網絡出站訪問。
其次,無論何時將圖像保存到雲存儲中,它都會發出CloudEvents。Knative三項賽通常與CloudEvents一起使用。你需要將傳入的請求解析為CloudEvents,並提取你需要的信息,如事件類型和圖像文件的位置:
var cloudEvent = JsonConvert.DeserializeObject<CloudEvent>(content); var eventType = cloudEvent.Attributes["eventType"]; var storageUrl = ConstructStorageUrl(cloudEvent);
有了這些信息,很容易為圖像構造存儲URL並使用該URL進行Vision API調用。完整的原始碼在這裡解釋,但這裡是相關的部分:
var visionClient = ImageAnnotatorClient.Create();var labels = await visionClient.DetectLabelsAsync(Image.FromUri(storageUrl), maxResults: 10);
一旦代碼準備好了,我們就可以通過定義一個ubscriber.yaml將服務掛接到Knative事件上。它和以前很相似。我們正在重用現有的源和通道,所以我們不必重新創建它們。我們只是創建一個新的訂閱指向我們新的Knative服務與願景API容器:
apiVersion: serving.knative.dev/v1alpha1kind: Servicemetadata:name: vision-csharpspec:runLatest:configuration:revisionTemplate:spec:container:# Replace {username} with your actual DockerHubimage: docker.io/{username}/vision-csharp:v1---apiVersion: eventing.knative.dev/v1alpha1kind: Subscriptionmetadata:name: gcppubsub-source-vision-csharpspec:channel:apiVersion: eventing.knative.dev/v1alpha1kind: Channelname: pubsub-testsubscriber:ref:apiVersion: serving.knative.dev/v1alpha1kind: Servicename: vision-csharp
一旦使用kubectl apply創建了所有內容,無論何時將映像保存到雲存儲桶中,都應該看到該映像的Knative服務日誌標籤。
例如,我有一張我最喜歡的地方的照片:
當我把圖片保存到桶裡時,我可以在日誌中看到Vision API中的以下標籤:
info: vision_csharp.Startup[0]This picture is labelled: Sea,Coast,Water,Sunset,Horizoninfo: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]Request finished in 1948.3204ms 200
可以看到,我們使用Knative事件將一個服務(雲存儲)連接到另一個服務(Vision API)。這只是一個例子,但可能性是無限的。在本教程的翻譯API集成部分中,我展示了如何將發布/訂閱連接到翻譯API。
這就是Knative三項賽。在本系列的下一篇也是最後一篇文章中,我將討論Knative構建。