OpenWhisk 是一個事件驅動的 Serverless 平台,允許開發者將程式碼封裝成動作,並透過 API gateway 或其他事件觸發執行。當請求到達 API gateway 後,會經過控制器驗證身份並查詢動作資訊。控制器接著將請求傳送到 Kafka 訊息佇列,由呼叫器接收並執行對應的 Docker 容器。執行結果會儲存至 CouchDB,並回傳給使用者。理解這個流程有助於開發者更有效率地使用 OpenWhisk。文章也介紹了 SuraWhisk UI,一個方便管理 OpenWhisk 動作和名稱空間的圖形化介面工具,讓開發者更容易上手。此外,文章還說明如何使用 Docker Swarm 模式操作 FaaS 叢集,以及如何利用 EC2 Spot 例項降低營運成本,提供更全面的 Serverless 架構佈署和管理策略。
建置 OpenWhisk 動作的流程與實作細節
在前面的章節中,我們已經瞭解瞭如何使用 Docker 封裝 OpenWhisk 動作。本章節將探討 OpenWhisk 的內部流程,特別是在呼叫動作時的內部機制,以及如何建立和呼叫 Docker 容器作為 OpenWhisk 動作。
呼叫流程解析
OpenWhisk 是一個事件驅動的平台,任何型別的事件都可以被捕捉和解釋。在本例中,我們將重點介紹透過向閘道器傳送直接請求來觸發的事件。呼叫流程從一個根據 HTTP 的請求開始,並將其傳送到 API 閘道器。例如,我們可以使用 wsk 命令列工具來發起這種請求。
請求處理流程
- API 閘道器接收請求:API 閘道器接收到請求後,會將該呼叫轉發給後端的控制器。
- 控制器處理請求:控制器是 OpenWhisk 的核心元件之一,它使用 Scala 語言編寫,並利用 Akka 和 Spray 框架實作了一組 REST API。控制器接受所有型別的請求,如果接收到 POST 請求,它將其解釋為對 OpenWhisk 動作的呼叫。
- 身份驗證和授權:控制器首先進行身份驗證和授權檢查。它會查詢憑證資訊並與儲存在 CouchDB 例項中的資料進行驗證。
- 動作查詢和呼叫:如果一切正常,控制器會查詢有關動作的資訊,包括它是什麼型別以及如何呼叫它。在我們的例子中,我們使用 Docker 作為動作的基本單元,因此控制器會發現我們的動作是一個黑盒子,並準備好呼叫它。
使用 Kafka 進行訊息處理
- 請求轉發給 Kafka:控制器不會直接向呼叫器發出請求,而是將請求傳送給 Kafka 叢集,這是訊息系統的骨幹。使用 Kafka 可以防止呼叫丟失,並透過在系統繁忙時排隊呼叫使系統更加強壯。
- 訊息持久化:控制器將包含呼叫動作所需的所有資訊的訊息釋出到 Kafka。該訊息由 Kafka 持久化,以便在系統當機時可以重放。
- 取得啟用 ID:一旦 Kafka 取得了訊息,控制器就會收到一個啟用 ID,以便稍後取得呼叫的結果。
呼叫器處理呼叫
- 呼叫器訂閱訊息:在 Kafka 的另一側,一組呼叫器訂閱了請求的訊息。一旦訊息在佇列中可用,呼叫器就會收到通知。然後,呼叫器會執行實際的工作,即呼叫實際的 Docker 容器。
- 儲存結果:呼叫器取得結果後,將其儲存在 CouchDB 例項中,使用的啟用 ID 與之前相同。
實作範例:建立和呼叫 OpenWhisk 動作
現在,讓我們嘗試建立和呼叫我們在前面的章節中構建的 C 和 Go 函式。首先,我們將使用 wsk action create 命令建立一個動作:
$ wsk -i action create --docker chanwit/whisk_c whisk_c
ok: created action whisk_c
如果一切順利,wsk 將告訴我們 ok: created action。接下來,我們將使用 wsk action invoke 命令呼叫動作。invoke 命令接受一個或多個 --param 來將引數傳遞給動作。我們還可以傳遞 --result 以同步取得結果。結果當然是以 JSON 格式傳回的:
$ wsk -i action invoke --param key value --result whisk_c
{
"args": {
"key": "value"
},
"msg": "Hello from C program!"
}
我們將再次嘗試,這次使用 Go 程式。首先,建立動作:
$ wsk -i action create --docker chanwit/whisk_go whisk_go
ok: created action whisk_go
然後,使用 wsk action invoke 呼叫動作:
$ wsk -i action invoke --param hello world --result whisk_go
{
"keys": [
"hello"
],
"message": "Hello from Go",
"values": [
"world"
]
}
正如我們所見,使用 Docker 封裝動作基本上簡化了整個過程,從動作準備、建立到呼叫。
取得啟用結果
每次呼叫動作時,OpenWhisk 都會為其建立一個啟用記錄。要檢視啟用記錄,我們可以在不使用 --result 引數的情況下呼叫動作,例如:
$ wsk -i action invoke --param hello world whisk_go
ok: invoked /guest/whisk_go with id 6ba2c0fd6f4348b8a2c0fd6f4388b864
ID 6ba2c0fd6f4348b8a2c0fd6f4388b864 稱為啟用 ID。我們現在可以使用 wsk activation get 命令取得啟用記錄。在啟用 ID 之後新增欄位名稱將過濾它以僅顯示該欄位。以下示例僅顯示啟用記錄 6ba2c0 的 response 欄位:
$ wsk -i activation get 6ba2c0fd6f4348b8a2c0fd6f4388b864 response
ok: got activation 6ba2c0fd6f4348b8a2c0fd6f4388b864, displaying field response
{
"status": "success",
"statusCode": 0,
"success": true,
"result": {
"keys": [
"hello"
],
"message": "Hello from Go",
"values": [
"world"
]
}
}
在啟用記錄中,JSON 結果放置在 result 鍵下。您可以觀察到所有資料都正確地序列化為 JSON 並記錄在那裡。
Dockerfile 分析
RUN CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' main.go
# Build using the base image for whisk docker action
FROM openwhisk/dockerskeleton
ENV FLASK_PROXY_PORT 8080
COPY --from=0 /go/src/app/main /action/exec
CMD ["/bin/bash", "-c", "cd actionProxy && python -u actionproxy.py"]
程式碼解密:
- CGO_ENABLED=0 go build:這行命令是用來編譯 Go 程式碼的。透過設定
CGO_ENABLED=0,我們確保編譯過程不依賴於 C 編譯器,從而產生一個靜態的可執行檔。 - FROM openwhisk/dockerskeleton:這行指令告訴 Docker 使用
openwhisk/dockerskeleton作為基礎映像來構建新的映像。這是 OpenWhisk 提供的一個基礎映像,用於執行 Docker 動作。 - ENV FLASK_PROXY_PORT 8080:這行指令設定了一個環境變數
FLASK_PROXY_PORT為8080。這個變數可能被 OpenWhisk 的代理服務使用,以指定服務的埠。 - COPY –from=0 /go/src/app/main /action/exec:這行指令將之前構建階段生成的
main可執行檔複製到新的映像中的/action/exec路徑。這裡的--from=0指定了複製來源是第一個構建階段(即編譯 Go 程式碼的階段)。 - CMD ["/bin/bash", “-c”, “cd actionProxy && python -u actionproxy.py”]:這行指令定義了容器啟動時要執行的預設命令。它會進入
actionProxy目錄並執行 Python 指令碼actionproxy.py。
OpenWhisk 呼叫流程
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 程式碼解密:
rectangle "HTTP 請求" as node1
rectangle "轉發請求" as node2
rectangle "身份驗證與授權" as node3
rectangle "查詢動作資訊" as node4
rectangle "使用 Kafka 傳送訊息" as node5
rectangle "訊息持久化" as node6
rectangle "通知呼叫器" as node7
rectangle "呼叫 Docker 容器" as node8
rectangle "傳回結果" as node9
rectangle "儲存結果" as node10
node1 --> node2
node2 --> node3
node3 --> node4
node4 --> node5
node5 --> node6
node6 --> node7
node7 --> node8
node8 --> node9
node9 --> node10
@enduml圖表翻譯:
此圖表展示了 OpenWhisk 中一個動作的呼叫流程。首先,客戶端透過 HTTP 請求向 API 閘道器發起呼叫。API 閘道器將請求轉發給控制器,控制器負責身份驗證和授權,並查詢動作的資訊。隨後,控制器透過 Kafka 傳送訊息給呼叫器,呼叫器負責實際呼叫 Docker 容器並執行動作。執行結果最終被儲存在 CouchDB 中。
OpenWhisk 平台具有很大的靈活性和擴充套件性,未來可以結合更多的技術和工具來增強其功能。例如,可以探索使用不同的訊息佇列系統,或者開發更先進的身份驗證和授權機制。此外,還可以研究如何進一步最佳化 OpenWhisk 的效能和可擴充套件性,以滿足更大規模的應用需求。
使用者介面與SuraWhisk介紹
目前尚未有開放原始碼的OpenWhisk入口網站可供使用。為了讓開發者更方便使用OpenWhisk,SuraWhisk作為一個開放原始碼專案被開發出來並託管在GitHub上。SuraWhisk的原始碼可以在https://github.com/surawhisk/ui 找到。如果不想檢視原始碼,可以直接從預先建置好的Docker映像啟動UI。
啟動SuraWhisk UI
首先,建立一個磁碟區來儲存設定資料。端點及其用於身份驗證的API金鑰將儲存在該磁碟區中:
$ docker volume create surawhisk_vol
然後,可以使用以下命令執行UI:
$ docker run -d -p 8080:8080 -v surawhisk_vol:/root/data surawhisk/ui
SuraWhisk UI啟動後,將瀏覽器指向http://localhost:8080。UI的左側導航欄目前包含三個基本專案:設定、動作和名稱空間。
設定OpenWhisk端點
設定頁面(如圖6.3所示)用於設定OpenWhisk端點及其API金鑰。SuraWhisk容器執行在橋接網路上,因此可以透過Docker的閘道橋接IP(172.17.0.1)存取OpenWhisk的API閘道。也就是說,本地OpenWhisk例項的端點將是https://172.17.0.1/api/v1。目前訪客名稱空間的API金鑰可以透過執行wsk CLI並使用以下命令獲得:
$ wsk property get --auth
whisk auth 23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP
命令的結果提供了一串長字串,表示這是一個whisk auth。將整個字串(23b…IwP)複製並貼上到設定頁面的API金鑰文字方塊中,然後點選儲存按鈕。
內容解密:
此步驟設定了SuraWhisk與OpenWhisk之間的連線。首先,我們需要建立一個Docker磁碟區來持久化儲存設定資料,包括API端點和金鑰。接著,透過Docker執行SuraWhisk UI,並將其連線到剛建立的磁碟區。SuraWhisk UI允許使用者透過圖形介面管理OpenWhisk中的動作和名稱空間。要連線到OpenWhisk例項,需要提供正確的API端點和認證金鑰。這些資訊儲存在由wsk property get --auth命令輸出的認證字串中。
定義和呼叫新函式
可以在Actions/Create頁面(如圖6.4所示)定義一個函式,即OpenWhisk中的動作。本章前面建立的Docker映像將在這裡使用。在下面的範例中,我們建立了一個名為hello的函式作為Docker容器,其映像是chanwit/whisk_c。
建立動作的步驟:
- 在SuraWhisk UI中導航到Actions/Create頁面。
- 填寫動作名稱並選擇適當的Docker映像。
- 點選Create按鈕以建立動作。
建立成功後,會彈出一個對話方塊(如圖6.5所示),確認動作已成功建立。
呼叫動作
要呼叫動作,請導航到左側導航欄中的Actions/Invoke選單(如圖6.6所示)。目前名稱空間中的所有動作將列在動作組合方塊中。每次呼叫都可以接受鍵/值對作為動作的引數。這些引數可以透過點選Add按鈕新增。在下面的範例中,book引數被設定為包含值serverless。可以隨時透過點選每個鍵值對的Remove按鈕來移除引數。這些引數將在傳遞給動作之前被編碼為JSON。
呼叫動作的步驟:
- 在SuraWhisk UI中導航到Actions/Invoke頁面。
- 從動作組合方塊中選擇要呼叫的動作。
- 新增必要的引數。
- 點選Invoke按鈕以啟動呼叫程式。
練習題
以下是一些幫助您複習本章內容的問題:
- OpenWhisk的優勢是什麼?
- 請描述OpenWhisk的架構。
- OpenWhisk控制器(Controller)的角色是什麼?
- Kafka在OpenWhisk中的角色是什麼?為什麼它對OpenWhisk很重要?
- 什麼是Invoker?
- Controller和Invoker之間沒有直接連線的原因是什麼?
- 如何在OpenWhisk平台上定義和呼叫一個動作?
- 如何提高Invoker的效能?
操作根據Docker的FaaS叢集
操作和管理自己的叢集是保持系統執行的一大挑戰。雖然無伺服器架構旨在完全解決這個問題,但實際上,在某些情況下,我們仍然需要自行組態和管理伺服器。無伺服器架構與Docker的理念是在減少叢集維護和管理與完全控制叢集之間取得平衡。使用Docker是實作這種平衡的好方法。
使用Docker Swarm模式操作叢集
操作根據Docker的FaaS叢集使用了與操作Docker叢集相同的技術。我們需要混合使用執行獨立Docker容器和利用Docker Swarm模式的技術。本章重點介紹了組態穩定化、如何準備新的入口層、如何使用網路外掛、如何設定日誌系統,以及如何使用Golang指令碼操作叢集。
Docker Swarm模式的優勢:
- 提供叢集管理和容器協調功能。
- 允許跨多台主機佈署和管理容器。
- 支援服務發現和負載平衡。
EC2 Spot例項的使用
使用EC2 Spot例項可以顯著降低成本,有時甚至比使用AWS Lambda或其他雲端函式服務更便宜。因此,使用Spot例項可以在保持成本效益的同時,避免遇到AWS Lambda等服務的限制。
重點整理
在本章中,我們學習瞭如何使用SuraWhisk UI管理OpenWhisk,以及如何操作根據Docker的FaaS叢集。這包括了組態叢集、管理動作和呼叫函式等重要步驟。同時,我們也探討了使用Docker Swarm模式和EC2 Spot例項來最佳化叢集操作和降低成本的方法。這些知識對於在實際環境中佈署和管理無伺服器架構至關重要。
本章重點:
- SuraWhisk UI的使用。
- OpenWhisk中動作的定義和呼叫。
- 根據Docker的FaaS叢集的操作和管理。
- Docker Swarm模式在叢集管理中的應用。
- 使用EC2 Spot例項降低成本。
綜上所述,本章提供了關於OpenWhisk和根據Docker的FaaS叢集操作的全面介紹,為讀者在無伺服器架構領域提供了寶貴的知識和實踐經驗。