全部产品
云市场
云游戏

Custom Runtime 简介

更新时间:2020-03-31 18:21:12

本文介绍了 Custom Runtime 的原理和规范,您可以参见这些原理和规范打造属于您的自定义环境。

背景信息

Custom Runtime 就是自定义的执行环境, 您可以基于 Custom Runtime 实现:

  • 定制个性化语言执行环境(例如 Golang、Lua、Ruby)和各种语言的小版本(例如 Python3.7、Node.js12),打造属于自己的 Runtime。

  • 一键迁移现有的 Web 应用或基于传统开发 Web 项目到函数计算平台。

Custom Runtime 基本原理

cr

Custom Runtime 本质上是一个 HTTP Server, 您只需要实现一个监听固定端口的 HTTP Server, 将启动这个 Server 的命令保存为一个名为 bootstrap 的文件,最后一起 zip 打包作为代码包创建一个 Custom Runtime 的函数。

函数计算系统冷启动 Custom Runtime 的时候, 会默认调用 bootstrap 启动您自定义的 HTTP Server, 之后这个 HTTP Server 接管了函数计算系统的所有请求,包括来自您的事件调用或者 HTTP 函数调用。

事件调用

函数计算系统会将 Common Headers 和您调用的请求体转发给 Custom Runtime。

说明:Common Headers 里面的信息可以构造类似官方 Runtime 中的入参 context,而您调用函数的请求体可以构造类似官方 runtime 中的入参 event

如果您没有对事件调用函数定义为 def handler(context, event) 的需求, 您可以直接基于这个 HTTP Server 实现自定义逻辑。

HTTP 函数调用

函数计算系统会将用户的请求(包括请求路径、请求头和请求体)加上 Common Headers 转发给 Custom Runtime, 因此, 如果您对 Common Headers 不感兴趣, 那么基于 Custom Runtime 可以快速移植一个已有的 Web 应用。

执行环境

Custom Runtime 的 Docker 镜像基于 debian 9(stretch),Linux 内核为 Linux version 4.9.125。Custom Runtime 对 Python、Node.js 和 Java 提供了内置支持。

  • Python 3.7.4
  • Node.js v10.16.2
  • Open JDK 1.8.0( Open JDK version “1.8.0_232”、Open JDK Runtime Environment (build 1.8.0_232-8u232-b09-1~deb9u1-b09))

Custom Runtime 示例

您如果要实现一个 Custom Runtime,只需要满足以下三个条件:

  • 创建一个 HTTP Server,监听在固定端口(端口可以读取环境变量 FC_SERVER_PORT,默认为 9000)。
  • HTTP Serverr 需要在 15 秒内完成启动。
  • connection 最好设置为 keep alive,请求超时时间至少设置在 15 分钟以上。
    1. // 例如 Node.js 使用 express
    2. app.timeout = 0; // never timeout
    3. app.keepAliveTimeout = 0; // keepalive, never timeout

例如函数计算运行一个 Tornado 应用,操作步骤如下:

1.编写 server.py 代码。

  1. import tornado.ioloop
  2. import tornado.web
  3. import os
  4. class MainHandler(tornado.web.RequestHandler):
  5. def get(self):
  6. self.write("GET: Hello world")
  7. def post(self):
  8. self.write("POST: Hello world")
  9. def make_app():
  10. return tornado.web.Application([
  11. (r"/.*", MainHandler),
  12. ])
  13. if __name__ == "__main__":
  14. app = make_app()
  15. port = os.environ.get("FC_SERVER_PORT", "9000")
  16. app.listen(int(port))
  17. tornado.ioloop.IOLoop.current().start()

2.编写一个具有可执行权限的名字为 bootstrap#!/bin/bash 注释是必须要有的)的文件,启动上面代码的 HTTP Server。

  1. #!/bin/bash
  2. python server.py

3.最后一起 zip 打包, 然后基于这个 zip 包创建 runtime 为 custom 的函数。

说明:此时函数的 handler 没有任何意义, 您填写任意的一个满足函数计算 handler 字符集约束的字符串即可。

  1. root@33a2b0c2a9d7:/code# ls -ll
  2. total 16
  3. -rwxr-xr-x 1 root staff 17 Aug 16 22:19 bootstrap
  4. -rw-r--r-- 1 root staff 414 Aug 16 17:24 server.py
  5. drwxr-xr-x 38 root staff 1216 Aug 16 22:20 tornado
  6. root@33a2b0c2a9d7:/code# zip -r code.zip *
  7. root@33a2b0c2a9d7:/code# ls -ll code.zip
  8. -rw-r--r-- 1 root staff 943389 Aug 16 22:24 code.zip

Custom Runtime 实现的功能以及接口要求(可选)

注意事项

  • Custom Runtime 启动的服务一定监听 0.0.0.0:9000 或者 *:9000 端口,不必使用 127.0.0.1:9000, 因为这样会导致请求超时。

    1. {"ErrorCode":"FunctionNotStarted","ErrorMessage":"The CA's http server cannot be started:ContainerStartDuration:25000000000. Ping CA failed due to: dial tcp 21.0.5.7:9000: getsockopt: connection refused Logs : 2019-11-29T09:53:30.859837462Z Listening on port 9000\r\n"}
  • Custom Runtime 的 bootstrap 一定需要添加 #!/bin/bash,否则会遇见如下错误 。

    1. {"ErrorCode":"CAExited","ErrorMessage":"The CA process either cannot be started or exited:ContainerStartDuration:25037266905. CA process cannot be started or exited already: rpc error: code = 106 desc = ContainerStartDuration:25000000000. Ping CA failed due to: dial tcp 21.0.7.2:9000: i/o timeout Logs : 2019-11-29T07:27:50.759658265Z panic: standard_init_linux.go:178: exec user process caused \"exec format error\"

函数计算公共请求头

下文的请求头是 Custom Runtime 会从函数计算系统中接收到的。如果您需要访问阿里云其他服务,您可能需要用到临时 AccessKey 的 headers。 如果您要移植已有的应用,可忽略下文的内容。

Header 描述
x-fc-request-id Invoke/Initialize requestId
x-fc-access-key-id 临时 Accesskey ID
x-fc-access-key-secret 临时 AccesskeySecret
x-fc-security-token 临时 security token
x-fc-function-handler 函数的 handler, 如果 runtime 本身和函数完全是绑定的,该值是没有意义的
x-fc-function-memory 函数最大能使用的内存
x-fc-function-initializer 函数的 Initializer,如果 runtime 本身和函数完全是绑定的,则该值是不需要的
x-fc-initialization-timeout Initializer 执行的超时时间
x-fc-region 函数所在的地域
x-fc-account-id 函数所有者的 uid
x-fc-qualifier 函数 qualifier
x-fc-version-id 函数版本
x-fc-service-name 函数所在的服务的名字
x-fc-service-logproject 函配所在服务配置的 SLS logproject
x-fc-service-logstore 函数所在服务配置的 SLS logstore
x-fc-control-path 请求的类型

日志格式

推荐您在创建服务时使用日志服务,这样的话 Custom Runtime 中所有输出到终端的日志会被保存到您指定的日志服务中。

函数计算系统其他 Runtime 具有这样一个功能:当您调用函数的时候, 请求头中包含 x-fc-log-type" = "Tail" , 那么返回的响应头包含 x-fc-log-result 的内容就是函数执行时候打印的日志, 日志内容大小最大为 4 KB。

目前函数计算的控制台显示的日志就是基于上文这个功能实现。如果您对该功能没有需求,则可以忽略下文的内容。

  • 启动 Runtime (可选,冷启动的标志)

FunctionCompute ${runtime} runtime inited.

如果您使用 Go 开发, ${runtime} 可以为 Golang 自定义,但最好不要和官方的 Node.js 、Python、PHP 等重名。

  • Invoke 开始的日志(必选)

FC Invoke Start RequestId: ${RequestId}

  • Invoke 结束的日志(必选)

FC Invoke End RequestId: ${RequestId}

  • Initialize 开始的日志(可选,有 Initialize 的才需要)

FC Initialize Start RequestId: ${RequestId}

  • Initialize 结束的日志(可选,,有 Initialize 的才需要)

FC Initialize End RequestId: ${RequestId}

除了以上特殊的信息之外,推荐您自己的日志包含请求 ID,这样可以方便您日后诊断问题, 推荐日志格式为$utcdatetime(yyyy-MM-ddTHH:mm:ss.fff) $requestId [$Level] $message

HTTP Server 配置要求

  • 监听在任何 IP 的指定端口(端口可以读取环境变量 FC_SERVER_PORT,默认为 9000)。
  • connection keep alive。
  • request timeout 至少设置在 15 分钟以上。
  • HTTP Server 在 15 秒内启动完毕。

事件函数调用和 HTTP 函数调用

对于 Custom Runtime,您可以根据 header x-fc-control-path 来判别HTTP 函数调用和事件函数调用。

  • /invoke,该请求为非 HTTP 函数调用。当值是 /invoke 时,表示该请求是一次 invoke 调用。
  • /http-invoke ,该请求为 HTTP 函数调用, /http-invoke 表示是一个 http invoke 调用,函数计算会将您的请求(包括请求路径、请求头以及请求体)加上上述 Common Headers 后转发给 Custom Runtime, Custom Runtime 返回的响应头和响应体则会被返回给客户端。
  • /initialize,第一次调用函数创建执行环境,系统自动发起的 initialize 调用。

Custom Runtime 事件函数调用

Path x-fc-control-path 输入请求 期望的响应
POST /invoke /invoke 请求体:函数输入(InvokeFunction 时指定的 Payload)。
请求头:Common Request Headers。
响应体:函数 handler 的返回值。
成功状态: 200
失败状态:404
(通过 headerx-fc-status)。
POST /initialize /initialize 请求体:无。
请求头:Common Request Headers。
响应体:成功时无响应体。
成功状态: 200
失败状态:404
(通过header x-fc-status)。

HTTP 函数调用

当函数是 HTTP 函数调用时,您的函数提供的 Web API、Web Page 将直接被用户端访问,因此不需要实现非 HTTP 函数调用时所实现的 /invoke 以及 /initialize 接口,Custom Runtime 会收到除 Common Headers 之外的以下 headers。

Header 描述
x-fc-base-path 当您尚未配置自定义域名时,x-fc-base-path的值是 /2016-08-15/proxy/${servicename}/${functionname}/, 您代码可能需要将该值设定为 Web App 的 Path Base, 不同语言或框架有不同的处理。

更多信息

Custom Runtime 的限制信息,请参见限制项