利用Azure Functions和k8s构建Serverless计算平台
题记:昨晚在一个技术社区直播分享了“利用Azure Functions和k8s构建Serverless计算平台”这一话题。整个分享分为4个部分:Serverless概念的介绍、Azure Functions的简单介绍、k8s和KEDA的介绍和最后的演示。
Serverless
Serverless其实包含了两种概念:BaaS(Backend as a Service)和FaaS(Function as a Service)。这次的分享主要针对的是FaaS概念。
FaaS的最大特征就是:无需管理自己的服务器或拥有自己的持续运行的服务应用的情况下运行后端代码。 上面加粗的地方其实也揭示了FaaS和PaaS的本质区别:你为了运行后端代码,需不需要拥有一套持续运行的服务端完整应用(不管是WebSite还是Web API)。
另外,FaaS还拥有如下特征:
- 可以使用任何语言,不需要针对特定框架和函数进行编码
- 部署方式和传统系统有很大不同
- 水平伸缩完全自动化、弹性,并由平台供应商管理
- 函数通常由事件触发,部分平台供应商支持接收HTTP触发
当然判断什么东西不是FaaS也有一些标准:
- 能否在20ms启动半秒执行完,根本区别在于伸缩性的方式
- FaaS也可能依赖容器,但是和其他使用容器的应用区别在于伸缩性的自动化、透明和细度
- 没有传统的Ops,但是应用本身运维过程还是需要,甚至更难(因为不同)
使用FaaS有其优缺点,这里就报喜不报忧,只列一下优点:
- 降低运维成本
- 基础设施共享
- 减少基础设施维护人工成本
- 降低伸缩成本
- 按量付费:偶尔请求,流量忽高忽低
- 优化代码即可省钱
- 更易运维
- 伸缩的好处利于降低运维难度
- 降低打包和部署复杂度
- 快速投入市场,持续优化
Azure Functions
以官方文档的介绍:Azure Functions 允许你运行小段代码(称为“函数”)且不需要担心应用程序基础结构。 借助 Azure Functions,云基础结构可以提供应用程序保持规模化运行所需的所有最新状态的服务器。 函数由特定类型的事件“触发”。 支持的触发器包括对数据更改做出响应、对消息做出响应、按计划运行,或者生成 HTTP 请求的结果。 虽然你始终可以直接针对大量服务编写代码,但使用绑定可以简化与其他服务的集成。 使用绑定,你能够以声明方式访问各种 Azure 服务和第三方服务。
Azure Functions包含如下功能:
- 无服务器应用程序:使用 Functions,可在 Microsoft Azure 上开发无服务器应用程序。
- 语言选择:使用所选的 C#、Java、JavaScript、Python 和 PowerShell 编写函数。
- 按使用付费定价模型:仅为运行代码所用的时间付费。
- 自带依赖项:Functions 支持 NuGet 和 NPM,允许你访问你喜欢的库。
- 集成的安全性:使用 OAuth 提供程序(如 Azure Active Directory、Facebook、Google、Twitter 和 Microsoft 帐户)保护 HTTP 触发的函数。
- 简化的集成:轻松与 Azure 服务和软件即服务 (SaaS) 产品/服务进行集成。
- 灵活开发:直接在门户中编写函数代码,或者通过 GitHub、Azure DevOps Services 和其他受支持的开发工具设置持续集成和部署代码。
- 有状态无服务器体系结构:使用 Durable Functions 协调无服务器应用程序。
- 开放源代码:Functions 运行时是开源的,可在 GitHub 上找到。
大家看到了,Azure Functions虽然是来源于微软Azure的技术,但是是使用MIT协议开源的,且已经贡献给.NET Foundation。
所以,你可以使用Azure Functions来搭建(甚至定制)自己的Serverless计算平台。开源的不仅是Azure Functions框架本身,还包括了命令行工具(可以支持本地调试)和VSCode的扩展。当然,开发工具除了前面两者,你还是可以使用宇宙第一的IDE:Visual Studio。
下面是相关开源的地址:
- 框架:https://github.com/Azure/azure-functions-host
- 命令行工具:https://github.com/Azure/azure-functions-core-tools
- VSCode扩展:https://github.com/Microsoft/vscode-azurefunctions
只有开源的框架还不行,还需要运行环境,正如大部分开源FaaS框架一样,Azure Functions也把k8s作为运行环境。不过为了达到自动伸缩、不使用就不消耗资源的目标,还需要搭配其他中间件才能达到效果。
k8s和KEDA
众所周知,Kubernetes已经成为最主流的PaaS平台,各大公有云提供商都提供了k8s的服务,比如微软Azure上的AKS或者阿里云的ACK。
为了更好的理解为什么k8s可以作为Serverless完美的运行环境,是需要对如下概念有一些深入的理解的:
- Pod和Deployment:Pod代表了运行函数的实例,而Deployment用于控制函数的实例数。
- HPA(Horizontal Pod Autoscaler):k8s内置的水平Pod自动伸缩器,其基于一些度量指标(比如内存、CPU等)来对Deployment的Pod实例数进行伸缩。
- Helm Charts:一个强大的打包、发布k8s应用的包管理器。我们开发好的函数在编译为Docker Image之后,可以用Helm Charts来打包(当然也可以直接用k8s的yaml文件)。
k8s虽然提供了HPA,但是它无法基于更灵活的事件源来进行伸缩,也无法把Pod的实例数缩到0,或者由0伸到1。这个时候,就需要另外一个开源项目KEDA出场了(贡献者来自微软、AWS等大公司,以及很多社区志愿者)。
KEDA:Kubernetes Event-driven Autoscaling。项目地址在:https://github.com/kedacore/keda。其具有如下特点:
- 事件驱动
- 轻而易举实现自动伸缩
- 内置伸缩器
- 多种负载类型
- 社区开源项目
- 支持Azure Functions
KEDA的架构如下图所示:
从这个架构图,我们看到KEDA包含了3个组件,Metric Adapter给k8s的HPA提供度量指标让其进行1-n/n-1的伸缩,Controller控制Pod进行1-0/0-1的伸缩,Scaler侦听配置的触发器所触发的事件。
且支持的伸缩器涵盖了大部分主流云组件或中间件:
- Apache Kafka
- AWS CloudWatch
- AWS Kinesis Stream
- AWS SQS Queue
- Azure Blob Storage
- Azure Event Hubs
- Azure Monitor
- Azure Service Bus
- Azure Storage Queue
- External
- GCP Pub/Sub
- Huawei Cloudeye
- Liiklus Topic
- MySQL
- NATS Streaming
- PostgreSQL
- Prometheus
- RabbitMQ Queue
- Redis List
演示
既然Azure Functions是开源技术,为了验证技术中立性,在演示过程中特意选择了阿里云的ACK作为运行环境(Kubernetes托管版),并使用RabbitMQ作为伸缩触发器。
同时,我们采用C#/.NET Core来作为函数的开发语言。为什么用这个选择,是因为有第三方对AWS Lambda上的支持的语言进行了性能测试,得到的结论是.NET Core的C#和F#语言性能最高:
来源:https://read.acloud.guru/comparing-aws-lambda-performance-of-node-js-python-java-c-and-go-29c1163c2581
环境准备
首先,需要到阿里云上创建一个k8s集群,创建的选项截图如下:
通过如下命令来部署KEDA到k8s:
helm repo add kedacore https://kedacore.github.io/charts
kubectl create namespace keda
helm install keda kedacore/keda --namespace keda
通过如下命令来部署RabbitMQ到k8s:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install rabbitmq --set rabbitmq.password=PASSWORD,service.type=LoadBalancer bitnami/rabbitmq
这里需要注意(当然也可能是我打开方式不对),阿里云的ACK不能自动创建pv,所以rabbitmq部署后会有问题,所以需要到阿里云的ACK的控制面板里面手动创建pv,并重建rabbitmq所需的同名pvc。
创建Azure Functions项目
访问:https://github.com/Azure/azure-functions-core-tools,安装命令行工具。
在命令行中输入:
func init --docker
来初始化一个带有Dockerfile的Azure Functions项目,worker runtime选择dotnet。
在命令行中输入:
func function create
来创建一个函数,template选择QueueTrigger,输入你想要的函数名称。
使用你喜欢的编辑器(比如VSCode)打开项目文件夹,修改csproj文件中的PackageReference为如下内容:
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.RabbitMQ" Version="0.2.2029-beta" />
</ItemGroup>
修改函数代码为如下内容:
[FunctionName("MyMqFunction")]
public static void Run(
[RabbitMQTrigger("queue", ConnectionStringSetting = "RabbitMqConnection")] string inputMessage,
[RabbitMQ(QueueName = "downstream", ConnectionStringSetting = "RabbitMqConnection")] out string outputMessage,
ILogger log)
{
Thread.Sleep(5000);
outputMessage = inputMessage;
log.LogInformation($"RabittMQ output binding function sent message: {outputMessage}");
}
这个函数从一个名为”queue“的队列中读取inputMessage,延迟5秒后,把消息存储到名为”downstream"的队列中。
打开local.settings.json文件,在Values节点下添加RabbitMqConnection:
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"RabbitMqConnection":"amqp://user:PASSWORD@rabbitmq.default.svc.cluster.local:5672"
},
这里RabbitMQ的地址使用了k8s内部的默认Service地址,为了方便本地调试,你可以获取到RabbitMQ在k8s的公网IP后,给这个域名添加host配置。
在命令行中输入:
func start
就可以进行本地调试了。调试无误,就可以进行发布到k8s的工作了。
以上示例代码可以在这里找到:https://github.com/heavenwing/AzFuncOnK8S
发布函数到k8s并验证伸缩能力
考虑到我用的阿里云拉取Docker Hub比较慢,所以我是编译出Docker Image后,push到了阿里云的镜像仓库当中。 另外,我这里还遇到一个问题,就是能在AKS中正常运行的Docker Image在ACK中无法正常运行,出现"Access to the path '/proc/1/map_files' is denied"的错误,我的临时解决办法是修改Dockerfile文件,添加WORKDIR命令。
在把Docker Image推送到镜像仓库后,可以在命令行中输入:
func kubernetes deploy --name azfunconk8s --image-name registry.cn-chengdu.aliyuncs.com/zygcloud/azfunconk8s:latest --dry-run > deploy-funcs.yaml
得到部署的yaml文件后,我们需要对ScaledObject进行一点修改,为rabbitmq的trigger配置添加queueLength,根据需要配置maxReplicaCount属性,如下所示:
apiVersion: keda.k8s.io/v1alpha1
kind: ScaledObject
metadata:
name: azfunconk8s
namespace: default
labels:
deploymentName: azfunconk8s
spec:
scaleTargetRef:
deploymentName: azfunconk8s
maxReplicaCount: 20
triggers:
- type: rabbitmq
metadata:
type: rabbitMQTrigger
queueName: queue
name: inputMessage
host: RabbitMqConnection
queueLength: "20"
现在就可以把函数部署到k8s了,在命令行中输入:
kubectl apply -f .\deploy\deploy-funcs.yaml
这个时候应该可以看到k8s出现了名为azfunconk8s的Deployment,且需要实例和运行实例数都是为0:
另外写一个小程序,往RabbitMQ的queue队列里面放一些测试消息,经过30秒(默认pollingInterval时间)那么就会看到这个Deployment的所需实例数在提高,一直提高到你设置的maxReplicaCount。等队列中的消息处理完成,又会看到所需实例数在降低,等没有消息需要处理之后过上5分钟(默认cooldownPeriod时间),所需实例数就会变为0。
红包
能看到这里的小伙伴都是爱学习的,应该红包奖励,不过当然是需要回答问题的。
问:KEDA解决的是非http的触发器伸缩,那么什么东西可以解决http触发器伸缩问题?
在我的公众号中输入答案,获取支付宝红包口令,数量有限先答对先得。
利用Azure Functions和k8s构建Serverless计算平台的更多相关文章
- Polaristech 刘洋:基于 OpenResty/Kong 构建边缘计算平台
2019 年 3 月 23 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·北京站,Polaristech 技术专家刘洋在活动上做了<基于 ...
- 使用Azure Functions & .NET Core快速构建Serverless应用
Code Repo: https://github.com/Asinta/ServerlessApp_NetconfChina2020 Prerequisites Visual Studio Code ...
- Azure Functions(一)什么是 ServerLess
一,引言 自去年4月份分享过3篇关于 Azure Functions 的文章之后,就一直没有再将 Azure Functions 相关的内容了.今天再次开始将 Azure Functions 相关的课 ...
- 如何基于 K8S 多租能力构建 Serverless Container
当前 Kubernetes 已经成为名副其实的企业级容器编排规范,很多云平台都开始提供兼容 Kubernetes 接口的容器服务.而在多用户支持方面,多数平台选择直接提供专属虚机集群,用户需要花费大量 ...
- Azure App Service(一)利用Azure DevOps Pipeline 构建镜像,部署应用程序
一,引言 起因是前两天项目上做测试,需要我把写好的基于.NET 5 的 Web 测试程序作成 Docker 镜像.当我在本地验证完功能后,准备利用 Docker 构建应用程序镜像的时候,发现系统不支持 ...
- Azure DevOps(一)利用Azure DevOps Pipeline 构建应用程序镜像到AWS ECR
一,引言 最近项目上让开始学习AWS,作为一名合格的开发人员,当然也是学会利用Azure DevOps Pipeline 将应用程序部署到 AWS ECS(完全托管的容器编排服务).我们要学会将应用程 ...
- Azure DevOps(二)利用Azure DevOps Pipeline 构建基础设施资源
一,引言 上一篇文章记录了利用 Azure DevOps 跨云进行构建 Docker images,并且将构建好的 Docker Images 推送到 AWS 的 ECR 中.今天我们继续讲解 Azu ...
- 一元建站-基于函数计算 + wordpress 构建 serverless 网站
前言 本文旨在通过 快速部署一个 wordpress 网站到阿里云函数计算平台 这个示例来展示 serverless web 新的开发模式, 包括 FUN 工具一键初始化 NAS, 同步网站到 NAS ...
- Azure Functions + Azure Batch实现MP3音频转码方案
客户需求 客户的环境是一个网络音乐播放系统,根据网络情况提供给手机用户收听各种码率的MP3歌曲,在客户没购买歌曲的情况下提供一个三十秒内的试听版本.这样一个系统非常明确地一个需求就是会定期需要将一批从 ...
随机推荐
- Linux文件列表查询ll和ls区别
ll ll查询文件列表,查询结果为当前目录下文件和文件夹的详细信息,包括权限.根目录.用户.创建时间等. ls ls查询出的查询结果只显示当前目录下文件夹和文件名称
- Robot Framework(5)- 使用测试库
如果你还想从头学起Robot Framework,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1770899.html 前言 在RF 测 ...
- UIAutomator2的API文档(二)
1.设备屏幕事件 熄灭屏幕d.screen_off() 唤醒屏幕d.screen_on() 屏蔽状态d.info.get('screenOn')#返回True or False 解锁屏幕d.unloc ...
- web自动化之iframe操作
from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from seleni ...
- Kivy主窗体大小的控制
1. 引入依赖模块 主窗体大小的控制,需要使用到kivy.core.window中的Window模块 from kivy.app import App from kivy.core.window im ...
- springboot整合mybatis报错
java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more ...
- Ef core 如何设置主键
在正题之前,先说明几个问题. (1)写 sql 不好吗,为什么要引入 ORM ? 总的来说由于需求的复杂性增加,引入了面向对象编程,进而有了 ORM ,ORM 使得开发人员以对象的方式表达业务逻辑.对 ...
- 【Ubuntu】Ubuntu中下载特定版本内核和设置某版本内核为默认启动内核
0. 基本命令 uname -a # 查看当前所使用内核 dpkg -l | grep linux # dpkg后是lmn的l.查看当前操作系统的内核 dekg -l | grep linux-ima ...
- Java中方法的重载与重写
1.方法的名字和参数列表称为方法的签名:每个方法具有唯一与其对应的签名: 2.方法的重载:在某个类中,存在具有多个相同名字不同参数列表的方法,称之为重载: 被重载的方法必须改变参数列表(参数个数或类型 ...
- Rocket - devices - TLZero
https://mp.weixin.qq.com/s/JHjUZncEcoZpRxIS1ECV5g 简单介绍TLZero的实现. 1. /dev/null /dev/null最主要的特点是写入的数据被 ...