AWS SAM包含具有本地依赖项的gem

时间:2020-08-26 18:15:45

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

我想在本地运行我的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,并使其在生产环境中正常工作?

我读过一些有关使用Layers的知识,但我并不完全理解,因为这是我第一次使用lambda函数。

似乎山姆人解决方案还有一些未解决的问题,但这不会在不久的将来。

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

1 个答案:

答案 0 :(得分: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时,将推动整个应用程序(包括该层)的运行,并配置要使用该层的功能。