FAAS原理白話就是,用戶提交一段函數代碼(如js代碼),我們後臺把代碼拼接爲dockerfile(根據用戶的函數語言,自動組裝(如js代碼需要js環境,nginx),後臺打一個鏡像,然後k8s集羣根據用戶的配置需求,跑這個docker鏡像。用戶刪除函數,直接把鏡像銷燬。
以下爲開源FAAS:Openwhisk的基本使用
Openwhisk是屬於Apache基金會的開源Faas計算平臺,由IBM在2016年公佈並貢獻給開源社區。IBM Cloud本身也提供完全託管的OpenWhisk Faas服務IBM Cloud Function。從業務邏輯來看,OpenWhisk同AWS Lambda一樣,爲用戶提供基於事件驅動的無狀態的計算模型,並直接支持多種編程語言。
OpenWhisk特點:
• 高性能,高擴展性的分佈式FaaS計算平臺
• 函數的代碼及運行時全部在Docker容器中運行,利用Docker engine實現FaaS函數運行的管理、負載均衡、擴展.
• OpenWhisk所有其他組件(如:API網關,控制器,觸發器等)也全部運行在 Docker容器中。這使得OpenWhisk全棧可以很容易的部署在任意IaaS/PaaS平臺上。
• 相比其他FaaS實現(比如OpenFaaS),OpenWhisk更像是一套完整的Serverless 解決方案,除了容器的調用和函數的管理,OpenWhisk 還包括了用戶身份驗證/鑑權、函數異步觸發等功能。
目前支持的語言: Nodejs, Python, Java, php, Ruby, Go, Rust, dotnet, Ballerina, blackBoxes。
安裝
整個安裝需要提前安裝java跟nodejs。
• 安裝java
下載JDK
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
將JDK安裝包上傳到服務器上並解壓
$ tar -zxvf jdk-8u171-linux-x64.tar.gz
#切換到當前用戶目錄下面,編輯配置文件
$ cd ~
$ vim .bash_profile
在.bash_profile文件最後添加
JAVA_HOME=/home/tomcat/jdk1.8.0_171
CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib
PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin
export JAVA_HOME CLASSPATH PATH
#驗證
$ java -version
• 安裝nodejs
下載Node.js安裝包
wget https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.xz
#解壓文件
tar xvf node-v10.15.3-linux-x64.tar.xz
創建軟鏈接
ln -s /home/node-v10.15.3-linux-x64.tar.xz/bin/node /usr/local/bin/node
ln -s /home/node-v10.15.3-linux-x64.tar.xz/bin/npm /usr/local/bin/npm
查看node, npm版本
node -v
npm -v
如果成功,則安裝完成
• 編譯openwhisk
如果沒有代碼,可以從本地上傳或從git clone下載
yum install git
git clone下來
git clone https://github.com/apache/incubator-openwhisk.git openwhisk
切換到openwhisk目錄,運行下面命令
$ ./gradlew :core:standalone:build
• 配置OpenWhisk Cli工具:下載https://github.com/apache/openwhisk-cli
上傳到服務器解壓, 解壓
設置API HOST
wsk property set --apihost http://172.17.0.1:3233
設置auth
wsk property set --auth 789c46b1-71f6-4ed5-8c54-816aa4f8c502
可以通過以下命令獲取當前的auth
wsk property get --auth
• 在.\bin目錄下面會有相應的可執行文件。
java -jar openwhisk-standalone.jar
會有如下輸出:
____ ___ _ _ _ _ _
/\ \ / _ \ _ __ ___ _ __ | | | | |__ (_)___| | __
/\ /__\ \ | | | | '_ \ / _ \ '_ \| | | | '_ \| / __| |/ /
/ \____ \ / | |_| | |_) | __/ | | | |/\| | | | | \__ \ <
\ \ / \/ \___/| .__/ \___|_| |_|__/\__|_| |_|_|___/_|\_\
\___\/ tm |_|
Running pre flight checks ...
Local Host Name: 172.17.0.1
Local Internal Name: 172.17.0.1
[ OK ] 'docker' cli found. (Docker version 19.03.6, build 369ce74a3c)
[ OK ] 'docker' version 19.3.6 is newer than minimum supported 18.3.0
[ OK ] 'docker' is running.
[ OK ] 'wsk' cli found. (2019-09-23T17:46:38.323+0000)
[ WARN ] Configure wsk via below command to connect to this server as [guest]
wsk property set --apihost 'http://172.17.0.1:3233' --auth '23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP'
[ OK ] Server port [3233] is free
服務起來後設置提示的命令:設置apihost和auth
wsk property set --apihost 'http://172.17.0.1:3233' --auth '23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP'
• 運行Hello world
創建hello.js文件
/**
* Hello world as an OpenWhisk action.
*/
function main(params) {
var name = params.name || 'World';
return {payload: 'Hello, ' + name + '!'};
}
創建action
$ wsk action create hellotest hello.js
ok: created action hellotest
$ wsk action invoke hellotest --result
{
"playload": "hello world"
}
系統流程
先介紹一下 OpenWhisk 中從事件觸發到函數執行完畢的流程。 OpenWhisk 中,代碼是基於事件(Event)觸發的。事件產生於事件源(feed),可以用於觸發函數的事件多種多樣:可以是IoT設備傳感器發出的信號,可以是一個 Github repo的push,也可以是最簡單的一個前端HTTP 請求。事件與對應的函數代碼,通過規則(Rule)綁定。通過匹配事件對應的規則,OpenWhisk會觸發對應的行爲(Action)。值得注意的是,多個Action 可以串聯,完成複雜的操作。
整體架構
參考鏈接:https://github.com/apache/openwhisk/blob/master/docs/about.md
- 面向用戶的REST API(Nginx): OpenWhisk 的核心繫統通過Rest API 接收函數觸發和函數的CRUD請求。如一個函數觸發的POST請求格式如下···POST /api/v1/namespaces/$userNamespace/actions/myAction ···此處的nginx 服務器主要用於接收 HTTPS 請求(SSL termination),並將處理後的 HTTP 請求直接轉發給控制器(Controller).
- 控制器(Controller, 真正進入系統): 真正開始處理請求的地方。控制器是用 Scala 語言實現的,並提供了對應的 REST API,接收 Nginx 轉發的請求。Controller 分析請求內容,進行下一步處理。
- CouchDB(身份驗證和鑑權):控制器首先需要驗證用戶的身份和權限。用戶的身份信息(credentials)保存在CouchDB的用戶身份數據庫(subjects database)中。驗證無誤後,控制器進行下一步處理。
- CouchDB(得到對應的Action的代碼及配置): 確認用戶的身份後,控制器需要從 CouchDB中讀取將要被觸發的函數(OpenWhisk將要執行的代碼片段抽象成爲 Action,爲了簡便,此處直接稱之爲函數)。函數對應的數據存儲在CouchDB的whisk 數據庫,主要包含要被執行的代碼、默認參數、被執行代碼的權限、及CPU/內存使用限制。
- Consul和負載均衡:到了這一步,控制器已經有了觸發函數所需要的全部信息,在將數據發送給觸發器(Invoker)之前,控制器需要和Consul確認,從Consul 獲取處於空閒狀態的觸發器的地址。Consul 是一個開源的服務註冊/發現系統,在 OpenWhisk中Consul負責記錄跟蹤所有觸發器的狀態信息。當控制器向Consul發出請求,Consul從後臺隨機選取一個空閒的觸發器信息,並返回。
- 觸發請求送進Kafka: Kafka 充當了Controller和Invoker之間的緩存,當後端 Invoker 負載過大,沒有及時處理Kafka數據流中的請求時,Controller 依然可以將請求送入Kafka,無需阻塞當前線程。同時所有送進Kafka 的請求消息都會被以log的形式的形式保存在文件系統中,即使系統癱瘓,已經由 Controller發出的請求也不會丟失。
- 觸發器運行用戶代碼: 觸發器從對應的 Kafka topic 中接收控制器傳來的請求,並執行響應代碼。OpenWhisk 的觸發器是構建在 Docker 之上的,每一個函數觸發都運行在一個獨立的 Docker 容器之內.
- CouchDB 保存運行結果: 觸發器執行結果最終會被保存在 CouchDB 中的 whisk 數據庫裏, 保存的格式如下:
{
"activationId": "31809ddca6f64cfc9de2937ebd44fbb9",
"response": {
"statusCode": 0,
"result": {
"hello": "world"
}
},
"end": 1474459415621,
"logs": [
"2016-09-21T12:03:35.619234386Z stdout: Hello World"
],
"start": 1474459415595,
}
保存結果包括用戶函數的返回值,及日誌記錄。對異步觸發用戶,可以通過步驟6中返回的activationID取回函數運行結果。同步觸發的的結果和異步觸發一樣保存在 CouchDB裏,控制器在得到觸發結束的確認後,從CouchDB 中取得運行結果,直接返回給用戶。