我正在开发部署到 AWS Lambda 的无服务器 Flask 应用程序。该程序使用 Cryptography 库(使用版本 3.4.7)。在本地,程序运行良好,没有任何问题。但是,无论何时部署在 Lambda 上,都会出现以下错误:
from cryptography.fernet import Fernet
File "/var/task/cryptography/fernet.py", line 16, in <module>
from cryptography.hazmat.primitives import hashes, padding
File "/var/task/cryptography/hazmat/primitives/padding.py", line 11, in <module>
from cryptography.hazmat.bindings._padding import lib
ImportError: /var/task/cryptography/hazmat/bindings/_padding.abi3.so: cannot open shared object file: No such file or directory
当使用“危险材料”模块中的一些必需功能时,会出现非常相似的错误:
File "/var/task/cryptography/hazmat/primitives/kdf/pbkdf2.py", line 28, in __init__
backend = _get_backend(backend)
File "/var/task/cryptography/hazmat/backends/__init__.py", line 23, in _get_backend
return default_backend()
File "/var/task/cryptography/hazmat/backends/__init__.py", line 14, in default_backend
from cryptography.hazmat.backends.openssl.backend import backend
File "/var/task/cryptography/hazmat/backends/openssl/__init__.py", line 6, in <module>
from cryptography.hazmat.backends.openssl.backend import backend
File "/var/task/cryptography/hazmat/backends/openssl/backend.py", line 113, in <module>
from cryptography.hazmat.bindings.openssl import binding
File "/var/task/cryptography/hazmat/bindings/openssl/binding.py", line 14, in <module>
from cryptography.hazmat.bindings._openssl import ffi, lib
ImportError: /var/task/cryptography/hazmat/bindings/_openssl.abi3.so: cannot open shared object file: No such file or directory
但是,引用的库文件确实存在,并且它们位于指定的确切路径中。
该应用程序在 requirements.txt 中包含
cryptography==3.4.7
作为依赖项。然后无服务器安装包,同时使用 sls deploy
部署到 AWS。 Serverless 将所有内容打包并上传到 AWS。我可以按预期看到此 zip 文件夹中的所有文件。
我认为这可能是 Serverless 在部署时错误地上传或安装包的问题,所以我什至尝试将 cryptography 文件夹直接包含在我的项目中。然而,尽管对无服务器配置或加密包本身进行了任何更改,但我在已部署的 Lambda 上使用此包一直没有成功。有谁知道我可以做些什么来完成这项工作?
之前我遇到过类似的问题,通过从 linux 机器运行部署命令解决了这个问题。我使用 mac 进行开发,我试图从我的 mac 部署我的 lambda 函数。然而,当它被部署时,一些依赖项会抛出导入错误。
根据我的经验,这是由于操作系统在mac或linux环境下运行时对依赖项的打包方式不同。因此,尝试从 Linux 机器内部运行无服务器部署命令,看看是否可行。
就我而言,我设置了一个 gitlab CI/CD 管道以在 gitlab 管道环境中运行命令,这解决了问题。
我为解决类似问题所做的工作是,在尝试向 lambda 函数添加一个带有加密库的层时,在 lambda 函数和层中使用相同的运行时和处理器架构。
例如,我的问题是我有一个运行在 Python 3.9 和 arm64 架构中的 lambda 函数。但是我正在创建运行 python 3.8 的层 .zip 文件,并且在 x86_64 架构中。
别问我为什么在 Python 3.8 和 x86_64 中重新创建 lambda 比相反的方式更容易。
无论如何,只要我将层(带有密码学库)添加到 lambda,它就会顺利运行。
所以,我的理论是,您需要同时匹配运行时和体系结构,才能使层与 lambda 函数一起正常工作。
此外,现在我查找了我的解决方案,它实际上得到了这篇文章的支持:https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html
(看里面的注释)
Amazon 提出的一个建议是使用“sam”工具通过 Docker 容器构建分发。但是,在我的情况下,我无法在构建环境中使用 docker。
Amazon 提供了一些其他文档,介绍如何通过传递非常明确的命令行标志来使用 pip 安装要求,以确保下载 Lambda 环境的版本:
pip install \
--platform manylinux2014_x86_64 \
--implementation cp \
--python 3.9 \
--only-binary=:all: --upgrade \
--target=build/package \
cryptography==38.0.3
“build/package”路径将导致依赖项被下载并安装到该目录中,以便轻松压缩以上传到 Lambda 中。
如果您有
setup.cfg
或 pyproject.toml
文件,也可以通过使用“.”来使用这些标志。作为要加载的资源,而不是明确命名的库。
我预计随着亚马逊引入新的运行时环境并弃用旧的运行时环境,给定的
--platform
和--python
标志将需要更改。
将我的 Lambda 函数从 python 3.6 迁移到 python 3.9 后,我遇到了类似的错误
我使用
amazonlinux
docker 容器进行开发、测试和部署(通过无服务器)。
在 cryptography 的文档 中,Linux 的安装步骤不像 macOS 中那样简单,因为
cryptography
ships manylinux
wheels(从 2.0 开始)。
这里是你可以尝试的:
升级
pip
并再次通过cryptography
重新安装pip
。
或
自己编译
cryptography
(你需要一个 C 编译器,一个 Rust 编译器,Python 的头文件(如果你不使用 pypy),以及 OpenSSL 和 libffiInstall 的头文件),这些包是 redhat-rpm-config
gcc
libffi-devel
python3-devel
openssl-devel
cargo
,使用你的包管理器然后运行:
pip install cryptography --no-binary cryptography
在密码学的常见问题解答页面,有一个关于 AWS Lambda 的部分。
我在使用 M1 处理器从 Mac 将 lambda 部署到 AWS 时遇到了完全相同的问题。我通过向无服务器配置添加
dockerRunCmdExtraArgs
参数来修复它:
pythonRequirements:
dockerizePip: 'non-linux'
dockerImage: public.ecr.aws/sam/build-python3.9:latest
dockerRunCmdExtraArgs: ['--platform', 'linux/amd64']