这篇文章已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已发生变化。

Fission:Kubernetes 的无服务器函数即服务

Fission 是一个构建在 Kubernetes 之上的函数即服务 (FaaS) / 无服务器函数框架。

Fission 使您能够轻松地从函数在 Kubernetes 上创建 HTTP 服务。它在源代码级别工作,并且(在大多数情况下)抽象化了容器镜像。它还通过让您无需深入了解 Kubernetes 即可构建有用的服务来简化 Kubernetes 的学习曲线。

要使用 Fission,您只需创建函数并通过 CLI 添加它们。您可以将函数与 HTTP 路由、Kubernetes 事件或其他触发器关联。目前 Fission 支持 NodeJS 和 Python。

函数在其触发器触发时被调用,并且只在运行时消耗 CPU 和内存。空闲函数除了存储外不消耗任何资源。

为什么要在 Kubernetes 上构建 FaaS 框架?

我们认为需要一个可以在各种基础设施(包括公有云和本地基础设施)上运行的 FaaS 框架。接下来,我们必须决定是从零开始构建,还是在现有编排系统之上构建。很快就清楚了,我们不应该从零开始构建——那样最终只会重新发明集群管理、调度、网络管理等等。

Kubernetes 提供了一个强大而灵活的编排系统,拥有全面的 API,并由一个强大且不断发展的社区支持。基于它进行构建意味着 Fission 可以将容器编排功能留给 Kubernetes,而专注于 FaaS 特性。

我们不希望有单独的 FaaS 集群的另一个原因是,FaaS 与其他基础设施结合使用效果最佳。例如,它可能非常适合小型 REST API,但需要与其他服务一起工作来存储状态。FaaS 也非常适合作为事件处理器来处理来自存储、数据库以及 Kubernetes 本身通知的机制。Kubernetes 是所有这些服务在其上互操作的绝佳平台。

部署和使用 Fission

Fission 可以通过 `kubectl create` 命令安装:有关说明,请参阅项目 README

下面是如何编写一个“hello world”HTTP 服务

$ cat \> hello.py

def main(context):

    print "Hello, world!"


$ fission function create --name hello --env python --code hello.py --route /hello


$ curl http://\<fission router\>/hello

Hello, world!

Fission 负责将函数加载到容器中、将请求路由到函数等等。我们将在下一节中深入介绍更多细节。

Fission 如何在 Kubernetes 上实现

FaaS 框架的核心必须能够 (1) 将函数转换为服务,以及 (2) 管理这些服务的生命周期。

实现这些目标有多种方法,每种方法都有不同的权衡。框架应该在源代码级别操作,还是在 Docker 镜像级别操作(或者介于两者之间,比如“buildpacks”)?函数第一次运行时可接受的开销是多少?这里的选择会影响平台的灵活性、易用性、资源使用和成本,当然还有性能。

打包、源代码和镜像

我们的目标之一是让 Fission 对新用户非常易于使用。我们选择在源代码层面操作,
这样用户就可以避免处理容器镜像构建、将镜像推送到注册表、管理注册表凭据、镜像版本控制等等问题。

然而,容器镜像是打包应用程序最灵活的方式。纯粹的源代码级别接口不会允许用户打包二进制依赖项,例如。

因此,Fission 采用了混合方法——使用包含函数动态加载器的容器镜像。这种方法允许大多数用户在源代码级别纯粹使用 Fission,但也允许他们在需要时定制容器镜像。

在 Fission 中,这些镜像被称为“环境镜像”,它们包含了语言运行时(例如 NodeJS 或 Python)、一组常用依赖项以及一个函数动态加载器。如果这些依赖项对于用户正在编写的函数来说足够了,则无需重新构建镜像。否则,可以修改依赖项列表并重新构建镜像。

这些环境镜像只是 Fission 中与语言相关的部分。它们向框架的其余部分提供统一接口。这种设计使得 Fission 可以轻松扩展到更多语言。

冷启动性能

无服务器函数的目标之一是函数只在运行时消耗 CPU/内存资源。这优化了函数的资源成本,但代价是当从空闲状态启动时会产生一些性能开销(即“冷启动”开销)。

冷启动开销在许多用例中都很重要。特别是对于交互式用例中使用的函数——比如用户正在等待操作完成的 Web 或移动应用程序——几秒的冷启动延迟是不可接受的。

为了优化冷启动开销,Fission 为每个环境维护一个运行中的容器池。当一个函数的请求到来时,Fission 不需要部署一个新的容器——它只需选择一个已经在运行的容器,将函数复制到容器中,动态加载它,并将请求路由到该实例。对于 NodeJS 和 Python 函数,这个过程的开销大约在 100 毫秒左右。

Fission 如何在 Kubernetes 上工作

fission-arch.png Fission 被设计为一组微服务。一个 Controller 跟踪函数、HTTP
路由、事件触发器和环境镜像。一个 Pool Manager 管理空闲环境容器池、将函数加载到这些容器中以及在函数实例空闲时终止它们。一个 Router 接收 HTTP 请求并将其路由到函数实例,如有必要,会向 Pool Manager 请求一个实例。

Controller 提供 Fission API。所有其他组件都监视 Controller 以获取更新。Router 被公开为 LoadBalancer 或 NodePort 类型的 Kubernetes Service,具体取决于 Kubernetes 集群的托管位置。

当 Router 收到请求时,它会查找缓存以查看此请求是否已有应路由到的服务。如果不是,它会查找要映射请求的函数,并向 poolmgr 请求一个实例。poolmgr 有一个空闲 Pod 池;它选择一个 Pod,将函数加载到其中(通过向 Pod 中的 sidecar 容器发送请求),并将 Pod 的地址返回给 Router。Router 将请求代理到该 Pod。该 Pod 会被缓存以供后续请求使用,如果它空闲了几分钟,就会被终止。

(目前,Fission 将一个函数映射到一个容器;计划在后续版本中实现自动扩缩到多个实例。对于不要求隔离的场景,也计划复用函数 Pod 来托管多个函数。)

Fission 的用例

机器人、Webhooks、REST API
Fission 是一个很好的框架,用于构建小型 REST API、实现 webhooks 以及为 Slack 或其他服务编写聊天机器人。

作为一个简单 REST API 的例子,我们构建了一个小型留言簿应用程序,它使用函数来读写留言簿,并与 redis 实例协同工作来跟踪状态。您可以在Fission GitHub 仓库中找到该应用程序。

该应用程序包含两个端点——GET 端点列出 redis 中的留言簿条目并将其渲染为 HTML。POST 端点将新条目添加到 redis 的留言簿列表中。就这么简单——没有 Dockerfile 需要管理,更新应用程序就像调用 `fission function update` 一样简单。

处理 Kubernetes 事件
Fission 还支持基于 Kubernetes watch 来触发函数。例如,您可以设置一个函数来监视特定命名空间中匹配特定标签的所有 Pod。函数在其上下文中获取序列化对象和 watch 事件类型(added/removed/updated)。

这些事件处理函数可用于简单的监控——例如,每当集群中添加新服务时,您都可以发送一条 Slack 消息。还有更复杂的用例,例如通过监视 Kubernetes 的第三方资源来编写自定义控制器。

状态和路线图

Fission 目前处于早期 Alpha 阶段(2017 年 1 月)。尚未准备好用于生产环境。我们正在寻找早期采用者和反馈。

Fission 的未来如何?我们正在努力让 Kubernetes 上的 FaaS 更加便捷、易用且更易于集成。未来几个月,我们正致力于添加单元测试支持、与 Git 集成、函数监控和日志聚合。我们还在努力与其他事件源集成。

创建更多语言环境也在进行中。目前支持 NodeJS 和 Python。Klavs Madsen 已贡献了对 C# .NET 的初步支持。

您可以在我们的 GitHub issuesprojects 中找到我们当前的路线图。

参与其中

Fission 是一个开源项目,由 Platform9 Systems 公开开发。请在 GitHub 上查看我们,如果您想与我们交流,请加入我们的 Slack 频道。我们也在 Twitter 上:@fissionio