如何在AWS Lambda中正确加载gem扩展

时间:2019-01-23 15:38:36

标签: ruby aws-lambda rubygems sequel pg

我无法解决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中,并在Ubuntu上的CodeBuild中构建,并验证了.so文件是否存在于上载到lambda的结果工件中。我还编辑了$ LOAD_PATH,但这似乎无济于事。

还有其他人遇到过这个困难吗?还有其他解决或调试提示吗?

2 个答案:

答案 0 :(得分:2)

您的libpq.so.5文件夹中是否有lib

您的错误是说在libpq.so.5上找不到$PATH,在AWS Lambda中,文件夹lib会自动加载到路径上,因此,您只需要拥有此文件那里。

在lambda世界之外创建的可执行文件不能在Lambda上运行,此外,您需要在Lambda映像上自行编译可执行文件。这是如何执行此操作的示例:

宝石文件

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

运行./build.sh后,它将根据需要生成文件夹libvendor,现在只需要部署lambda函数即可。

要在本地测试,可以运行: docker run --rm -it -v $PWD:/var/task -w /var/task lambci/lambda:ruby2.5 handler.run

它将返回类似于以下内容的内容:

Lambda execution

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/

答案 1 :(得分:2)

很少有好的插件可以管理 AWS lambda 的依赖项。 serverless-ruby-layer 代表 ruby​​,serverless-python-requirements 代表 python。

对于您的 ruby​​ 案例,您只需将插件相关配置添加到 serverless.yml 中即可使用 serverless-ruby-layer。

 FirstTrip = _service.Trips.OrderBy(t => t.StartDate).FirstOrDefault();

并且您需要在无服务器项目文件夹中使用以下命令安装插件,

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 将自动将 gems 和 libs 部署到层。

在文档中查看此示例 here