Categories
程式開發

OpenFaaS的無狀態微服務介紹


本文作者Alex將帶我們了解了OpenFaaS的最新改進,也就是對無狀態微服務的完整支持,並給出了一個用Ruby和Sinatra編寫的留言簿示例。

目前,我們已經在OpenFaaS 0.9.0中合併並發布了對無狀態微服務的支持。這意味著工程師現在可以利用OpenFaaS中簡單而強大的開發人員體驗,打造出管理你所有FaaS函數和微服務的單一平台。整套體驗的內容從CLI到Prometheus度量,再到內置的自動擴展都包括在內。甚至縮放到零都得到了支持。本文中,我將引領大家部署一個用Ruby和Sinatra編寫的留言簿示例,這個留言簿由MySQL支持,使用Kubernetes部署到OpenFaaS上。

為什麼要這樣做?

現代的雲原生微服務和FaaS函數之間有很多重疊部分,我將在下一部分中具體說明。 OpenFaaS一直支持在Windows上運行任何容器或進程,無論是FaaS函數、AWS CLI、ImageMagick甚至是PowerShell都可以。社區在短時間內提出了兩個要求,這兩個要求成為了我們的故事進一步發展的催化劑。

我們在Wireline.io的一位新用戶提出了一項功能請求,希望增強函數的HTTP路由功能。 Wireline希望編寫出無需任何額外更改,就可以同時運行在AWS Lambda和OpenFaaS上的函數。大約在同一時間,GitLab的首席執行官Sid Sijbrandi聯繫了我們,希望了解更多關於無服務器的信息,並想知道如何在GitLab上利用它。 Sid問我,OpenFaaS能否同時用來管理FaaS函數,和他的團隊更熟悉的一些微服務(例如Sinatra應用)。他對在空閒時縮放到零的能力表現出了特別的興趣。

在開始研究示例,展示如何將Sid的請求付諸實踐之前,我們先來看一些背景知識。

什麼是函數?

在了解什麼是“無狀態微服務”之前,我們先來看”FaaS函數”的定義。我在2017年1月發表的博客文章:函數即服務(FaaS)中給出了具體定義。

函數往往會:

  • 調用短期函數(Lambda有默認的1秒超時設置)
  • 不發布TCP服務——經常訪問第三方服務或資源
  • 往往是臨時的/事件驅動的,例如響應Webhooks
  • 應該平穩地應對流量高峰
  • 不管是什麼名稱,都會運行在由流動的、非確定性的基礎架構支持的服務器上
  • 正常工作時會簡化複雜的事物
  • 有幾個相關的主題:基礎架構管理、批處理、訪問控制、定義、擴展和依賴關係

從第一篇文章發表以來,我拓展了自己最初的觀察,將函數的定義重寫為一系列屬性。

函數是:

  • 無狀態的
  • 短暫的
  • 自動擴展的
  • 單一用途的

函數是無狀態的,因為它們不依賴內部存儲器、狀態機、存儲的文件或掛載的捲。根據外部服務,對函數的每次調用應導致相同的最終結果。函數不必嚴格冪等,但在嚴格冪等時更易管理。

函數是短暫的,因為在任何時候都可以用相同的副本替換它們,而不會影響行為。這一屬性意味著我們可以用相同的方式管理所有函數——檢查函數的運行狀況、查看它們的生命週期、日誌記錄,乃至監控工作等都可以用同一種方法來處理。

函數能自動從最小副本數擴展到最大副本數,甚至自動降到零並再次擴展上來,以匹配需求或節省資源。

函數是單一用途的,但必須以常識為準。我們用不著每次在代碼中編寫 function x() {} 或 def x: 時都創建一個新的FaaS函數。函數的單一用途可能是“一條員工記錄的CRUD”“格式化此IBAN”或“使用機器學習模型識別此圖像的內容”。

只要你編寫了至少一個無服務器函數,那麼你就會意識到入口點往往已經從你那裡抽像出來了。你只需編寫一個處理程序——然後所有依賴項都以一種通用格式表示,例如Node.js的package.json或Python的requirements.txt文件。

下面是一個Node.js函數的示例:

"use strict"

module.exports = (context, callback) => {
    callback(undefined, {status: "done"});
}

作為開發人員,你用不著了解用於引導處理程序的機制——這是無聊的重複性細節,你可以讓FaaS框架或工具包來操心這些事情。
我們看到了類似的抽像模式,也看到了諸如Sinatra、Django和Express.js之類的微服務框架中隱藏無聊細節的現象。一種尺寸很少能滿足所有需求,因此每種語言或運行時都有多種選擇。

什麼是無狀態微服務?

無狀態微服務是一種微服務,它可以像FaaS函數一樣進行部署,並可以通過FaaS框架或OpenFaaS這樣的平台來管理。因此,在OpenFaaS CLI、Gateway API或UI中不需要特殊的路由(route)、標誌(flag)或過濾器(filter)。

OpenFaaS的無狀態微服務介紹 1

就OpenFaaS組件而言,函數可以用任何語言編寫並打包在Docker映像中。它必須通過8080端口上的HTTP提供內容,並將鎖定文件寫入/tmp/.lock。如果你的函數或服務檢測出自身的異常,那麼你可以刪除鎖定文件,OpenFaaS將重新啟動/重新安排你的函數。

OpenFaaS有一個Ruby語言模板,可用於創建Ruby FaaS函數。 Ruby無狀態微服務是使用https://rubyonrails.org/)(https://rubyonrails.org/“>Ruby on Rails(、Sinatra或其他Ruby微服務框架創建的Ruby微服務。其中的主要區別在於,與FaaS函數相比你要做的工作更多了。現在,你必須管理自己的Dockerfile、狀況檢查和路由。

Sinatra是Ruby的DSL或框架,用於快速構建微服務。

下面是官方網站上的hello-world示例:

require 'sinatra'

get '/frank-says' do
  'Put this in your pipe & smoke it!'
end

如果我們將該文件另存為main.rb並運行gem install sinatra,然後運行ruby main.rb,則將在默認端口5678上啟動一個Web服務器,然後可以跳轉至URL:http://127.0.0.1:5678/frank-says上。

OpenFaaS CLI可以模板化、構建和部署這個微服務。然後,OpenFaaS平台將跟踪這個微服務的調用指標,並將其自動放大、縮小甚至降為零並再次放大。

創建Sinatra無狀態微服務

下面我們來使用Sinatra創建一個無狀態微服務。

你首先需要準備一些工具:

  • 適用於Mac/Linux/Windows的Docker
  • 一個Docker Hub帳戶,或其他Docker倉庫的帳戶
  • OpenFaaS和CLI——可選Kubernetes或Swarm

創建一個Hello World服務

首先創建一個新文件夾並生成一個dockerfile函數。其中dockerfile模板會告訴OpenFaaS CLI,在不應用其他任何腳手架或模板的情況下運行Docker構建,你必須提供自己的Dockerfile。

$ mkdir -p sinatra-for-openfaas/ 
  && cd sinatra-for-openfaas/

$ faas-cli new --prefix=alexellis2 --lang dockerfile frank-says

用你的Docker Hub帳戶或另一個Docker倉庫替換alexellis2。一個Docker映像將被推送到這裡,這是build/faas-cli up命令的一部分。

這將創建兩個文件,就像你用faas-cli new上列出的一種語言創建函數時一樣:

./frank-says/Dockerfile
./frank-says.yml

創建一個Gemfile和main.rb文件:
./frank-says/main.rb:

require 'sinatra'

set :port, 8080
set :bind, '0.0.0.0'

open('/tmp/.lock', 'w') { |f|
  f.puts "Service started"
}

get '/' do
  'Frank has entered the building'
end

get '/logout' do
  'Frank has left the building'
end

有關OpenFaaS負載的注意事項:

  • 它們必須綁定到TCP端口8080
  • 準備接收流量時,它們必須寫一個文件/tmp/.lock。

./frank-says/Gemfile:

source 'https://rubygems.org'
gem "sinatra"

可以在此文件中添加任意gems列表。
現在將./frank-says/Dockerfile替換為:

FROM ruby:2.4-alpine3.6
WORKDIR /home/app
COPY    .   .
RUN bundle install
RUN addgroup -S app 
  && adduser app -S -G app
RUN chown app:app -R /home/app
WORKDIR /home/app

HEALTHCHECK --interval=5s CMD ( -e /tmp/.lock ) || exit 1

USER app
CMD ("ruby", "main.rb")

Dockerfile執行以下操作:

  • 添加非root用戶
  • 添加Ruby源代碼和Gemfile,然後安裝sinatra gem
  • 添加一個間隔為5秒的健康檢查
  • 設置啟動命令

部署示例

現在你已經做好了準備,可以使用OpenFaaS CLI構建和部署示例了。

  • 使用你的帳戶詳細信息登錄
$ docker login
  • 運行up命令,該命令是build、push和deploy的別名。
$ faas-cli up --yaml frank-says.yml

Deploying: frank-says.

Deployed. 200 OK.
URL: http://127.0.0.1:8080/function/frank-says

使用curl調用你的微服務,或在Web瀏覽器中查看它:

$ curl http://127.0.0.1:8080/function/frank-says/
Frank has entered the building.

你也可以嘗試自定義路徑:

$ curl http://127.0.0.1:8080/function/frank-says/logout
Frank has left the building.

你可以嘗試更新消息或添加其他路由,然後再次運行faas-cli以重新部署微服務。
現在檢查faas-cli list,能看到每次訪問微服務時調用計數會隨之增加。

$ faas-cli list
Function                        Invocations     Replicas
frank-says                      5               1

觸發自動擴展

現在,我們可以使用簡單的bash for循環來觸發自動擴展:

$ for i in {1..10000}
do
  sleep 0.01 
  && curl http://127.0.0.1:8080/function/frank-says 
  && echo
done

在另一個窗口中輸入:watch faas-cli list或者定期運行faas-cli list 。自動擴展生效後,你應該能看到Invocations的值增加,並且Replicas值也會增加。

Function                        Invocations     Replicas
frank-says                      702             4

當bash for循環完成或使用Ctrl + C取消它時,你會看到副本數減少到1。
你也可以在以下網址使用OpenFaaS UI監視和調用微服務:http://127.0.0.1:8080

OpenFaaS的無狀態微服務介紹 2

閱讀有關自動擴展的更多信息,包括如何配置最小、最大和零副本縮放參數

部署帶有MySQL的Sinatra留言簿

$ git clone https://github.com/openfaas-incubator/openfaas-sinatra-guestbook 
  && cd openfaas-sinatra-guestbook

在./sql.yml中配置你的MySQL數據庫細節。如果你還沒有MySQL,那麼只需花幾分鐘使用Kubernetes上的helm或docker run,以及官方Docker映像就能部署完畢。

$ cp sql.example.yml sql.yml

最後部署留言簿:

$ faas-cli up

http://127.0.0.1:8080/function/guestbook

使用上面命令提供的URL來訪問微服務。
在UI中登錄留言簿,完成後,你可以隨時發佈到/function/guestbook/reset來重置MySQL表。

OpenFaaS的無狀態微服務介紹 3

留言簿代碼的狀態存儲在MySQL表單中,這意味著它可以隨時重新啟動而不會丟失數據。這是FaaS函數和無狀態微服務的一個關鍵屬性。如果OpenFaaS添加了我們代碼的其他副本——每個副本都將具有相同的環境視圖,因為它依賴於外部數據庫來獲取其數據。

啟用零縮放

要啟用縮放到零的功能,只需按照文檔說明啟用faas-idler。

然後在你的stack.yml文件中添加一個標籤,以告知OpenFaaS你的函數可以進行零縮放:

    labels:
      com.openfaas.scale.zero: true

最後,通過faas-cli up重新部署留言簿。一旦檢測到空閒狀態,faas-idler現在會將你的函數縮放到零副本。默認的空閒時間設置為5分鐘,可以在部署時配置。
回到Sid最初的問題,我們已經部署了一個用Ruby編寫的無狀態微服務,該服務將在空閒時縮放到零,還能及時擴展以服務流量。管理它的方式與我們現有的FaaS函數完全相同,這意味著你可以專注於構建重要的內容,而不必操心Kubernetes或Docker Swarm的內部細節。

總結

現在,我們已經使用MySQL、ebs視圖、Bootstrap和Sinatra部署了一個簡單的hello-world Sinatra服務和一個更完整的留言簿示例。接下來你就可以開始使用OpenFaaS簡化開發人員工作流程了——你可以使用FaaS函數,或者簡化微服務的管理工作。

作者介紹:

Alex Ellis([email protected])是@openfaas的創始人。

原文鏈接https://www.openfaas.com/blog/stateless-microservices/