Fn 函式佈署流程涉及 Docker 映像構建和推播至倉函式庫。首先,使用 fn build 命令構建映像,再以 fn deploy 佈署至指定應用程式,同時 Fn 會自動更新版本號。佈署後,fn routes list 命令可驗證佈署結果,並透過 curl 命令與函式互動,觀察 HTTP 回應中的 Fn_call_id 等資訊。除了 Java,Fn 也支援 Go 等 runtime。利用 fn init --runtime go 初始化 Go 函式,目錄中包含 func.gofunc.yamltest.json 等檔案。func.go 撰寫函式程式碼,需注意錯誤處理和日誌記錄,錯誤訊息應寫入 STDERR 並以非零碼離開。佈署 Go 函式流程與 Java 類別似,使用 fn deploy 佈署,fn call 進行呼叫。

Fn 函式佈署與測試詳解

在前面的章節中,我們已經瞭解瞭如何使用 Fn 專案建立和佈署函式。本章節將探討如何佈署函式並與之互動,同時介紹如何使用不同的 runtime(如 Go)來建立函式。

佈署函式

當我們完成了函式的開發後,下一步就是將其佈署到 Fn 伺服器上。佈署的過程涉及構建 Docker 映像並將其推播到指定的 Docker 倉函式庫。

佈署流程

  1. 構建函式:首先,我們使用 fn build 命令來構建函式的 Docker 映像。

    $ fn build
    Building image hello:0.0.1
    Function hello:0.0.1 built successfully.
    
  2. 佈署函式:接著,使用 fn deploy 命令將構建好的映像佈署到指定的應用程式中。

    $ fn deploy --app demo --registry chanwit
    Deploying hello to app: demo at path: /hello
    Bumped to version 0.0.2
    Building image chanwit/hello:0.0.2
    Pushing chanwit/hello:0.0.2 to docker registry...
    

    在佈署過程中,Fn 會自動增加映像的版本號,構建新的 Docker 映像,並將其推播到指定的 Docker 倉函式庫。

  3. 驗證佈署結果:佈署完成後,可以使用 fn routes list 命令來列出應用程式中的所有路由,以驗證函式是否成功佈署。

    $ fn routes list demo
    path    image                  endpoint
    /hello  chanwit/hello:0.0.2  localhost:8080/r/demo/hello
    

與函式互動

佈署完成後,我們可以使用 curl 命令來與函式互動。Fn 會將函式暴露為 HTTP 端點,因此我們可以像存取普通的 HTTP 端點一樣與之互動。

$ curl -v localhost:8080/r/demo/hello
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /r/demo/hello HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 13
< Content-Type: text/plain
< Fn_call_id: 01C8SPGSEK47WGG00000000000
< Xxx-Fxlb-Wait: 78.21μs
< Date: Sat, 17 Mar 2018 10:01:43 GMT
<
* Connection #0 to host localhost left intact
Hello, world!

在回應的 HTTP 頭中,我們可以看到一些額外的資訊,如 Fn_call_idXxx-Fxlb-Wait。這些資訊對於呼叫跟蹤和效能監控非常有用。

使用 Go Runtime 建立函式

除了 Java 之外,Fn 還支援其他多種 runtime,包括 Go。讓我們來看看如何使用 Go 建立函式。

初始化 Go 函式

使用 fn init 命令並指定 --runtime go 來建立一個新的 Go 函式。

$ fn init --runtime go hello_go
Creating function at: /hello_go
Runtime: go
Function boilerplate generated.
func.yaml created.

建立完成後,我們可以看到函式目錄下的檔案結構:

$ cd hello_go
$ tree .
.
├── func.go
├── func.yaml
└── test.json

其中,func.go 是函式的主程式,func.yaml 是 Fn 的函式描述檔案,而 test.json 則包含了用於功能測試的測試韌體。

函式程式碼

func.go 中,我們可以看到函式的實際程式碼。以下是一個簡單的例子,展示瞭如何使用 Go 來處理輸入的 JSON 資料。

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Message struct {
    Name string
}

func main() {
    m := &Message{Name: "world"}
    err := json.NewDecoder(os.Stdin).Decode(m)
    if err != nil {
        fmt.Fprintf(os.Stderr, "err JSON Decode: %s\n", err.Error())
        os.Exit(250)
    }
    fmt.Printf(`{"success": "Hello %s"}`, m.Name)
    os.Exit(0)
}

錯誤處理和日誌記錄

在函式程式碼中,我們需要注意錯誤處理和日誌記錄。Fn 會將寫入 STDERR 的訊息儲存到日誌中,因此我們應該將錯誤訊息寫入 STDERR。同時,函式應該以非零的離開碼離開,以指示錯誤。

佈署和測試 Go 函式

佈署 Go 函式的過程與佈署 Java 函式類別似。我們可以使用 fn deploy 命令來佈署函式,並使用 fn call 命令來呼叫函式。

$ fn deploy --app demo --registry chanwit
Deploying hello_go to app: demo at path: /hello_go
...
$ echo '{"Name": "chanwit"}' | fn call demo /hello_go
{"success": "Hello chanwit"}

如果我們在呼叫函式時沒有提供正確的輸入,函式將會傳回錯誤。

$ fn call demo /hello_go
{"error":{"message":"container exit code 250"}}
ERROR: error calling function: status 502

這個例子展示瞭如何在 Fn 中使用 Go runtime 建立和佈署函式,以及如何處理錯誤和記錄日誌。

內容解密:
  1. 佈署流程:詳細介紹瞭如何使用 fn buildfn deploy 命令來構建和佈署函式。
  2. 與函式互動:展示瞭如何使用 curl 命令來與佈署好的函式互動,並解析了回應中的 HTTP 頭資訊。
  3. Go Runtime:介紹瞭如何使用 Go runtime 建立函式,包括初始化函式、編寫函式程式碼、錯誤處理和日誌記錄。
  4. 佈署和測試 Go 函式:演示瞭如何佈署和測試使用 Go runtime 建立的函式。

透過本章節的學習,讀者應該能夠掌握如何在 Fn 中佈署和管理函式,以及如何使用不同的 runtime(如 Go)來建立函式。這些技能對於開發高效、可靠的 serverless 應用程式非常重要。

Fn 函式管理與佈署詳解:從日誌檢查到 Docker Swarm 佈署

檢查呼叫日誌與錯誤處理

要檢視所有的呼叫日誌,可以使用 fn calls 命令。需要注意的是,這裡的命令是 calls,而不是其他拼寫。fn calls list 命令可以接受應用程式的名稱作為引數,主要關注的屬性包括 ID狀態

呼叫日誌範例

以下範例展示了兩個呼叫日誌,第一個是錯誤的,第二個是成功的,按照逆時間順序排列:

$ fn calls list demo
ID: 01C8VRGN9R47WGJ00000000000
App: demo
Route: /hello_go
Created At: 2018-03-18T05:15:04.376Z
Started At: 2018-03-18T05:15:04.738Z
Completed At: 2018-03-18T05:15:07.519Z
Status: success

ID: 01C8VRFE3647WGE00000000000
App: demo
Route: /hello_go
Created At: 2018-03-18T05:14:24.230Z
Started At: 2018-03-18T05:14:24.566Z
Completed At: 2018-03-18T05:14:27.375Z
Status: error

擷取特定呼叫ID的日誌

現在,我們選取第二個呼叫ID來取得日誌訊息。檢索日誌的命令是 fn logs get,它需要應用程式名稱和呼叫ID:

$ fn logs get demo 01C8VRFE3647WGE00000000000
err JSON Decode: EOF

上述日誌訊息是Go程式印出到 os.Stderr 的內容。

日誌檢查重點

  • 使用 fn calls list 檢視所有呼叫日誌
  • 重點關注 ID狀態 屬性
  • 使用 fn logs get 檢索特定呼叫ID的日誌

在 Docker Swarm 上佈署 Fn

建立網路與資料儲存

首先,我們需要在 Swarm 範圍的網路上建立一個 Fn 叢集。為了穩定性,我們使用 weaveworks/net-plugin 作為基礎網路。請注意,網路必須是可連線的,且子網路必須在 10.32.0.0/16 的範圍內。例如,10.32.3.0/24 是合適的:

$ docker network create \
  --driver weaveworks/net-plugin:2.1.3 \
  --attachable \
  --subnet 10.32.3.0/24 \
  fn_net

建立資料函式庫儲存卷

接下來,我們為資料儲存建立一個卷。為了展示一個生產級的設定,我們使用 MySQL 作為儲存,而不是預設的 SQLite3。這樣可以讓我們水平擴充套件 Fn 伺服器的數量。

$ docker volume create mysql_vol

啟動 MySQL 例項

以下是啟動 MySQL 例項的 docker run 命令。我們將例項連線到之前建立的 fn_net 網路,並指定網路別名以確保服務可以透過 mysql 名稱存取。所有的環境變數都用於設定使用者名稱、密碼和預設資料函式庫 fn_db。不要忘記將 mysql_vol 卷繫結到容器內的 /var/lib/mysql,以確保資料在容器移除後仍然存在:

$ docker run \
  --detach \
  --name mysql \
  --network fn_net \
  --network-alias mysql \
  -e MYSQL_DATABASE=fn_db \
  -e MYSQL_USER=func \
  -e MYSQL_PASSWORD=funcpass \
  -e MYSQL_RANDOM_ROOT_PASSWORD=yes \
  -v mysql_vol:/var/lib/mysql \
  mysql

啟動 Fn 伺服器

接下來的步驟是啟動 Fn 伺服器。本文示範如何啟動兩個 Fn 伺服器,它們指向同一個日誌儲存(MySQL)。每個 Fn 伺服器都連線到 fn_net。第一個例項被命名為 fn_0。Fn 伺服器需要 FN_DB_URL 環境變數指向外部的日誌儲存,這可以是 PostgreSQL 或 MySQL。只需按照以下命令提供完整的 URL:

$ docker run --privileged \
  --detach \
  --network fn_net \
  --network-alias fn_0 \
  --name fn_0 \
  -e "FN_DB_URL=mysql://func:funcpass@tcp(mysql:3306)/fn_db" \
  fnproject/fnserver

啟動多個 Fn 伺服器例項

讓我們啟動另一個 Fn 伺服器例項 fn_1。基本上,這應該在不同的節點(實體或虛擬)上完成:

$ docker run --privileged \
  --detach \
  --network fn_net \
  --network-alias fn_1 \
  --name fn_1 \
  -e "FN_DB_URL=mysql://func:funcpass@tcp(mysql:3306)/fn_db" \
  fnproject/fnserver

設定 Fn LB 負載平衡器

在設定所有 Fn 伺服器例項後,現在是時候將它們聚合起來。我們使用 Fn LB 作為所有 Fn 伺服器前面的負載平衡器。與其他容器一樣,我們只需建立它並將其連線到 fn_net。由於它是 FaaS 閘道器,我們還將其內部埠 8081 對應到主機的 8080 埠,以便 Fn CLI 可以連線到 Fn 叢集而無需任何特殊設定。網路別名僅在其他服務需要連線到此閘道器時使用。

接下來,將 Fn 伺服器節點列表作為命令列引數傳遞。目前,節點列表組態只允許直接傳遞給容器。只需將它們放在 <name>:<port> 格式中,以逗號分隔:

$ docker run --detach \
  --network fn_net \
  --network-alias fnlb \
  --name fnlb \
  -p 8080:8081 \
  fnproject/fnlb:latest --nodes fn_0:8080,fn_1:8080

驗證佈署

現在是時候驗證一切是否正常執行。我們使用 docker ps 命令檢查所有容器:

$ docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Command}}\t{{.Ports}}"
CONTAINER ID   NAMES      COMMAND                  PORTS
ce4f8e9bc300   fnlb       "./fnlb --nodes fn_0..."   0.0.0.0:8080->8081/tcp
dae4fb892b4d   fn_1       "preentry.sh ./fnser..."   2375/tcp
8aefeb9e19ef   fn_0       "preentry.sh ./fnser..."   2375/tcp
67bd136c331a   mysql      "docker-entrypoint.s..."   3306/tcp

使用 Fn UI 進行監控

Fn UI 是為 Fn 建立的使用者介面專案。它提供了一個簡單的儀錶板,包含易於使用的時間序列圖,可以近乎實時地監控函式的執行情況。要啟動 Fn UI,我們建立並將容器連線到 fn_net,同時將埠釋出到 4000。Fn UI 需要 Fn 伺服器的 URL。但由於它們都在 Fn LB 後面,所以我們只需將 FN_API_URL 設定為 Fn LB 的位置。

請注意,它們都在 fn_net 網路內相互連線,因此 URL 顯示為 http://fnlb:8081,使用的是 fnlb 在網路內的真實名稱和埠:

$ docker run --detach \
  --network fn_net \
  --network-alias fnui \
  -p 4000:4000 \
  -e "FN_API_URL=http://fnlb:8081" \
  fnproject/ui

存取 Fn UI 儀錶板

設定 Fn UI 例項後,瀏覽到 localhost:4000 以開啟儀錶板。我們將看到所有應用程式列在那裡,如下圖所示。應用程式可以在那裡進行管理,例如建立或刪除。如果您不希望螢幕始終自動重新整理,請取消選中 Auto refresh

執行函式

選擇應用程式後,您可以透過點選 Run Function 按鈕在儀錶板中執行函式,如下圖所示。如果執行函式時發生錯誤並失敗,例如,會彈出通知。要執行函式,請以 JSON 格式輸入 Payload 並按下 Run 按鈕。

重點整理

  1. 日誌檢查:使用 fn calls listfn logs get 命令檢查呼叫日誌和錯誤。
  2. Docker Swarm 佈署:建立網路和資料函式庫卷,啟動 MySQL 和 Fn 伺服器例項,使用 Fn LB 進行負載平衡。
  3. Fn UI 監控:使用 Fn UI 進行函式監控和執行。

佈署架構圖

  graph LR
    A[使用者端] -->|HTTP/HTTPS|> B[Fn LB]
    B -->|負載平衡|> C[Fn Server 1]
    B -->|負載平衡|> D[Fn Server 2]
    C -->|存取資料函式庫|> E[MySQL 資料函式庫]
    D -->|存取資料函式庫|> E
    F[Fn UI] -->|監控|> C
    F -->|監控|> D

圖表翻譯: 此圖示展示了 Fn 的佈署架構。使用者端透過 Fn LB 存取 Fn Server,Fn Server 進一步存取 MySQL 資料函式庫。同時,Fn UI 用於監控 Fn Server 的狀態。