关于前端:Serverless-Custom-Container-Runtime

10次阅读

共计 8738 个字符,预计需要花费 22 分钟才能阅读完成。

这是第 106 篇不掺水的原创,想获取更多原创好文,请搜寻公众号关注咱们吧~ 本文首发于政采云前端博客:Serverless Custom (Container) Runtime

背景

咱们晓得 Serverless 能够了解为 Serverless = FaaS + BaaS。Serverless 利用中,对于服务端业务逻辑代码,开发者是以 函数 的模式去实现的,即 FaaS(函数即服务)。(Serverless 相干文章能够看下团队联合阿里云 FC 谈谈我对 FaaS 的了解)

对于云厂商的 FaaS 平台,尽管他们反对多种编程语言及版本的规范运行环境,但毕竟还是 无限 的。所以,为了满足用户更多个性化开发语言及版本的函数实现需求,他们提供了 Custom Runtime 服务 ,即 可定制化运行环境,反对用户用任何编程语言编写的函数。

以阿里云函数计算 FC 为例,这是它所反对的开发语言列表:

反对语言 运行环境
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,就须要自定义运行时。

那么什么是 Custom Runtime 呢?

概念

运行时(Runtime)指函数代码在运行时所依赖的环境,<u> 包含任何库、代码包、框架或平台 </u>。Custom Runtime 就是齐全由 用户自定义函数的运行环 境。

FaaS 平台通过凋谢实现自定义函数运行时,反对依据需要应用 任意开发语言的任意版本 来编写函数。

作用

阿里云官网文档中说到,基于 Custom Runtime 咱们能够实现这两件事:

  • 定制个性化语言(例如 Go、Lua、Ruby)和各种语言的小版本(例如 Python 3.7、Node.js 14)的执行环境,打造属于您的运行环境。
  • 一键迁徙 现有的 Web 利用或基于传统开发的 Web 我的项目到函数计算平台,不必做任何革新。

实现 Custom Runtime

本文将以阿里云 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 的开发流程,一步一步打造属于本人的自定义运行环境。

1. 搭建一个具备监听端口的 HTTP Server

  • 须要留神的是,这个服务肯定要监听 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 平台。

2. 创立一个启动指标 Server 的可执行文件 bootstrap

函数计算冷启动 Custom Runtime 时,会默认调用 bootstrap 文件启动自定义的 HTTP Server。而后这个 HTTP Server 接管了函数计算零碎的所有申请。

  • bootstrap 是运行时入口疏导程序文件,它会通知 FaaS 如何启动你的自定义运行时。Custom Runtime 加载函数时会固定检索 bootstrap 同名文件,并执行该程序来启动 Custom Runtime 运行时。
  • bootstrap 需具备 777 或 755 可执行权限
  • 如果是 shell 脚本,肯定要增加#!/bin/bash

创立 bootstrap 文件如下:

#!/bin/bash
./node_modules/.bin/ts-node server.ts

3. 编写资源配置文件 template.yaml

在当前目录下编写一份用于部署到函数计算的资源配置文件 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: './'

4. 部署、调用测试、实现

(1)应用fun deploy -y 命令将咱们的自定义运行时和业务逻辑代码所有资源部署到阿里云。

(2)应用命令调用部署函数,验证

$ fun invoke -e "hello,my custom runtime"  

看到胜利输入,就代表咱们的 custom runtime 功败垂成了!它能够间接运行咱们写的 TS 代码了。

实现 Custom Container Runtime

TS 的运行环境问题能够用 Custom Runtime 解决,然而 Node 某些版本平台不反对的问题,就不能用同样的方法了。因为 Node 是全局装置的,依赖零碎环境。

FC 平台曾经为咱们想好了此类问题的解决办法,为咱们提供了 Custom Container Runtime(自定义容器运行环境)的能力。FaaS 平台有这种能力,是因为它的底层实现原理是 Docker 容器 ,所以它通过使用容器技术, 把咱们的利用代码和运行环境打包为 Docker 镜像,放弃环境一致性。实现一次构建,到处运行。

工作原理

Custom Container Runtime 工作原理与 Custom Runtime 基本相同:

  • 函数计算零碎初始化执行环境实例前会表演该函数的服务角色,取得长期用户名和明码并 拉取镜像
  • 拉取胜利后依据指定的启动命令 Command、参数 Args 及 CAPort 端口(默认 9000)启动自定义的 HTTP Server。
  • 而后这个 HTTP Server 接管了函数计算零碎的所有申请,包含来自事件函数调用及 HTTP 函数调用。

上面咱们自定义一个 Node v16.1.0 版本的容器运行环境。

操作步骤

1. 自定义 HTTP Server

这一步和 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                 

验证通过。

2. 构建镜像并上传

同样的,须要先做两个筹备工作:

  • 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

<img src=”https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6acbfc32153e48f9a7df5e377e43bbd8~tplv-k3u1fbpfcp-zoom-1.image” alt=”image-20210514150709489″ style=”zoom:50%;” />

验证通过后,最初上传镜像:

# 上传镜像
$ docker push $IMAGE_NAME  

上传胜利后,能够在阿里云镜像服务中看到咱们的镜像。前面就能够应用它啦!

3. 定义 template.yaml

创立一个 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']
4. 部署测试
# 应用命令部署到 FC 
$ fun deploy -y

<img src=”https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/319556a34c8b4ad5bc861a3b432f7ab9~tplv-k3u1fbpfcp-zoom-1.image” alt=”image-20210509163842880″ style=”zoom:50%;” />

部署胜利后,咱们去 FC 平台上进行测试。

因为咱们在template.yaml 中配置的触发器是 http 触发器,所以咱们点击“执行”按钮进行调试,发现失常运行, 返回后果为 runtime is : Node v16.1.0,阐明咱们的自定义容器运行环境也胜利实现了!

<img src=”https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a3553a89ace54a618a85304ca32d5d5b~tplv-k3u1fbpfcp-zoom-1.image” alt=”image-20210509163945647″ style=”zoom:50%;” />

小结

Custom Runtime 为咱们突破了 FaaS 平台对语言的限度;Custom Container Runtime 让开发者能够将利用代码和运行环境打包成容器镜像作为函数的交付物,优化开发者体验、晋升开发和交付效率。

自定义(容器)运行时让咱们开发者应用 Serverless 的自由度更高,通过它们能够让咱们无需代码革新,一键迁徙咱们的 Web 利用。

参考资料

what-is-runtime

为阿里云 serverless 打造 Deno 运行时

Custom Runtime 阐明

fun 工具

函数计算反对容器镜像 - 减速利用 Serverless 过程

Custom Runtime – 突破云函数语言限度

开源作品

  • 政采云前端小报

开源地址 www.zoo.team/openweekly/ (小报官网首页有微信交换群)

招贤纳士

政采云前端团队(ZooTeam),一个年老富裕激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 40 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员形成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端利用、数据分析及可视化等方向进行技术摸索和实战,推动并落地了一系列的外部技术产品,继续摸索前端技术体系的新边界。

如果你想扭转始终被事折腾,心愿开始能折腾事;如果你想扭转始终被告诫须要多些想法,却无从破局;如果你想扭转你有能力去做成那个后果,却不须要你;如果你想扭转你想做成的事须要一个团队去撑持,但没你带人的地位;如果你想扭转既定的节奏,将会是“5 年工作工夫 3 年工作教训”;如果你想扭转原本悟性不错,但总是有那一层窗户纸的含糊… 如果你置信置信的力量,置信平凡人能成就不凡事,置信能遇到更好的本人。如果你心愿参加到随着业务腾飞的过程,亲手推动一个有着深刻的业务了解、欠缺的技术体系、技术发明价值、影响力外溢的前端团队的成长历程,我感觉咱们该聊聊。任何工夫,等着你写点什么,发给 ZooTeam@cai-inc.com

正文完
 0