Fission 介绍

7月 1, 2017 tech post

Fission 是一个 Serverless Framework,基于 Kubernetes ,使用 Golang 编写。目前处于 early alpha 阶段,所以实现还很简单。

fission 目前主要有这样几个概念:

  • Function:开发写的代码
  • Environment: function 的运行环境,一个 docker image ,目前只支持运行单个文件的 function ( issue#103)
  • Pool:它就是 fission 的资源池,实质就是在 kubernetes 之上运行的一批容器,管理它的组件叫做 Pool Manager
  • Service:当 pool 中的容器被激活,它就变成了一个可对外提供服务的 service
  • Router:将用户的请求转发到 pool 中对应的 service 上
  • Controller:对外暴露 API ,存储 function 的代码以及存储其他数据到 Etcd 上。

看看官网的使用示例:

# 准备好运行环境:添加 env
$ fission env create --name nodejs --image fission/node-env
# 上传代码:添加function
$ fission function create --name hello --env nodejs --code hello.js
# 添加路由
$ fission route create --method GET --url /hello --function hello

其中的 hello.js 内容如下:

module.exports = async function(context) {
    return {
        status: 200,
        body: "Hello, world!\n"
    };
}

然后我们调用它:

# 调用
$ curl http://$FISSION_ROUTER/hello
Hello, world!

在上述示例中,fission 的执行的流程如下:

1.新建资源池

新建 nodjs 的 env 后,pool manager 会在 kubernetes 中创建与之对应的 Deployment 来做为它的资源池,默认有 3 个 pod 副本,每个 pod 包含两个 container :fetcher container 和 service container。

fetcher 的镜像固定是 fission/fetcher,它的作用是从 controller 获取 function 对应的代码。service container 的镜像即我们在 env 中规定的 fission/node-env,它负责加载 function 并对外提供服务。

这两个容器之间有一个共享的 volume 用来传递代码。

2.存储 Function

Controller 将上传的 hello.js 存储起来(这里是本地)。

3.添加路由

Controller 得到的路由信息提供给 pool manager 和 router 使用。

4.处理请求

Router 会从 controller 和 pool manager 获取 functions 和 triggers 的信息,并会在本地缓存 url 到 function,function 到 service 的映射,在接到用户的请求后,会先判断有无已被缓存的 service:

  1. 如果没有,会把情况告知 pool manager,同时将用户的请求阻塞住。
  2. 如果有,则会直接将请求转发到对应的 service。

说说没有的情况,pool manager 在收到 router 的请求后,会从 pool 中选择一个 pod A 并激活它,同时新建一个 pod 来补充 pool 。激活的过程如下:

  1. pool manager 请求 pod A 中 fetcher 容器的接口, fetcher 容器从 controller 拉取 hello.js 的代码并将其放到与 service 容器的共享 volume 中。
  2. pool manager 请求 pod A 中 service 容器的接口, service 容器把共享 volume 中的 hello.js 加载到服务中。

激活之后,pod A 就可以对外提供服务了(一个 Service),这时 router 将用户的请求转发到 pod A 的 service 容器上。在用户请求处理完毕后,pod A 会被缓存下来,等到持续几分钟内没有新的请求,pool manager 就会把 pod A 销毁。

到这里,一个请求就算完成了。

开发

Fission 本身也是部署在 Kubernetes 中的,Controller,Router,Pool Manager 这几个组件被打包到 fission-bundle , fission-bundle 又被打包到了 docker 镜像中。所以每次修改代码都得重新打包 fission-bundle 的镜像,然后推送到私有的 Docker 仓库中,非常繁琐。如果是使用 minikube 的 kubernetes ,倒是可以通过

$ minikube docker-env

来避免推送镜像,但还是很繁琐。我想尝试将代码挂载到容器中,然后使用类似 beenodemon 这样的工具来自动编译并重启服务。