本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰! javascript
這是第 106 篇不摻水的原創,想獲取更多原創好文,請搜索公衆號關注咱們吧~ 本文首發於政採雲前端博客:Serverless Custom (Container) Runtimephp
咱們知道 Serverless 能夠理解爲 Serverless = FaaS + BaaS 。Serverless 應用中,對於服務端業務邏輯代碼,開發者是以函數的形式去實現的,即 FaaS(函數即服務)。( Serverless 相關文章能夠看下團隊結合阿里雲 FC 談談我對 FaaS 的理解)html
對於雲廠商的 FaaS 平臺,雖然他們支持多種編程語言及版本的標準運行環境,但畢竟仍是有限的。因此,爲了知足用戶更多個性化開發語言及版本的函數實現需求,他們提供了 Custom Runtime 服務,即可定製化運行環境,支持用戶用任何編程語言編寫的函數。前端
以阿里雲函數計算 FC 爲例,這是它所支持的開發語言列表:java
支持語言 | 運行環境 |
---|---|
Node.js | Node.js 6.10(runtime=nodejs6)、 Node.js 8.9.0(runtime=nodejs8)、 Node.js 10.15.3(runtime=nodejs10) Node.js 12.16.1(runtime=nodejs12) |
Python | Python 2.7(runtime = python2.7) Python 3.6(runtime = python3) |
PHP | PHP 7.2.7(Runtime=php7.2) |
Java | Java OpenJDK 1.8.0(runtime=java8) |
C# | .NET Core 2.1(runtime=dotnetcore 2.1) |
Go | Go Custom Runtime |
Ruby | Ruby Custom Runtime |
PowerShell | PowerShell Custom Runtime |
TypeScript | TypeScript Custom Runtime |
F# | F# Custom Runtime |
C++ | C++ Custom Runtime |
Lua | Lua Custom Runtime |
Dart | Dart Custom Runtime |
其餘語言 | Custom Runtime |
能夠看出,對於咱們前端工程師,若是想使用阿里雲 FC 平臺,並不能爲所欲爲的使用 Node.js 和 TypeScript 。由於 Node.js,只支持表格中的四種版本,而 TypeScript ,FC 平臺自身徹底不支持。因此要想使用 Node.js 的其它版本和 TypeScript,就須要自定義運行時。node
那麼什麼是 Custom Runtime 呢?python
運行時( Runtime )指函數代碼在運行時所依賴的環境,包括任何庫、代碼包、框架或平臺。Custom Runtime 就是徹底由用戶自定義函數的運行環境。git
FaaS 平臺經過開放實現自定義函數運行時,支持根據需求使用任意開發語言的任意版本來編寫函數。web
阿里雲官方文檔中說到,基於 Custom Runtime 咱們能夠實現這兩件事:docker
本文將以阿里雲 FC 爲例,實現一個 Custom Runtime。其它平臺好比騰訊雲 SCF 等,原理和過程也都大體相同。
Custom Runtime 本質上是一個 HTTP Server,代碼裏面包含一個名爲 bootstrap 的啓動文件,以後這個 HTTP Server 接管了函數計算平臺的全部請求,包括事件調用或者 HTTP 函數調用等。
現在 Typescript
在 Node 中的應用已經愈來愈普遍,因此筆者將實現一個能夠運行 TS 代碼的 TypeScript 運行時。
爲了更快更好地玩轉 Serverless 應用,須要先安裝阿里雲的一個 Fun工具,它是一個用於支持 Serverless 應用部署的工具,能幫助咱們便捷地管理函數計算、API 網關、日誌服務等資源。它經過一個資源配置文件(template.yml),協助咱們進行開發、構建、部署操做。
安裝配置過程以下:
(1)安裝:
// 安裝命令
$ npm install @alicloud/fun -g
// 執行 fun --version 檢查安裝是否成功
$ fun --version
3.6.21
複製代碼
(2)安裝好後,使用fun config
命令配置帳戶信息(配置文檔),按照提示依次配置 Account ID、AccessKey ID、AccessKey Secret、Default Region Name。
配置完成後,先在本地建立一個 TypeScript 項目 custom-runtime-typescript,並安裝相關依賴。
npm i typescript ts-node @types/node
複製代碼
接下來,開始 Custom Runtime 的開發流程,一步一步打造屬於本身的自定義運行環境。
0.0.0.0:CAPort
或*:CAPort
端口,默認是 9000。若是使用127.0.0.1:CAPort
端口,會致使請求超時用 TS 編寫一個 HTTP Server 文件 server.ts 以下:
注意:在開發函數具體的邏輯以前,通常會確認開發的函數是事件函數仍是 HTTP 函數
import * as http from 'http';
// 建立一個 HTTP Server
const server = http.createServer(function (req: http.IncomingMessage, res: http.ServerResponse): void {
var rid = req.headers["x-fc-request-id"];
console.log(`FC Invoke Start RequestId: ${rid}`);
var rawData = "";
req.on('data', function (chunk) {
rawData += chunk;
});
req.on('end', function () {
// 處理業務邏輯 ……
console.log(rawData);
res.writeHead(200);
res.end(rawData);
console.log(`FC Invoke End RequestId: ${rid}`);
});
});
server.timeout = 0; // never timeout
server.keepAliveTimeout = 0; // kee palive, never timeout
// 啓動 HTTP 服務並監聽 0.0.0.0:9000 端口
server.listen(9000, '0.0.0.0', function () {
console.log('FunctionCompute typescript runtime inited.');
});
複製代碼
編寫完成後,能夠先在本地測試該服務是否啓動成功,經過安裝在項目中的 ts-node 命令來運行上述代碼:
# 啓動 HTTP 服務
$ ./node_modules/.bin/ts-node server.ts
複製代碼
啓動後,在另外一個終端中使用 curl 命令測試:
$ curl 0.0.0.0:9000 -X POST -d "hello world" -H "x-fc-request-id:123"
hello world
複製代碼
若服務已正常啓動,說明它能夠在接收 HTTP 請求後處理業務邏輯,而後將處理結果再以 HTTP 響應的形式返回給 FaaS 平臺。
函數計算冷啓動 Custom Runtime 時,會默認調用 bootstrap 文件啓動自定義的 HTTP Server。而後這個 HTTP Server 接管了函數計算系統的全部請求。
#!/bin/bash
建立 bootstrap 文件以下:
#!/bin/bash
./node_modules/.bin/ts-node server.ts
複製代碼
在當前目錄下編寫一份用於部署到函數計算的資源配置文件 template.yaml:
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
custom-runtime: # 服務名稱
Type: 'Aliyun::Serverless::Service'
Properties:
Description: 'helloworld'
custom-runtime-ts: # 函數名稱
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler # Handler 在此時沒有實質意義,填寫任意的一個知足函數計算 Handler 字符集約束的字符串便可, 例如 index.handler
Runtime: custom # custom 表明自定義運行時
MemorySize: 512
CodeUri: './'
複製代碼
(1)使用fun deploy -y
命令將咱們的自定義運行時和業務邏輯代碼全部資源部署到阿里雲。
(2)使用命令調用部署函數,驗證
$ fun invoke -e "hello,my custom runtime"
複製代碼
看到成功輸出,就表明咱們的 custom runtime 大功告成了!它能夠直接運行咱們寫的 TS 代碼了。
TS 的運行環境問題能夠用 Custom Runtime 解決,可是 Node 某些版本平臺不支持的問題,就不能用一樣的辦法了。由於 Node 是全局安裝的,依賴系統環境。
FC 平臺已經爲咱們想好了此類問題的解決辦法,爲咱們提供了 Custom Container Runtime (自定義容器運行環境)的能力。FaaS 平臺有這種能力,是由於它的底層實現原理是 Docker 容器,因此它經過運用容器技術,把咱們的應用代碼和運行環境打包爲 Docker 鏡像,保持環境一致性。實現一次構建,處處運行。
Custom Container Runtime 工做原理與Custom Runtime 基本相同:
下面咱們自定義一個 Node v16.1.0 版本的容器運行環境。
這一步和 Custom Runtime 相同,使用 Node.js Express 自定義一個 Http 服務 server.js,GET 和 POST 方法分別路由至不一樣的 Handler:
// server.js 文件
'use strict';
const express = require('express');
// Constants
const PORT = 9000;
const HOST = '0.0.0.0';
// HTTP 函數調用
const app = express();
app.get('/*', (req, res) => {
res.send(`Hello FunctionCompute, http function, runtime is : Node ${process.version}\n`);
});
// 事件函數調用
app.post('/invoke', (req, res) => {
res.send(`Hello FunctionCompute, event function,runtime is : Node ${process.version}\n`);
});
// 啓動 HTTP 服務並監聽 9000 端口
var server = app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
server.timeout = 0; // never timeout
server.keepAliveTimeout = 0; // keepalive, never timeout
複製代碼
啓動服務,本地測試一下:
# 啓動 HTTP 服務
$ node server.js
複製代碼
# 新開一個終端,經過 curl 命令測試
$ curl http://0.0.0.0:9000
Hello FunctionCompute, http GET, this runtime is : Node v11.5.0 # 這是我本地的 Node 版本,後面在自定義容器中會輸出 v16.1.0
複製代碼
驗證經過。
一樣的,須要先作兩個準備工做:
1)安裝啓動 Docker
2)使用阿里雲容器鏡像服務建立命名空間和鏡像倉庫存放咱們的自定義鏡像
接下來,先編寫 Dockerfile,再構建包含咱們 Node 指定版本運行環境和應用代碼的鏡像,最後上傳到本身的鏡像倉庫。
(有須要的同窗能夠先看下這篇文章如何把一個 Node.js web 應用程序給 Docker 化 )
(1) 編寫 Dockerfile:
# 基於基礎鏡像 node:16.1.0-alpine3.11 構建咱們本身的鏡像
FROM node:16.1.0-alpine3.11
# 設置容器工做目錄
WORKDIR /usr/src/app
# 將 package.json 和 package-lock.json 都拷貝到工做目錄
COPY package*.json ./
# 安裝依賴
RUN npm install
# 將當前目錄下的全部文件拷貝到容器工做目錄中
COPY . .
# 暴露容器 8080 端口
EXPOSE 8080
# 在容器中啓動應用程序
ENTRYPOINT [ "node", "server.js" ]
複製代碼
(2)安裝啓動 Docker,登陸阿里雲鏡像服務,構建並上傳:
# 登陸
$ sudo docker login --username=xxx registry.cn-hangzhou.aliyuncs.com
複製代碼
登陸成功後,先構建 Docker 鏡像:
# 指定ACR鏡像地址:其中 my_serverless 爲你本身的容器命名空間;nodejs 爲你本身的鏡像倉庫名稱;v16.1.0 爲鏡像版本號
$ export IMAGE_NAME="registry.cnhangzhou.aliyuncs.com/my_serverless/nodejs:v16.1.0"
複製代碼
# 構建鏡像
# -t 給鏡像取名字打標籤,一般 name:tag 或者 name 格式
$ docker build -t $IMAGE_NAME .
複製代碼
再啓動容器,本地打開瀏覽器 http://localhost:9000/ 看是否能夠正常響應,來驗證咱們的自定義鏡像是否能夠運行成功:
# 啓動容器: 將容器的 9000 端口映射到主機的 9000 端口
$ docker run -p 9000:9000 -d $IMAGE_NAME
複製代碼
驗證經過後,最後上傳鏡像:
# 上傳鏡像
$ docker push $IMAGE_NAME
複製代碼
上傳成功後,能夠在阿里雲鏡像服務中看到咱們的鏡像。後面就可使用它啦!
建立一個 template.yaml
文件以下:
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
CustomContainerRuntime: # 服務名稱
Type: 'Aliyun::Serverless::Service'
Properties:
Policies:
- AliyunContainerRegistryReadOnlyAccess
InternetAccess: true
nodejs-express-http: # 函數名稱
Type: 'Aliyun::Serverless::Function'
Properties:
Description: 'HTTP function powered by nodejs express'
Runtime: custom-container # 表示自定義容器
Timeout: 60
CAPort: 9000 # 注意!這裏Custom Container Runtime使用的監聽端口必定要和HTTP Server監聽的端口保持一致,不然會出現錯誤
Handler: not-used
MemorySize: 1024
CodeUri: ./ # Root directory for the function or the Dockerfile path
CustomContainerConfig: # 容器鏡像配置
# Sample image value: registry-vpc.cn-shenzhen.aliyuncs.com/fc-demo/nodejs-express:v0.1 使用同地域的VPC鏡像地址加速
Image: 'registry.cn-hangzhou.aliyuncs.com/my_serverless/nodejs:v16.1.0'
Command: '[ "node"]'
Args: '["server.js"]'
Events:
http-trigger-test:
Type: HTTP
Properties:
AuthType: ANONYMOUS
Methods: ['GET', 'POST', 'PUT']
複製代碼
# 使用命令部署到 FC
$ fun deploy -y
複製代碼
部署成功後,咱們去 FC 平臺上進行測試。
由於咱們在template.yaml
中配置的觸發器是 http 觸發器,因此咱們點擊「執行」按鈕進行調試,發現正常運行,返回結果爲 runtime is : Node v16.1.0,說明咱們的自定義容器運行環境也成功實現了!
Custom Runtime 爲咱們打破了 FaaS 平臺對語言的限制;Custom Container Runtime 讓開發者能夠將應用代碼和運行環境打包成容器鏡像做爲函數的交付物,優化開發者體驗、提高開發和交付效率。
自定義(容器)運行時讓咱們開發者使用 Serverless 的自由度更高,經過它們可讓咱們無需代碼改造,一鍵遷移咱們的 Web 應用。
開源地址 www.zoo.team/openweekly/ (小報官網首頁有微信交流羣)
政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 40 餘個前端小夥伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的「老」兵,也有浙大、中科大、杭電等校的應屆新人。團隊在平常的業務對接以外,還在物料體系、工程平臺、搭建平臺、性能體驗、雲端應用、數據分析及可視化等方向進行技術探索和實戰,推進並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。
若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變既定的節奏,將會是「5 年工做時間 3 年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手推進一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給 ZooTeam@cai-inc.com