|
| 1 | +# 上线 Python 应用仅需一条命令的开源框架:Zappa(详细教程) |
| 2 | + |
| 3 | +> 本文面向有 Python Web 基础的小伙伴 |
| 4 | +
|
| 5 | + |
| 6 | + |
| 7 | +作者:HelloGitHub-吱吱 |
| 8 | + |
| 9 | +这里是 **HelloGitHub 推出的[《讲解开源项目》](https://github.com/HelloGitHub-Team/Article)系列**,今天要向小伙伴们介绍一个 Python 无服务(Serverless)框架 Zappa。 |
| 10 | + |
| 11 | +Zappa 让我们可以轻松部署 Python 应用程序:仅需几条命令、打包代码、上传云服务器、程序上线,bingo 一气呵成!从此减少部署成本,放下运维的重担。仅需你有一点点 Python Web 基础! |
| 12 | + |
| 13 | +它到底有多便捷?下面就让我们上手来试试吧! |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +> 项目地址:https://github.com/Miserlou/Zappa |
| 18 | +
|
| 19 | +## 一、前言 |
| 20 | + |
| 21 | +### 1.1 介绍 Serverless |
| 22 | + |
| 23 | +刚开篇便提到了一个~~莫名其妙~~的名词:**无服务(Serverless)**,一开始我也是问号脸,经过多方搜证,我们可以简单的认为 Serverless 是指不必担心底层基础结构,不需要管理服务器,从而来构建和运行应用程序。具体概念小课堂如下: |
| 24 | + |
| 25 | +#### 1.1.1 什么鬼? |
| 26 | + |
| 27 | +回忆一下,平时上线一个简单的 Python Web 应用的过程。 |
| 28 | + |
| 29 | +- 一个 24 小时不间断运行的服务器:比如云主机,用以搭建代码运行环境和进行系统配置,维持着运行我们的应用; |
| 30 | +- 部署 Web 服务器:我们需要选择合适的 Web 服务器,经过配置和启动,实现反向代理和负载均衡; |
| 31 | +- 域名绑定:最后如果要被广泛用户访问,我们需要注册域名,并且绑定在服务器; |
| 32 | +- 运营维护:配置和启动在应用上线之后,我们还需要管理和维护我们的服务器,预防黑客攻击,应对未来用户访问高峰期。 |
| 33 | + |
| 34 | +而对于使用 Serverless 架构的应用,我们只需要关心我们的应用编写和核心业务,无需操心云主机、操作系统、资源分配和 Web 服务器配置等相关问题,无需考虑服务器的规格大小、存储类型、网络带宽、自动扩缩容问题,无需再对服务器进行运维、不断打系统补丁和应用补丁、无需进行数据备份等工作。一切非核心业务都外包给了公共云营运商,让开发人员从复杂的部署和运维环境中脱身出来,专注于业务本身的价值。 |
| 35 | + |
| 36 | +用 Zappa 里的一句话说就是 **“without any permanent infrastructure”**(无需任何永久性基础设施)。 |
| 37 | + |
| 38 | +敲黑板,尽管从名字上说是 Serverless,但是仍然需要物理服务器,只是我们开发人员成了甩手掌柜。 |
| 39 | + |
| 40 | +#### 1.1.2 好处有? |
| 41 | + |
| 42 | +- 降低运维需求和维护成本; |
| 43 | +- 完全自动化的弹性扩容和缩容:在业务高峰期时,产品的计算能力和容量自动扩大,承载更多的用户请求;反之,在业务下降时,所使用的资源也会同时收缩,避免资源浪费; |
| 44 | +- 节省开支,全新的计量计费模式:开发者仅需根据使用量来付费。在无业务量的情况下,不会有空闲资源占用,也不会有费用产生。 |
| 45 | + |
| 46 | +#### 1.1.3 普遍认为 Serverless = FaaS + BaaS |
| 47 | + |
| 48 | +- BaaS(Backedn as a Service 后端即服务) |
| 49 | + - 后端,指的就是各种云产品和云服务,例如对象存储 OS ,消息队列 MQ,云数据库 DB,云缓存 Redis以及各种以 API 形式提供的服务。用户直接开通即可使用,无需考虑部署、扩容、备份、安全等各种运维工作。 |
| 50 | +- FaaS(Functions as a Service 函数即服务) |
| 51 | + - 是 Serverless 的核心,让用户仅需编写和上传核心业务代码,交由平台完成部署、调度、流量分发和弹性伸缩等能力,它提供了一种新的方式来提供计算资源,进一步降低云计算的使用门槛。 |
| 52 | + |
| 53 | +#### 1.1.4 AWS Lambda |
| 54 | + |
| 55 | +在该项目中,伸手白嫖[ AWS 海外区域账户免费 AWS Lambda 套餐](https://amazonaws-china.com/cn/free/?cs-awsft-actsft&sc_channel=ta&sc_campaign=freetier_crosslink&sc_country=cn&sc_geo=chna&sc_category=mult&sc_outcome=acq&trkCampaign=freetier_crosslink_acts&trk=request_for_pilot_account&all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc)。[AWS Lambda](https://amazonaws-china.com/cn/lambda/?did=ft_card&trk=ft_card) 作为 Serverless 最早的框架产品由亚马逊在2014年推出,是一种无服务器的计算服务,无需预置或管理服务器即可运行代码。Lambda 几乎可以为任何类型的应用程序或后端服务运行代码,我们只需上传相应的代码,它会处理运行和扩展代码所需的一切工作。 |
| 56 | + |
| 57 | + |
| 58 | + |
| 59 | +### 1.2 Python 的 Serverless 框架 |
| 60 | + |
| 61 | +本篇文章的主角:Zappa 登场!我们可以通过 Zappa 工具体验一下 Serverless 技术,用它实现我们 Python 应用程序的无服务器部署,初步体验无限伸缩扩展、零宕机、零维护的快捷。有了 Zappa,我们无需: |
| 62 | + |
| 63 | +- **配置** Web 服务器 |
| 64 | +- **付费** 24/7 服务器的正常运行时间 |
| 65 | +- **担心**负载平衡和可扩展性 |
| 66 | +- **保持**自己的服务器时刻在线状态 |
| 67 | + |
| 68 | +## 二、亲自动手 |
| 69 | + |
| 70 | +实战时间:已经实验(踩坑)成功(不断)的我就来分享部署一个简单的 `Flask` 应用的过程,不要担心跟着做你也可以~ |
| 71 | + |
| 72 | +### 2.1 环境 |
| 73 | + |
| 74 | +1. Python版本要求:3.6/3.7/3.8 |
| 75 | +2. 测试系统:Ubuntu 18.04.4 LTS |
| 76 | + |
| 77 | +### 2.2 准备 |
| 78 | + |
| 79 | +1. **保证**自己的项目是运行在[虚拟环境](https://docs.python-guide.org/dev/virtualenvs/)下。 |
| 80 | + |
| 81 | + ```bash |
| 82 | + # 需要安装 Python 3.x 版本 |
| 83 | + python --version |
| 84 | + |
| 85 | + # 安装 Pipenv |
| 86 | + pip install --user pipenv |
| 87 | + |
| 88 | + # 进入自己的项目 |
| 89 | + cd demo |
| 90 | + |
| 91 | + # 实例化 pipfile 和 venv |
| 92 | + pipenv shell |
| 93 | + ``` |
| 94 | + |
| 95 | +  |
| 96 | + |
| 97 | +2. **安装** Zappa 和 Flask,项目需要其他库的话,可自行添加。 |
| 98 | + |
| 99 | + ```bash |
| 100 | + $ pipenv install zappa flask |
| 101 | + ``` |
| 102 | + |
| 103 | +  |
| 104 | + |
| 105 | +3. 在目录下创建 `my_app.py` 文件,写入官方样例,可以先 `pipenv run python my_app.py`看看是否能正常运行 |
| 106 | + |
| 107 | + ```python |
| 108 | + from flask import Flask |
| 109 | + app = Flask(__name__) |
| 110 | +
|
| 111 | + @app.route('/') |
| 112 | + def hello(): |
| 113 | + return "hello, from Zappa!\n" |
| 114 | +
|
| 115 | + if __name__ == '__main__': |
| 116 | + app.run() |
| 117 | + ``` |
| 118 | +
|
| 119 | +4. [注册 AWS 账户](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html?nc2=h_ct&src=default),并且正确安装 AWS credentials file |
| 120 | +
|
| 121 | + - 登录 AWS,找到 `My Security Credentials` 下的 `Access keys (access key ID and secret access key)` ,如果没有则创建一个,记住 `access key ID` 和 `secret access key` |
| 122 | +
|
| 123 | + - 安装 AWS 的命令行界面,添加 credentials |
| 124 | +
|
| 125 | + ```bash |
| 126 | + # 在虚拟环境下安装 |
| 127 | + pipenv install awscli |
| 128 | +
|
| 129 | + # 查看信息 |
| 130 | + aws configure list |
| 131 | +
|
| 132 | + # 添加,并且按照提示将 access key ID 和 secret access key 填入 |
| 133 | + aws configure |
| 134 | +
|
| 135 | + # 后两个 region name 和 output format 选填 |
| 136 | + ``` |
| 137 | + |
| 138 | +  |
| 139 | + |
| 140 | + - 此时在 `~/.aws` 目录下会出现两个文件 config 和 credentials,credentials 中储存了 AWS 的 ` access key ID` 和 `secret access key`, config 中储存了 region name 和 output format 信息。 |
| 141 | + - 如果是在 Windows 上操作的同学,可以查看官方提供的安装 AWS credentials file 的[教程](https://amazonaws-china.com/cn/blogs/security/a-new-and-standardized-way-to-manage-credentials-in-the-aws-sdks/)。 |
| 142 | +
|
| 143 | +### 2.3 安装与配置 |
| 144 | +
|
| 145 | +1. 通过执行下面语句进行初始化,定义部署和配置的设置,自动检测应用类型(Flask 或 Django) |
| 146 | +
|
| 147 | + ```bash |
| 148 | + $ zappa init |
| 149 | + ``` |
| 150 | +
|
| 151 | + 在执行过程中,可能需要如下设置,后续也可以在新生成的 `zappa_setting.json` 的配置文件中修改: |
| 152 | +
|
| 153 | +  |
| 154 | +
|
| 155 | + 完成后,我们的项目目录中将有一个 `zappa_settings.json` 文件,里面是我们刚刚定义的基本部署设置,后期我们可以按照自己的需求修改此文件。 |
| 156 | +
|
| 157 | + ```json |
| 158 | + { |
| 159 | + "dev": { |
| 160 | + "app_function": "my_app.app", |
| 161 | + "profile_name": null, |
| 162 | + "project_name": "demo", |
| 163 | + "runtime": "python3.6", |
| 164 | + "s3_bucket": "zappa-ti0ra29xi" |
| 165 | + } |
| 166 | + } |
| 167 | + ``` |
| 168 | +
|
| 169 | +2. 注意如果之前已经在 `~/.aws/config` 文件中添加 region 信息,则会在 `zappa init` 的时候自动寻找到这些 region 信息,无需后续修改。 |
| 170 | + |
| 171 | + 如果之前没有添加,则修改 `zappa_settings.json`,添加 region 信息如下: |
| 172 | + |
| 173 | + ```bash |
| 174 | + # 修改如下 |
| 175 | + { |
| 176 | + "dev": { |
| 177 | + "app_function": "my_app.app", |
| 178 | + "profile_name": null, |
| 179 | + "project_name": "demo", |
| 180 | + "runtime": "python3.6", |
| 181 | + "s3_bucket": "zappa-ti0ra29xi" |
| 182 | + "aws_region": "us-west-2" |
| 183 | + } |
| 184 | + } |
| 185 | + ``` |
| 186 | + |
| 187 | + region 的信息可以自行选择,[具体信息请移步](https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html)。 |
| 188 | +
|
| 189 | +### 2.4 部署和使用 |
| 190 | +
|
| 191 | +配置设置后,可以使用如下命令将应用程序打包并部署: |
| 192 | +
|
| 193 | +```bash |
| 194 | +$ zappa deploy dev |
| 195 | +``` |
| 196 | +
|
| 197 | +当我们调用 deploy 时,Zappa 会自动将我们的应用程序和本地虚拟环境打包到 Lambda 兼容的 archive,用为 Lambda 预先编译的版本替换所有依赖项,设置功能处理程序和必要的 WSGI 中间件,然后上传 archive 到 S3,创建和管理必要的Amazon IAM 策略和角色,将其注册为新的 Lambda function,创建新的 API 网关资源,为其创建 WSGI 兼容的路由,将其链接到新的 Lambda function,最后从 S3 bucket 中删除 archive。 |
| 198 | +
|
| 199 | +执行成功后,就会出现一个链接,点击链接即可访问我们的简易 Web 应用。看到已上线的应用程序,心内窃喜,直呼快准狠。 |
| 200 | +
|
| 201 | + |
| 202 | +
|
| 203 | +## 三、其他命令 |
| 204 | +
|
| 205 | +1. 更新操作:假设应用程序已经部署完毕,并且只需要上传新的Python代码,而无需修改基础路由,则可以执行以下操作: |
| 206 | +
|
| 207 | + ```bash |
| 208 | + $ zappa update dev |
| 209 | + ``` |
| 210 | +
|
| 211 | + 这将创建一个新的 archive,将其上传到 S3 并更新 Lambda function 以使用新代码。 |
| 212 | +
|
| 213 | +2. 查看部署和事件计划的状态,只需使用命令: |
| 214 | +
|
| 215 | + ```bash |
| 216 | + $ zappa status production |
| 217 | + ``` |
| 218 | +
|
| 219 | +3. 查看部署的日志: |
| 220 | +
|
| 221 | + ```bash |
| 222 | + $ zappa tail dev |
| 223 | +
|
| 224 | + # 过滤 HTTP 请求 |
| 225 | + $ zappa tail dev --http |
| 226 | +
|
| 227 | + # 执行相反操作,并且仅显示非 HTTP 事件和日志消息 |
| 228 | + $ zappa tail dev --non-http |
| 229 | +
|
| 230 | + # 选择时长 |
| 231 | + $ zappa tail dev --since 4h # 4 hours |
| 232 | + ``` |
| 233 | +
|
| 234 | +4. 回滚操作: 通过提供要返回的修订版本数将部署的代码回滚到以前的版本。 |
| 235 | +
|
| 236 | + ```bash |
| 237 | + # 回滚到3年前部署的版本 |
| 238 | + $ zappa rollback production -n 3 |
| 239 | + ``` |
| 240 | +
|
| 241 | +5. 安排 function 定期执行:修改 `zappa_setting.json` ,加入如下内容: |
| 242 | +
|
| 243 | + ```json |
| 244 | + { |
| 245 | + "dev": { |
| 246 | + ... |
| 247 | + "events": [{ |
| 248 | + // The function to execute |
| 249 | + "function": "your_module.your_function", |
| 250 | + // When to execute it (in cron or rate format) |
| 251 | + "expression": "rate(1 minute)" |
| 252 | + }], |
| 253 | + ... |
| 254 | + } |
| 255 | + } |
| 256 | + ``` |
| 257 | +
|
| 258 | + 然后执行如下操作,我们的 function 就会在每分钟执行一次。 |
| 259 | +
|
| 260 | + ```bash |
| 261 | + $ zappa schedule dev |
| 262 | +
|
| 263 | + # cancal |
| 264 | + $ zappa unschedule dev |
| 265 | + ``` |
| 266 | +
|
| 267 | +6. 取消部署:如果要删除以前发布的 API Gateway 和 Lambda function,则只需: |
| 268 | +
|
| 269 | + ```bash |
| 270 | + $ zappa unschedule dev |
| 271 | + ``` |
| 272 | +
|
| 273 | +## 四、踩坑建议 |
| 274 | +
|
| 275 | +在成功运行一次之前,踩坑千千万万遍,都是因为自己手残眼瞎魔改了很多地方,把经历过的报错记录下来,分享给和我一样的小小白。 |
| 276 | +
|
| 277 | +1. `“Unable to import module ‘handler’: attempted relative import with no known parent package”`:原因是我们期望的依赖在虚拟的环境中没有,需要查看自己虚拟环境中的依赖是否完整,[解决请移步](https://medium.com/@gregorypierce/unable-to-import-module-handler-attempted-relative-import-with-no-known-parent-package-f3545ab91df1)。 |
| 278 | +
|
| 279 | +2. 出现如下报错,可以更换一个 region 信息,[解决请移步](https://github.com/Miserlou/Zappa/issues/1194)。 |
| 280 | +
|
| 281 | + ```bash |
| 282 | + $ zappa deploy dev |
| 283 | + Calling deploy for stage dev.. |
| 284 | + Creating demo-dev-ZappaLambdaExecutionRole IAM Role.. |
| 285 | + Error: Failed to manage IAM roles! |
| 286 | + You may lack the necessary AWS permissions to automatically manage a Zappa execution role. |
| 287 | + Exception reported by AWS:An error occurred (InvalidClientTokenId) when calling the CreateRole operation: The security token included in the request is invalid. |
| 288 | + To fix this, see here: https://github.com/Miserlou/Zappa#custom-aws-iam-roles-and-policies-for-deployment |
| 289 | + ``` |
| 290 | +
|
| 291 | +3. 如果我们在 `zappa init` 的时候,不使用默认分配的 `s3_bucket` ,则须注意自己的名称是不允许重名的,点击查看[官方方法](https://amazonaws-china.com/cn/premiumsupport/knowledge-center/s3-error-bucket-already-exists/),否则会报错 `botocore.errorfactory.BucketAlreadyExists: An error occurred (BucketAlreadyExists) when calling the CreateBucket operation: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.` 。 |
| 292 | +
|
| 293 | +## 五、写在最后 |
| 294 | +
|
| 295 | +是不是当自己成功部署后,突然觉得妙不可言,一身轻松,好像再也没有了之前所说的繁琐的过程,反而几条命令,白嫖 AWS 的服务,咱的应用程序就轻巧上线了呢,还不赶紧把生成的链接分享给小伙伴们点击一下。 |
| 296 | +
|
| 297 | +至此,我们已经可以基本实现快速部署一个简单的 Flask 应用了,由于篇幅有限,还有部分 Zappa 的高级功能没有提及,以及如何使用 Zappa 部署 Django 应用或者一个更为庞大的项目(包含数据库等),希望感兴趣的小伙伴们能够多多尝试,我已经开始期待的搓搓手了。如果大家对开源项目感兴趣,请第一时间关注我们 HelloGitHub,我们将会为大家带来更多有趣的干货内容。 |
0 commit comments