如何在 AWS Lambda 中正确加载 gem 扩展
How to correctly load a gem extension in AWS Lambda
我在处理 AWS Lambda 上的 gem 加载错误时遇到问题。
{
"errorMessage": "LoadError: libpq.so.5: cannot open shared object file: No such file or directory - /var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.4/lib/pg_ext.so",
"errorType": "Function<Sequel::AdapterNotFound>",
"stackTrace": [
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.4/lib/pg.rb:4:in `<top (required)>'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/adapters/postgres.rb:6:in `<top (required)>'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:88:in `load_adapter'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:17:in `adapter_class'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:45:in `connect'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:121:in `connect'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:399:in `adapter_method'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:406:in `block (2 levels) in def_adapter_method'",
"/var/task/lib/warehouse/loader.rb:5:in `connection'",
"/var/task/lib/warehouse/loader.rb:24:in `initialize'",
"/var/task/lib/warehouse/update.rb:43:in `new'",
"/var/task/lib/warehouse/update.rb:43:in `block in handle'",
"/var/task/lib/warehouse/update.rb:42:in `each'",
"/var/task/lib/warehouse/update.rb:42:in `handle'",
"/var/task/lambda.rb:11:in `handler'"
]
}
我正在使用 Sequel 库从 AWS Lambda 建立 PSQL 连接,但该函数似乎找不到 so 文件。我 已经 在 vendor/bundle
中打包依赖项,在 CodeBuild 上 Ubuntu 中构建,并验证 .so 文件存在于上传到 lambda 的结果工件中。我还编辑了 $LOAD_PATH,但这似乎没有帮助。
还有其他人遇到过这个困难吗?关于解决或调试的任何进一步提示?
你的 lib
文件夹中有 libpq.so.5
吗?
您的错误是在 $PATH
上找不到 libpq.so.5
,在 AWS Lambda 中,文件夹 lib
会自动加载到路径中,因此,您只需要拥有这个文件在那里。
在 lambda 世界之外创建的可执行文件不能在 Lambda 上 运行,此外,您需要在 Lambda 映像上自行编译可执行文件。这是一个如何做到这一点的例子:
Gemfile
source "https://rubygems.org"
gem "pg"
gem "mysql2"
handler.rb
require 'pg'
require 'mysql2'
def run(event:, context:)
{
postgres_client_version: PG.library_version,
mysql_client_version: Mysql2::VERSION
}
end
Dockerfile
FROM lambci/lambda:build-ruby2.5
RUN yum install -y postgresql postgresql-devel mysql mysql-devel
RUN gem update bundler
ADD Gemfile /var/task/Gemfile
ADD Gemfile.lock /var/task/Gemfile.lock
RUN bundle install --path /var/task/vendor/bundle --clean
这将构建您的映像,然后 运行 它生成 PG 和 MYSQL 可执行文件,然后将其复制到您的 lib 文件夹。
build.sh
#!/bin/bash -x
set -e
rm -rf lib && rm -rf vendor && mkdir lib && mkdir vendor
docker build -t pg_mysql_layer -f Dockerfile .
CONTAINER=$(docker run -d pg_mysql_layer false)
docker cp \
$CONTAINER:/var/task/vendor/ \
./
docker cp \
$CONTAINER:/usr/lib64/libpq.so.5.5 \
lib/libpq.so.5
docker cp \
$CONTAINER:/usr/lib64/mysql/. \
lib/
docker rm $CONTAINER
在 运行ning ./build.sh
之后,它将生成文件夹 lib
和 vendor
以及您需要的所有内容,现在您只需要部署您的 lambda 函数。
要在本地进行测试,您可以 运行:
docker run --rm -it -v $PWD:/var/task -w /var/task lambci/lambda:ruby2.5 handler.run
它将 return 类似于此:
REF: https://www.stevenringo.com/ruby-in-aws-lambda-with-postgresql-nokogiri/
REF: https://www.reddit.com/r/ruby/comments/a3e7a1/postgresql_on_aws_lambda_ruby/
很少有好的插件可以管理 AWS lambda 的依赖项。 serverless-ruby-layer for ruby and serverless-python-requirements 对于 python。
对于您的 ruby 案例,您只需将与插件相关的配置添加到 serverless.yml.
即可使用无服务器-ruby 层
service: using-docker-yums
plugins:
- serverless-ruby-layer
custom:
rubyLayer:
use_docker: true
docker_yums:
- postgresql-devel
native_libs:
- /usr/lib64/libpq.so.5
provider:
name: aws
runtime: ruby2.5
functions:
hello:
handler: handler.hello
并且您需要在无服务器项目文件夹中使用以下命令安装插件,
sls plugin install -n serverless-ruby-layer
现在运行 sls deploy
会自动将 gem 和 libs 部署到层。
查看文档中的示例 here
这里有一个类似@ruan-carlos 的解决方案,但一步到位,更容易理解。
#!/bin/bash
set -e
cat >Dockerfile <<EOF
FROM public.ecr.aws/lambda/ruby:2.7
RUN yum install -y postgresql-libs
EOF
rm -rf lib
docker build -t pg-layer-source .
mkdir lib
docker create -ti --name dummy pg-layer-source bash
docker cp dummy:/usr/lib64/libpq.so.5.5 lib/libpq.so.5
docker cp dummy:/usr/lib64/libldap_r-2.4.so.2.10.7 lib/libldap_r-2.4.so.2
docker cp dummy:/usr/lib64/liblber-2.4.so.2.10.7 lib/liblber-2.4.so.2
docker cp dummy:/usr/lib64/libsasl2.so.3.0.0 lib/libsasl2.so.3
docker cp dummy:/usr/lib64/libssl3.so lib
docker cp dummy:/usr/lib64/libsmime3.so lib
docker cp dummy:/usr/lib64/libnss3.so lib
docker rm -f dummy
zip -r $(date +%Y-%m-%d-%s)-lib-pg-layer.zip lib
我在处理 AWS Lambda 上的 gem 加载错误时遇到问题。
{
"errorMessage": "LoadError: libpq.so.5: cannot open shared object file: No such file or directory - /var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.4/lib/pg_ext.so",
"errorType": "Function<Sequel::AdapterNotFound>",
"stackTrace": [
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.4/lib/pg.rb:4:in `<top (required)>'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/adapters/postgres.rb:6:in `<top (required)>'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:88:in `load_adapter'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:17:in `adapter_class'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:45:in `connect'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:121:in `connect'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:399:in `adapter_method'",
"/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:406:in `block (2 levels) in def_adapter_method'",
"/var/task/lib/warehouse/loader.rb:5:in `connection'",
"/var/task/lib/warehouse/loader.rb:24:in `initialize'",
"/var/task/lib/warehouse/update.rb:43:in `new'",
"/var/task/lib/warehouse/update.rb:43:in `block in handle'",
"/var/task/lib/warehouse/update.rb:42:in `each'",
"/var/task/lib/warehouse/update.rb:42:in `handle'",
"/var/task/lambda.rb:11:in `handler'"
]
}
我正在使用 Sequel 库从 AWS Lambda 建立 PSQL 连接,但该函数似乎找不到 so 文件。我 已经 在 vendor/bundle
中打包依赖项,在 CodeBuild 上 Ubuntu 中构建,并验证 .so 文件存在于上传到 lambda 的结果工件中。我还编辑了 $LOAD_PATH,但这似乎没有帮助。
还有其他人遇到过这个困难吗?关于解决或调试的任何进一步提示?
你的 lib
文件夹中有 libpq.so.5
吗?
您的错误是在 $PATH
上找不到 libpq.so.5
,在 AWS Lambda 中,文件夹 lib
会自动加载到路径中,因此,您只需要拥有这个文件在那里。
在 lambda 世界之外创建的可执行文件不能在 Lambda 上 运行,此外,您需要在 Lambda 映像上自行编译可执行文件。这是一个如何做到这一点的例子:
Gemfile
source "https://rubygems.org"
gem "pg"
gem "mysql2"
handler.rb
require 'pg'
require 'mysql2'
def run(event:, context:)
{
postgres_client_version: PG.library_version,
mysql_client_version: Mysql2::VERSION
}
end
Dockerfile
FROM lambci/lambda:build-ruby2.5
RUN yum install -y postgresql postgresql-devel mysql mysql-devel
RUN gem update bundler
ADD Gemfile /var/task/Gemfile
ADD Gemfile.lock /var/task/Gemfile.lock
RUN bundle install --path /var/task/vendor/bundle --clean
这将构建您的映像,然后 运行 它生成 PG 和 MYSQL 可执行文件,然后将其复制到您的 lib 文件夹。
build.sh
#!/bin/bash -x
set -e
rm -rf lib && rm -rf vendor && mkdir lib && mkdir vendor
docker build -t pg_mysql_layer -f Dockerfile .
CONTAINER=$(docker run -d pg_mysql_layer false)
docker cp \
$CONTAINER:/var/task/vendor/ \
./
docker cp \
$CONTAINER:/usr/lib64/libpq.so.5.5 \
lib/libpq.so.5
docker cp \
$CONTAINER:/usr/lib64/mysql/. \
lib/
docker rm $CONTAINER
在 运行ning ./build.sh
之后,它将生成文件夹 lib
和 vendor
以及您需要的所有内容,现在您只需要部署您的 lambda 函数。
要在本地进行测试,您可以 运行:
docker run --rm -it -v $PWD:/var/task -w /var/task lambci/lambda:ruby2.5 handler.run
它将 return 类似于此:
REF: https://www.stevenringo.com/ruby-in-aws-lambda-with-postgresql-nokogiri/
REF: https://www.reddit.com/r/ruby/comments/a3e7a1/postgresql_on_aws_lambda_ruby/
很少有好的插件可以管理 AWS lambda 的依赖项。 serverless-ruby-layer for ruby and serverless-python-requirements 对于 python。
对于您的 ruby 案例,您只需将与插件相关的配置添加到 serverless.yml.
即可使用无服务器-ruby 层service: using-docker-yums
plugins:
- serverless-ruby-layer
custom:
rubyLayer:
use_docker: true
docker_yums:
- postgresql-devel
native_libs:
- /usr/lib64/libpq.so.5
provider:
name: aws
runtime: ruby2.5
functions:
hello:
handler: handler.hello
并且您需要在无服务器项目文件夹中使用以下命令安装插件,
sls plugin install -n serverless-ruby-layer
现在运行 sls deploy
会自动将 gem 和 libs 部署到层。
查看文档中的示例 here
这里有一个类似@ruan-carlos 的解决方案,但一步到位,更容易理解。
#!/bin/bash
set -e
cat >Dockerfile <<EOF
FROM public.ecr.aws/lambda/ruby:2.7
RUN yum install -y postgresql-libs
EOF
rm -rf lib
docker build -t pg-layer-source .
mkdir lib
docker create -ti --name dummy pg-layer-source bash
docker cp dummy:/usr/lib64/libpq.so.5.5 lib/libpq.so.5
docker cp dummy:/usr/lib64/libldap_r-2.4.so.2.10.7 lib/libldap_r-2.4.so.2
docker cp dummy:/usr/lib64/liblber-2.4.so.2.10.7 lib/liblber-2.4.so.2
docker cp dummy:/usr/lib64/libsasl2.so.3.0.0 lib/libsasl2.so.3
docker cp dummy:/usr/lib64/libssl3.so lib
docker cp dummy:/usr/lib64/libsmime3.so lib
docker cp dummy:/usr/lib64/libnss3.so lib
docker rm -f dummy
zip -r $(date +%Y-%m-%d-%s)-lib-pg-layer.zip lib