如何在15分钟内构建一个无服务器服务?
消息来源:baojiabao.com 作者: 发布时间:2024-11-01
“无服务器”(Serverless)这个词已经流行了有一段时间了。
亚马逊在2015年发布了AWS Lambda服务之后,出现了许多工具,利用这些工具只需几个命令就可以建个无服务器服务。与传统的服务相比,无服务器服务具有容易开发、容易部署、容易维护的特点。它们的性价比还非常高,特别是对于那些没有太大流量的简单服务。
什么是无服务器?
顾名思义,“无服务器”就是说运行服务的时候不需要服务器。准确地说,服务依然是跑在服务器上的,但是作为开发者,你不需要考虑服务器的问题。
以AWS Lambda为例,你可以写一个“函数”部署到Lambda上,这个函数可以处理HTTP请求。AWS会跑一个服务器,负责运行所有函数,每当你的HTTP endpoint被访问时,Lambda就会调用你的函数来处理请求。但服务器的事情完全不需要你操心,你要做的只有写个函数,然后扔到Lambda上。
这种服务最大的好处就是非常便宜。还以AWS Lambda为例,Lambda每个月提供免费的100万次访问,和40万GB秒的计算力(1GB秒的意思是你的运算可以占用1GB的内存1秒钟)——对于绝大部分的小型服务来说这就足够了。相比之下,EC2的nano实例的费用是每小时$0.0058,折合每天$0.14,还是Lambda要便宜得多。
用AWS部署一个无服务架构的个人网站
在这篇文章里我想介绍下怎样利用AWS部署一个无服务架构的个人网站。这个个人网站将具备以下特点:
包含前端和后端;
基本上以静态文件为主,或者主要的计算都在前端(比如React应用);
与后台通过API通信,但数量非常少;
后台不需要太大内存或CPU(比如一个简单的网页计数器,每次请求只需要访问一次数据库)。
服务将部署到以下域名上(这里用的都是假想的域名):
API服务:https://myservice-api.example.com
前端:https://myfrontend.example.com
这里用了HTTPS,因为各大浏览器早已开始将HTTP协议标记为不安全协议了。为了保证安全,HTTPS是必要的,后面会介绍如何设置证书等。
整个网站将使用以下的AWS服务:
Lambda + API Gateway + S3,用于跑API服务器;
DynamoDB,数据存储;
S3,静态网站;
Cloudfront,分散式CDN,用作静态网站和API的前端;
AWS Certificate Manager(ACM),为https网站生成证书。
至于API服务器的开发部署,我们采用Python + Flask的组合开发服务,然后用Zappa(https://github.com/Miserlou/Zappa)作为无服务器部署工具。
设置AWS环境
首先需要设置AWS环境,以便从代码和zappa中访问AWS。需要两个步骤:
创建AWS用户,用于程序访问;
设置本地环境,使代码使用AWS用户。
创建AWS用户
登录到AWS中,选择“IAM”服务来管理用户。
创建一个名为“myservice-admin”的用户(或者任何你喜欢的用户名),勾选“Programmatic access”选项。
在下一步中,点击“Attach existing policies directly”按钮,然后将“AdministratorAccess”添加到该用户。
从安全的角度来说这种做法并不好。不过出于演示的目的,本文不再详述怎样找出部署无服务架构所需的许可权了。
点击“Next”按钮,最后点击“Create User”按钮,myservice-admin用户就建好了。注意在创建成功的那个画面上会显示Access Key ID和Secret access key两个值。务必要将这两个复制保存下来,稍后要用它们来设置本地环境。
这个画面是唯一能看到Secret access key的地方!如果你忘了复制就关闭了页面,那就只能去用户的详细画面去生成新的access key和secret了。
设置本地AWS环境
为了在本地使用AWS,我们需要创建本地环境。
首先安装awscli工具,用它来帮我们配置环境:
安装结束后,就可以使用aws configure命令进行设置:
这里需要输入上一步保存下来的Access Key ID和Secret Access Key值。至于区域,我用的是us-east-1。其他区域应该也可以,但如果你要像我一样使用CloudFront的话,其他区域可能会有一些麻烦。
在DynamoDB中创建表
我们的后台API要实现一个计数器。为了保存计数器的数值,我们需要使用DynamoDB。DynamoDB是AWS提供的一个键值数据库。首先我们需要在DynamoDB中建一个表,并设置好我们需要的计数器初始值。
在AWS控制台中选择DynamoDB服务,然后点击“Create Table”按钮。在“Create DynamoDB table”画面,在Table name中填写myservice-dev,Primary key字段填写id,然后点击Create Table按钮。
几秒钟之后表就建好了。选择刚刚建好的表,然后在右侧选择Items选项卡,单击Create item按钮创建一个项目,项目内容为id="counter"及counter_value=0。
创建值时需要点击左侧的加号按钮才能添加counter_value属性,而且别忘了把counter_value属性的类型设置为Number。
创建API服务
接下来我们要建立API服务。这个API将提供一个计数器API,每次调用都会将计数器的值加一。计数器值保存在DynamoDB中。API的endpoint如下:
POST /counter/increase:增加计数器的值,并返回计数器值;
GET /counter:返回计数器值。
用Python和Flask编写API服务
首先我们要创建Python虚拟环境,并安装必要的包:
Flask是Web框架,boto3是访问DynamoDB必须的包。simplejson可以解决一些JSON转换时遇到的问题。接下来创建myservice.py,内容如下:
再创建一个run.py,以便在本地测试该服务:
运行服务:
这样就可以在命令行中测试这个服务了(再开一个终端输入下面的命令):
我们可以看到计数器的值增加了,说明这个服务可以用了!
将服务部署到Lambda上
要部署API到Lambda上,可以使用Zappa包。Zappa包使得部署微服务变得极其容易。首先安装Zappa:
然后执行Zappa init命令初始化Zappa环境。它会问你几个问题,但基本上可以使用默认值来回答:
初始化完成后,在目录下会生成一个zappa_settings.json文件。然后就可以部署服务了:
现在我们的服务就部署成功了。可以用下面的Curl命令测试,也可以打开浏览器测试GET的API:
绑定自定义域名
不过上面的API服务还有一个小问题。自动生成的API endpoint是2ks1n5nrxh.execute-api.us-east-1.amazonaws.com,很难记也不好用。不过我们可以很容易地给它绑定一个自定义域名。
我们的自定义域名是https://myservice-api.example.com。为了使用HTTPS,我们需要现申请一个证书。AWS的Certificate Manager服务提供免费的证书。生成证书之后就可以在AWS的API Gateway里自定义域名了。
申请证书
从AWS控制台切换到ACM服务(服务名称叫Certificate Manager,但敲ACM就能搜索到)。点击Request a certificate按钮,然后选择Request a public certificate选项。选择公开的证书就是免费的。
下一步,我们需要向AWS证明我们拥有这个域名。我这个域名是从Google Domains申请的,所以我在这里选择DNS validation。点击Review按钮然后点击Confirm and Request。
现在证书请求已经生成了,AWS会显示一个验证画面,上面写明了怎样验证该域名:
根据说明,我们需要在域名下添加一条CNAME记录。由于我的域名是从Google Domains申请的,我就打开Google Domains,找到域名example.com,然后添加上面指定的CNAME:
这里在Name栏中只添加了_2adee19a0967c7dd5014b81110387d11字元串,去掉了后面的.example.com部分,否则.example.com就重复了。
接下来要等待大约10分钟,AWS Certificate Manager就会去验证域名了。验证成功后,Status栏会显示“Issued”。
现在证书已经申请好了,我们可以继续去给API绑定域名。
为API服务绑定自定义域名
切换到API Gateway服务。从左侧的APIs一栏可以看到,Zappa已经帮我们建好了myservice-dev服务。
从左侧点击“Custom Domain Names”,然后点击右侧的Create Custom Domain Name按钮,填写必要的字段。
这里我希望API使用CloudFront服务,这样能在全世界都达到最理想的访问速度,因此我选择了Edge Optimized。如果不使用CloudFront,你可以选择Regional。
点击Save按钮后,这个自定义域名绑定就建好了。实际上要等待大约40分钟左右域名绑定才能正常使用,不过我们可以利用这段时间去配置DNS。
回到Google Domains添加这条CNAME:
该步骤完成后,等待大约40分钟,等API Gateway中的“Initializing...”字样消失后,自定义域名就可以使用了。
前端的静态网站
接下来我们要给这个API服务创建一个前端。作为例子,这里只创建一个非常简单的页面,它能调用/counter/increase。
前端编程
先建一个目录myfrontend:
然后建一个简单的HTML文件index.html:
将前端发布到S3
我们可以把前端部署到S3上。首先需要建一个桶,桶的名字就是域名。
接下来要把我们的网站放到这个桶中。打开该桶,选择Properties选项卡,然后选择Static Web Hosting。在弹出的对话框中选择Use this bucket to host a website,在Index document字段中输入index.html。点击Save关闭对话框。
上面显示了“Endpoint”链接,我们稍后会用这个URL测试静态网站。
最后一件事就是让这个桶允许公开访问。我们需要添加一个桶策略来实现这一点。打开这个桶,选择Permissions选项卡,然后点击Bucket Policy按钮。
保存之后,我们应该可以在Bucket Policy按钮上以及Permissions选项卡上看到橙色的“public”字样,表明我们的桶是可以被公开访问的。
这样桶就建好了,但里面还是空的,现在需要把网站的内容上传到这个桶中。首先进入刚才建好的myfrontend目录中,然后输入下面的命令:
上面的命令会把当前目录下(注意命令中的那个点 . )的所有文件都上传到S3中。
现在就完成了!在浏览器中打开下面的地址就可以看到网站内容了(地址就是前面创建桶时显示的Endpoint的URL):
嗯?貌似不太对。计数器没有显示任何值呢?
而且似乎有JavaScript错误。打开浏览器的控制台就能看到以下错误:
Failed to load https://myservice-api.example.com/counter: No "Access-Control-Allow-Origin" header is present on the requested resource. Origin "http://myfrontend.example.com.s3-website-us-east-1.amazonaws.com" is therefore not allowed access. If an opaque response serves your needs, set the request"s mode to "no-cors" to fetch the resource with CORS disabled.
显然,我们需要设置CORS header(https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)才能让这个脚本工作,因为后台API被放到了另一个域名上(myservice-api.example.com和myfront.example.com不是同一个域名)。
不过由于我们还要给前端绑定自定义域名,绑定后URL会发生变化,所以这里先放一放,等一会儿绑定好域名之后再来考虑CORS的问题。
给静态网站设置CloudFront和自定义域名
最后一步就是给前端设置CloudFront并绑定自定义域名。前面我们已经申请了*.example.com的证书,所以这一步就很容易了。
从AWS控制台中切换到CloudFront服务。点击Create Distribution按钮,然后点击Web里的Start按钮。
在“Create Distribution”画面上,我们需要填写以下信息:
创建好distribution后,就可以在distribution列表中看到CloudFront的域名了。
上面的状态还是“In Progress”,我们可以利用这段时间去设置DNS。跟前面类似,去Google Domains里添加一个CNAME:
解决CORS问题
现在唯一的问题就是CORS了。CORS是由于前端和后台的域名不一致导致的,为了让前端能访问后台API,我们需要给后台添加CORS支持。
回到API的代码目录(myservice),激活Python环境。然后安装flask_cors包:
然后编辑myservice.py,添加以下几行(3和6):
最后发布到AWS Lambda:
试着刷新下浏览器。现在就能看到计数器显示了正确的值。点击“Increase Counter”按钮也能增加计数器的值了。
总结
这篇文章介绍了创建一个简单的无服务器服务所需的多种AWS服务。如果你对AWS不熟悉,你可能会觉得我们用到了太多的服务,但其实绝大部分AWS服务都是一次性的,一旦设置好之后就不用再管了。以后的开发中用得上的只有zappa update和aws s3 sync两条命令而已。
而且至少,这种方法要比自己设置一台VPS、安装Web服务器再写个Jenkins脚本做持续部署要方便多了。
作为总结,下面是这篇文章的一些重点:
Lambda可以运行简单的服务,服务可以通过API Gateway暴露成HTTP服务;
如果要用Python写无服务器服务,那么Zappa是个非常方便的工具;
S3桶可以用作静态网站使用;
要想使用HTTPS,可以通过AWS ACM申请证书;
API Gateway和CloudFront都支持自定义域名。
希望这篇文章对你有所帮助!
相关文章
- B站怎么炸崩了哔哩哔哩服务器今日怎么又炸挂了?技术团队公开早先原因
2023-03-06 19:05:55
- 苹果iPhoneXS/XR手机电池容量续航最强?答案揭晓
2023-02-19 15:09:54
- 华为荣耀两款机型起内讧:荣耀Play官方价格同价同配该如何选?
2023-02-17 23:21:27
- google谷歌原生系统Pixel3 XL/4/5/6 pro手机价格:刘海屏设计顶配版曾卖6900元
2023-02-17 18:58:09
- 科大讯飞同传同声翻译软件造假 浮夸不能只罚酒三杯
2023-02-17 18:46:15
- 华为mate20pro系列手机首发上市日期价格,屏幕和电池参数配置对比
2023-02-17 18:42:49
- 小米MAX4手机上市日期首发价格 骁龙720打造大屏标准
2023-02-17 18:37:22
- 武汉弘芯遣散!结局是总投资1280亿项目烂尾 光刻机抵押换钱
2023-02-16 15:53:18
- 谷歌GoogleDrive网云盘下载改名“GoogleOne” 容量提升价格优惠
2023-02-16 13:34:45
- 巴斯夫将裁员6000人 众化工巨头裁员潮再度引发关注
2023-02-13 16:49:06
- 人手不足 韵达快递客服回应大量包裹派送异常没有收到
2023-02-07 15:25:20
- 资本微念与李子柒销声匿迹谁赢? 微念公司退出子柒文化股东
2023-02-02 09:24:38
- 三星GalaxyS8 S9 S10系统恢复出厂设置一直卡在正在检查更新怎么办
2023-01-24 10:10:02
- 华为Mate50 RS保时捷最新款顶级手机2022多少钱?1.2万元售价外观图片吊打iPhone14
2023-01-06 20:27:09
- 芯片常见的CPU芯片封装方式 QFP和QFN封装的区别?
2022-12-02 17:25:17
- 华为暂缓招聘停止社招了吗?官方回应来了
2022-11-19 11:53:50
- 热血江湖手游:长枪铁甲 刚猛热血 正派枪客全攻略技能介绍大全
2022-11-16 16:59:09
- 东京把玩了尼康微单相机Z7 尼康Z7现在卖多少钱?
2022-10-22 15:21:55
- 苹果iPhone手机灵动岛大热:安卓灵动岛App应用下载安装量超100万次
2022-10-03 22:13:45
- 苹果美版iPhone可以在中国保修 从哪看怎么查询iPhone的生产日期?
2022-09-22 10:00:07