lambda云函数更新支持python3.6
目录
关键词:aws、lambda、云函数、python3.6、运行时、依赖包
背景
有个用户在上传背景图,下次登录后背景图消失。
经过排查发现上传背景图,上传s3走的上传图片服务接口:lambda.9ong.com/uploadimg
而上传接口lambda.9ong.com/uploadimg 是aws上的lambda云函数服务。
问题
将代码调整后,在本地执行上传s3,但s3提示没有权限:
S3UploadFailedError: Failed to upload /tmp/jm-cqj.jpg to img6.9ong.com/jm-cqj_1642065228.jpg: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
经过确认比对,发现代码中的access_key与aws控制台的access_key不一致。判定是key被删导致。
理论上直接改代码,更新最新的密钥即可,但由于原云函数使用python2.7实现的功能,aws出于安全原因,不允许直接改python2.7的云函数,需要将python环境升级到3.6以上,而第三方包boto、PIL都需要更新,甚至io包的使用方式有所调整,需要在原来的基础之上进行调整修改。
支持python3.6的代码调整
这里忽略具体代码,这里默认代码测试是ok的。
代码与运行时依赖分离
旧版本代码上传是直接把逻辑代码文件与依赖包一起打到同一个zip包。详见:使用 .zip 文件归档部署 Python Lambda 函数 - AWS Lambda
但我们尝试过几次没有成功,一直报找到handler(handler.handler是入口文件handler.py的handler入口方法),后来发现其实就是异常错误了,比如:
其中有一次测试发现日志里报一个错误:
Unable to import module 'handler': libjpeg.so.8: cannot open shared object file: No such file or directory
结合AWS LambdaでPillow-SIMDを使用した際に起きたエラーの解決方法 - Qiita这篇文章,尝试将逻辑代码与依赖的python库和lib库分离。
看官方文档,关于lambda层的定义与创建:创建和共享 Lambda 层 - AWS Lambda
Lambda 层提供了一种方便的方法来打包库和其他可与 Lambda 函数搭配使用的依赖项。使用层可以缩小上传的部署存档的大小,并加快代码的部署速度。层还可促进代码共享和责任分离,以便您可以更快地迭代编写业务逻辑。
层是可以包含其他代码或数据的 .zip 文件存档。层可以包含库、自定义运行时、数据或配置文件。层可促进代码共享和责任分离,以便您可以更快地迭代编写业务逻辑。
层是可以包含库、自定义运行时、数据、配置文件的,但需要放在一个Lambda云函数能识别的path上:
运行时 | 路径 |
---|---|
Node.js | nodejs/node_modules |
Node.js | nodejs/node14/node_modules (NODE_PATH) |
Python | python |
Python | python/lib/python3.9/site-packages(站点目录) |
所有运行时 | bin (PATH) |
所有运行时 | lib (LD_LIBRARY_PATH) |
通过上表(来自上面的链接)我们就知道我们要构造的层的zip包结构是:
其中lib目录可以放比如前面缺失的libjpeg.so.8等文件,python目录用于存放依赖的第三方包 ,详见:如何生成依赖包的zip包?
这样就有了层的zip包:layer.zip。
然后对逻辑代码进行打包,打完的imageDeal.zip包如下:
如何生成运行时依赖的zip包
使用 .zip 文件归档部署 Python Lambda 函数 - AWS Lambda
我们是有依赖关系的部署程序包,参考上面文档,假设在mac或linux上:
我们先安装对应第三方包,创建一个package目录,将需要安装的第三方包下载到package目录:
mkdir lambda
# 准备python依赖包
cd lambda
mkdir python
pip3 install --target ./python qiniu
pip3 install --target ./python boto3
pip3 install --default-timeout=100 --target ./python Pillow
# 准备lib依赖
cd ..
mkdir lib
cp /usr/lib/x86_64-linux-gnu/libjpeg.so.8 lib/
# 压缩打包 ,在lambda目录下
zip -r layer.zip .
–default-timeout=100 用于解决read timeout问题,如果存在这种情况的话。
如果有必要时使用 sudo
运行时依赖zip包结构如下:
上传代码和依赖
创建层及上传
前面我们将python第三方依赖包和运行时依赖文件都打包到layer.zip,紧接着就是创建lambda层,上传这个zip包:
上传代码zip包
第三方依赖包与运行时依赖文件剥离到层后,剩下的就是我们的逻辑代码了(也就是gitlab上的代码文件),我们将前面压缩打包的imageDeal.zip上传:
进行一次简单的测试,保证lambda能正常调用到入口方法(详见运行时配置:handler.handler):
日志排查
测试过程中,并不是一直顺利,比如可能会因为依赖文件缺失报错等(一般语法的错误在本地都能解决),Lambda云函数支持了监控-日志:
Lambda 会记录云函数处理的所有请求,并通过 Amazon CloudWatch Logs 自动存储代码生成的日志。我们也可以在代码中插入自定义日志记录语句来验证代码。
自定义日志记录:
print("## s3 upload reponse:")
print(response)
Python 中的 AWS Lambda 函数日志记录 - AWS Lambda
参考
Python 中的 Lambda 函数处理程序 - AWS Lambda
Clarify multithreading documentation · Issue #1246 · boto/botocore