首页 > 解决方案 > AWS SAM 包含具有本机依赖项的 gem

问题描述

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

我尝试使用'pg'gem 连接到 postgresql 数据库。然后我继续运行sam buildand sam 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 需要的外部库。

我的问题是:

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

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

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

标签: rubyaws-lambdapgaws-samaws-sam-cli

解决方案


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

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

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

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

这意味着使用层比理想的要简单一些。

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

  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. pg你的函数的 Gemfile 中删除(它会因为层而自动可用,并且将它留在那里会阻止你构建函数)

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


推荐阅读