本文将详细介绍如何开发和部署 Serverless 应用,并通过阿里云函数计算控制台与开发者工具 Serverless Devs 进行应用的初始化、部署;最后分享应用的调试,通过科学发布、可观测性等介绍应用的部署和运维总结,进而实现从应用初始化到调试、发布、运维基础流程、核心步骤的探索。
一、如何开发、部署Serverless应用
1.通过控制台进行函数创建
下面我们将基于Serverless架构,在 FaaS 平台上实现 Hello world 的输出,基本步骤可分为:
1)注册账号,并登录;
2)找到对应的FaaS产品:阿里云的函数计算;
3)单击“创建函数”按钮,进行函数的创建;
4)配置函数,包括函数名称、运行时(可以认为是要使用的编程语言,或者要使用的编程环境等);
5)完成创建,并测试。
以阿里云函数计算为例,当注册并登录阿里云账号之后,需要找到函数计算产品,并单击进入产品首页,如图所示:
阿里云函数计算产品首页
选择左侧的“服务及函数”,并进行服务的创建,如图所示。
阿里云函数计算创建服务页面
然后进行函数的创建,如图所示。
阿里云函数计算创建函数页面
相对于其他的云平台,在阿里云函数计算平台,我们不仅要为即将创建的函数设置函数名称、选择运行时等,还需要设置该函数所在的服务。在阿里云函数计算的体系中,引入服务的概念会带来一定的好处:
- 相关联的函数可以放在一个服务下进行分类,这种分类实际上比标签分类更直观明了。
- 相关联的函数在同一个服务下共享一定的配置,例如 VPC 配置、NAS 配置,甚至某些日志仓库的配置等。
- 通过服务,我们可以很好地做函数环境的划分,例如对于一个相册项目,该项目可能存在线上环境、测试环境、开发环境,那么可以在服务层面做区分,即可以设定album-release、album-test、album-dev三个服务,进而做环境的隔离。
- 通过服务,我们可以很好地收纳函数。如果项目比较大,可能会产生很多函数,统一放在同一层级会显得非常混乱,这时就可以通过服务进行有效的收纳。
完成函数的创建之后,我们可以进行代码的编辑。阿里云函数计算支持从对象存储上传代码,支持直接上传代码包,以及在线编辑。除此之外,阿里云函数计算还支持直接上传文件夹,如图所示。
保存代码之后,可以单击“执行”按钮进行函数的触发、测试。
可以看到,系统已经输出相关日志:Hello world。至此,一个非常简单的函数就创建成功了。
2.通过工具进行函数创建与部署
通过Serverless开发者工具入门Serverless应用开发、部署、运维是非常方便的,我们以Serverless Devs为例介绍阿里云函数计算应用的部署,并对工具侧的函数创建、部署以及其他相关功能进行探索。
Serverless Devs 是一个开源的Serverless开发者平台,致力于为开发者提供强大的工具链。通过该平台,开发者可以一键体验多云 Serverless 产品,极速部署 Serverless 项目。按照官方目前的描述,Serverless Devs已经支持包括AWS Lanbda、阿里云函数计算、百度智能云函数计算、腾讯云云函数、华为云函数工作流等在内的多个云厂商的Serverless相关产品。
下面通过Serverless Devs开发者工具,以阿里云函数计算为例进行实践,探索如何创建、部署Serverless应用。
1)安装Serverless Devs开发者工具(执行npm install -g @Serverless-devs/s命令)。
2)设置阿里云凭证信息(执行s config add --AccessKeyID AccessKeyID --AccessKeySecret AccessKeySecret --AccountID AccountID命令)。
3)建立模板项目(执行s init node.js12-http -d fc-hello-world-demo命令),初始化过程如图所示。
通过Serverless Devs创建项目图
4)进入项目目录(执行cd fc-hello-world-demo命令),并部署(执行s deploy命令),部署后的结果如图所示。
通过Serverless Devs部署项目
项目部署成功之后,可以进行更多操作,具体如下,触发函数(执行s invoke命令),结果如图所示。
通过Serverless Devs触发函数
查看线上函数详情(执行s info命令),结果如图所示。
通过Serverless Devs查看函数详情
Serverless Devs 还拥有比较完善的桌面客户端。开发者可以通过桌面客户端进行应用的创建、管理以及相关配套功能的使用,示例如下,查看应用列表,并快速创建应用,如图所示。
通过Serverless Devs桌面客户端查看应用列表
创建应用之后,可以进行应用的管理。下图是Serverless Devs桌面客户端管理应用界面。
通过Serverless Devs桌面客户端管理应用
其他配套功能的使用如下。如图所示为一键压测函数性能。
通过Serverless Devs桌面客户端一键压测函数性能
一键对函数资源进行调试,如图所示。
通过Serverless Devs桌面客户端一键对函数资源进行调试
一键查看函数多维度指标信息,如图所示。
通过Serverless Devs桌面客户端一键查看函数多维度指标信息
除此之外,Serverless Devs还拥有较为方便的Yaml可视化配置功能,如下图所示。
通过Serverless Devs桌面客户端进行Yaml可视化配置
二、如何对Serverless应用进行调试
在应用开发过程中,或者应用开发完成后,当执行结果不符合预期时,通常要进行一定的调试。但是在Serverless架构下,调试往往会受到极大的考验,尤其在受环境因素限制时,通常会出现这样的情况:所开发的应用在本地可以健康、符合预期地运行,但是在FaaS平台上则有一些不可预测的问题;或者在一些特殊环境下,本地没有办法模拟线上环境,难以进行应用的调试。Serverless应用的调试一直备受诟病,但是各个云厂商并没有因此放弃在调试方向上的深入探索,下面我们介绍几种方式。
1.在线调试
(1)简单调试
所谓的简单调试,就是在控制台进行调试。以阿里云函数计算为例,可以在控制台通过“代码执行”按钮进行基本的调试,如下图所示。
必要的时候也可以通过设置Event来模拟一些事件。
在线调试的好处是可以使用一些线上环境进行代码的测试。当线上环境拥有VPC等资源时,在本地环境是很难进行调试的。
(2)断点调试
除了简单的在线调试之外,部分云厂商还支持断点调试,例如阿里云函数计算的远程调试。我们以阿里云函数计算远程调试为例,可以实现通过控制台进行函数的在线调试。当创建好函数之后,可以选择远程调试,并单击“开启调试”按钮,如图所示。
函数计算远程调试页面
开启调试之后,稍等片刻,系统将会进入远程调试界面,如图所示。
函数计算远程调试开始页面当出现图
当出现下图所示界面,我们可以进行断点调试。
函数计算远程调试断点调试页面
2.端云联调
在本地进行Serverless应用开发时,往往会涉及一些线上资源,例如通过对象存储触发器触发函数执行,通过VPC访问数据库等,此时线上和线下环境不一致会让线下开发、调试面临极大的挑战。Serverless Devs开发者工具通过搭建Proxy辅助函数的方法将线上和线下资源打通,可以快速帮助开发者在本地进行应用的开发与调试,这种调试方式称为端云联调。
如下图所示, Serverless Devs开发者工具会根据Yaml配置文件,创建辅助服务和辅助函数,并通过辅助服务和辅助函数实现线上和线下资源打通,以及完整的端云联调。
Serverless Devs端云联调原理示意图
Serverless Devs 开发者工具会根据Yaml配置文件的内容,创建辅助服务和辅助函数(辅助服务和Yaml中所声明的业务服务配置是一致的)。
通过触发器(包括通过SDK、API、s proxied invoke命令,或者其他触发器)触发辅助函数(函数计算C),请求流量回到本地调试实例(本地环境A),这时本地调试实例(本地函数执行环境容器)收到的event和context是真实来自线上的。
本地调试实例(本地环境 A)可以直接访问以下内容:
- VPC 内网资源,比如RDS、Kafka内网地址等;
- 一些云服务的内网地址;
- 硬盘挂载服务(直接访问 NAS)。
端云联调流程如下:
1)执行s proxied setup命令准备端云联调所需的辅助资源以及本地环境;
2)对于无触发器的普通事件函数或者HTTP触发器,准备工作完成后,启动另一个新的终端,切换到该项目路径下,执行s proxied invoke命令调用本地函数;
3)完成调试任务后,执行s proxied cleanup命令清理端云联调所需的辅助资源以及本地环境。
除了通过命令使用端云联调功能外,我们也可以在VSCode开发者工具中使用端云联调功能,如图所示。
在VSCode中使用端云联调功能
3.远程调试
端云联调在本地除了有一个通道服务容器外,还有一个函数计算容器,用来执行本地函数;远程辅助函数只是单纯将远程流量发送到本地。在实际调试过程中,需要登录到实例进行项目调试,此时可以选择使用远程调试。
相比于端云联调,远程调试在本地只有一个通道服务容器,执行过程全部依赖线上;远程函数将执行结果返回。远程调试整体架构简图如图所示。
除了通过上面远程调试架构简图所示的通道服务登录线上环境进行代码调试或问题定位之外,部分云厂商还提供了直接登录实例进行代码调试的功能。以Serverless Devs为例,当使用阿里云函数计算时,我们就可以直接通过instance命令进行线上实例登录。
尽管实例登录命令已经提供了便捷的登录体验,能帮助用户解决复杂场景下的应用异常定位等问题,但是登录实例后,用户无法直接通过函数日志、监控指标来具体定位问题,还需要借助例如 coredump、tcpdump、jmap 等工具进行问题的深入排查。
例如,某用户发现自己的线上程序最近出现一些函数错误提示,报错内容都是连接远程某服务时超时。该用户怀疑是函数实例与远端服务的网络连接不稳定,因此想进入实例内部,分析实例与远端服务的网络情况。此时,我们可以按照以下步骤进行问题的排查。
1)如图所示,登录实例内部后,需要执行 apt-get update 和 apt-get install tcpdump 两条命令,进行tcpdump 工具的安装。
2)安装完毕后,执行tcpdump 命令,对远端服务 IP 的请求进行抓包,并将抓包结果保存在 tcpdump.cap 文件中。
3)抓包完毕后,借助 OSS 命令行工具 ossutil64,将 tcpdump.cap 文件上传到自己的 OSS,然后下载到本地借助分析工具Wireshark进行分析。
4.本地调试
(1)命令行工具
大部分FaaS平台会为用户提供相对完备的命令行工具,如阿里云的Funcraft,同时也有一些开源项目如Serverless Framework、Serverless Devs等支持多云厂商的FaaS平台。通过命令行工具进行代码调试的方法很简单。以Serverless Devs为例,本地调试阿里云函数计算方法为:首先确保本地拥有一个函数计算的项目,然后在项目下执行调试指令,例如在Docker中进行调试,如下面所示。
通过命令行进行本地调试
(2)编辑器插件
以VSCode插件为例,下载好阿里云函数计算的VSCode插件,并且配置好账号信息之后,在本地新建函数,并且在打点之后进行断点调试,如图所示。
编辑器插件中进行调试
5.其他调试方案
(1)Web框架的本地调试
以Python语言Bottle框架为例,若在阿里云FaaS平台开发传统Web框架,可以增加如下代码:
app = bottle.default_app()
并且对run()方法进行条件限制(if __name__ == '__main__'):
if __name__ == '__main__': bottle.run(host='localhost', port=8080, debug=True)
例如:
# index.py import bottle @bottle.route('/hello/<name>') def index(name): return "Hello world" app = bottle.default_app() if __name__ == '__main__': bottle.run(host='localhost', port=8080, debug=True)
和传统开发思路一样,我们可以在本地开发并在本地进行调试。当部署到线上时,只需要在入口方法处设置index.app,即可实现平滑的部署。
(2)本地模拟事件调试
针对非Web框架,可以在本地构建一个方法,例如要调试对象存储触发器,代码如下:
import jsondef handler(event, context): print(event)def test(): event = { "events": [ { "eventName": "ObjectCreated:PutObject", "eventSource": "acs:oss", "eventTime": "2017-04-21T12:46:37.000Z", "eventVersion": "1.0", "oss": { "bucket": { "arn": "acs:oss:cn-shanghai:123456789:bucketname", "name": "testbucket", "ownerIdentity": "123456789", "virtualBucket": "" }, "object": { "deltaSize": 122539, "eTag": "688A7BF4F233DC9C88A80BF985AB7329", "key": "image/a.jpg", "size": 122539 }, "ossSchemaVersion": "1.0", "ruleId": "9adac8e253828f4f7c0466d941fa3db81161****" }, "region": "cn-shanghai", "requestParameters": { "sourceIPAddress": "140.205.***.***" }, "responseElements": { "requestId": "58F9FF2D3DF792092E12044C" }, "userIdentity": { "principalId": "123456789" } } ] } handler(json.dumps(event), None)if __name__ == "__main__": print(test())
这样通过构造一个event对象,即可实现模拟事件触发。
三、通过开发者工具进行依赖安装和项目构建
Serverless架构下的应用开发和传统架构下的应用开发有一个比较大的区别是二者所关注的内容维度是不同的,例如理想状态下的前者并不需要人们关注服务器等底层资源。
但是在当今的Serverless发展阶段,Serverless架构下的应用开发真的不需要人们对服务器等额外关注吗?其实不是的,虽然Serverless架构强调的是Noserver心智,但是在实际生产中,有很多依赖等是无法跨平台使用的,例如Python语言中的某些依赖需要进行二进制编译,和操作系统、软件环境等有比较大的关系,所以项目中如果引入这类依赖,需要在和函数计算平台线上环境一致的环境中进行依赖的安装、代码的打包或项目的部署。
阿里云函数计算对自身的线上函数环境有比较细致的描述,提供了相应地文档,例如使用C、C++ 、Go编译的可执行文件,需要与函数计算的运行环境兼容。
函数计算的Python运行环境如下。
●Linux内核版本:Linux 4.4.24-2.al7.x86_64。
●Docker基础镜像:docker pull python:2.7 ; docker pull python:3.6。
但是,在实际应用开发过程中,依赖的打包依旧是让一众开发者头疼的事情。他们在很多Serverless应用开发过程中都会面临类似的挑战:项目在本地可以正常运行,一发布到线上就找不到某个依赖,但是实际上依赖是存在的,此时问题定位就成了非常困难的事情。
目前来看,为Serverless应用安装依赖或者项目构建的方法通常有3种:
1)在本地创建项目之后,自行根据云厂商提供的环境数据进行线上环境搭建,进而进行依赖的安装。这种方法相对来说自主可控,但是难度非常大,操作较为烦琐。
2)用已有的开发者工具进行依赖的安装,如图所示:
以Serverless Devs开发者工具以及阿里云函数计算产品为例,开发者只需要按照语言习惯准备对应语言的相关依赖安装文件即可,例如Python语言的requirements.txt,Node.js语言的package.json等。然后在当前项目下,执行s build --use-docker命令即可完成与阿里云函数计算平台线上环境一致的环境中的依赖的安装。以Python项目为例,开发者只需要在项目目录下完成如下操作:
1开发源代码;
2执行s build –use-docker命令之后,自动根据requirements.txt文件下载对应的依赖到本地,并且和源码一起组成交付物;
3执行s deploy命令将整个交付物打包,创建函数,同时设置好依赖包的环境变量,让函数可以直接输入对应的代码依赖包。
3)目前,部分云厂商的FaaS平台控制台支持WebIDE,阿里云的WebIDE拥有实现命令行程序的能力,所以也可以在控制台的WebIDE中直接进行依赖的安装。在线安装依赖示意图如图所示:
在线安装依赖示意图
更多内容关注阿里云 Serverless 微信公众号(ID:serverlessdevs),汇集 Serverless 技术最全内容,定期举办 Serverless 活动、直播,用户最佳实践。