【问题标题】:AWS SAM Include gem with native dependenciesAWS SAM 包含具有本机依赖项的 gem
【发布时间】:2020-08-26 18:15:45
【问题描述】:

我想在本地运行我的 lambda 函数(我目前正在使用 ruby 2.7.1),但是当我需要一个需要本机依赖项的 gem 时,它会失败,因为它找不到它们。

我尝试使用 'pg' gem 连接到 postgresql 数据库。然后我继续运行sam buildsam local invoke HelloWorldFunction --event events/event.json,它失败并出现下一个错误:

Invoking app.lambda_handler (ruby2.7)
Failed to download a new amazon/aws-sam-cli-emulation-image-ruby2.7:rapid-1.0.0 image. 
Invoking with the already downloaded image.
Mounting /home/user/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated 
inside runtime container
Init error when loading handler app.lambda_handler
{
  "errorMessage": "libpq.so.5: cannot open shared object file: No such file or directory - /var/task/vendor/bundle/ruby/2.7.0/gems/pg-1.2.3/lib/pg_ext.so",
  "errorType": "Init<LoadError>",
  "stackTrace": [
    "/var/lang/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'",
    "/var/lang/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/pg-1.2.3/lib/pg.rb:5:in `<top (required)>'",
    "/var/lang/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'",
    "/var/lang/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'",
    "/var/task/app.rb:3:in `<top (required)>'",
    "/var/lang/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'",
    "/var/lang/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'"
  ]
}

接下来我尝试执行sam build --use-container 并得到Gem::Ext::BuildError 和消息ERROR: Failed to build gem native extension.

似乎没有包含gem需要的外部库。

我的问题是:

  • 如何使用 AWS SAM 实现这一点?最好的方法是什么?
  • 如何解决这个问题以在本地测试 lambda 并让它在生产环境中工作?

我阅读了一些关于为此使用图层的信息,但我并不完全理解,因为这是我第一次使用 lambda 函数。

sam proyect 似乎也有一些关于解决此问题的未解决问题,但不会在不久的将来。

任何帮助将不胜感激! 谢谢!

【问题讨论】:

  • 你在关注什么文档?
  • @D.SM 我正在​​关注AWS documentation 以及自动生成项目中包含的自述文件
  • sam build 是一个本地命令,如果这是真的,你有一个本地构建问题。

标签: ruby aws-lambda pg aws-sam aws-sam-cli


【解决方案1】:

Lambda 中的层基本上为您提供了一种安装依赖项的方法,这些依赖项与您的函数没有直接关系,但被它使用。这是支持重用和加快构建和部署时间的好方法。这里的想法是,您可以将诸如 postgresql 库之类的公共或共享依赖项安装到层中,然后从您的函数中引用它们。

简而言之,它们为您提供了一种将内容放置在 lambda 可以在运行时访问的文件系统上的方法。

但是,在这种情况下,有一些相互关联的问题:

  • pg gem 要求在操作系统上安装软件包,并且文件在构建时可用
  • pg gem 本身不会安装依赖项

这意味着使用图层比理想情况下要简单一些。

对于您的问题,请尝试以下操作:

  1. 创建一个名为pg_layer 的新目录
  2. 在该目录中,创建一个名为Makefile(大小写很重要)的文件,其内容如下:
LIB_DIR = $(ARTIFACTS_DIR)/lib
LIB_FILES = \
  /usr/lib64/libpq.so.* \
  /usr/lib64/libldap_r-2.4.so.2* \
  /usr/lib64/liblber-2.4.so.* \
  /usr/lib64/libsasl2.so.* \
  /usr/lib64/libssl3.so \
  /usr/lib64/libsmime3.so \
  /usr/lib64/libnss3.so


build-PGLayer:
  yum install -y amazon-linux-extras
  yum install -y postgresql-devel postgresql-libs
  mkdir -p $(ARTIFACTS_DIR)/vendor/bundle
  mkdir -p $(LIB_DIR)
  for f in $(LIB_FILES); do cp $$f $(LIB_DIR); done
  cp -r . $(ARTIFACTS_DIR)
  mkdir -p $(ARTIFACTS_DIR)/ruby/gems
  gem install pg --install-dir $(ARTIFACTS_DIR)/ruby/gems/2.7.0
  1. 更改您的 template.yaml 文件,并将以下内容添加到您的 Resources 部分:
  PGLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      CompatibleRuntimes:
        - ruby2.7
      ContentUri: 'pg_layer'
    Metadata:
      BuildMethod: makefile
  1. template.yaml 文件中,更改您的函数定义,将以下内容添加到Properties
      Layers:
        - !Ref PGLayer
  1. 从函数的 Gemfile 中删除 pg(由于层,它会自动可用,将其留在那里会阻止您构建函数)

当您准备好构建时,使用命令sam build --use-container。 要使用层在本地运行 lambda 函数,请使用 sam local start-api。 当你准备好部署时,sam deploy 会推送你的整个应用程序,包括层,并配置函数来使用层。

【讨论】:

  • 实际上,pg gem 需要放在 Gemfile 中,否则 rails 应用程序不会加载它。因此,这可能会在全局范围内安装 gem,但如果不在 Gemfile 中提及,则无法在 rails 应用程序中访问它。有什么解决办法吗?
  • @prcoder 我建议维护 2 个 Gemfile - 一个用于 Rails,一个用于 lambda。 Rails 的一个需要在子目录中,或者具有不同的名称,因为 SAM 要求它的一个被称为 Gemfile 而不是 pg gem。你可以为 Rails 指定环境变量BUNDLE_GEMFILE,告诉它应该使用的 Gemfile 的路径。 (见justinweiss.com/articles/how-does-rails-handle-gems
猜你喜欢
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多