ruby - AWS SAM 包含具有本机依赖项的 gem
问题描述
我想在本地运行我的 lambda 函数(我目前正在使用ruby 2.7.1
),但是当我需要一个需要本机依赖项的 gem 时,它会失败,因为它找不到它们。
我尝试使用'pg'
gem 连接到 postgresql 数据库。然后我继续运行sam build
and 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 需要的外部库。
我的问题是:
- 如何使用 AWS SAM 实现这一点?什么是最好的方法呢?
- 如何解决这个问题以在本地测试 lambda 并让它在生产环境中工作?
我阅读了一些关于为此使用图层的内容,但我并不完全理解,因为这是我第一次使用 lambda 函数。
sam proyect 似乎也有一些关于解决此问题的未解决问题,但不会在不久的将来出现。
任何帮助将不胜感激!谢谢!
解决方案
Lambda 中的层基本上为您提供了一种安装依赖项的方法,这些依赖项与您的函数没有直接关系,但被它使用。这是支持重用和加快构建和部署时间的好方法。这里的想法是,您可以将诸如 postgresql 库之类的公共或共享依赖项安装到层中,然后从您的函数中引用它们。
简而言之,它们为您提供了一种将东西放在 lambda 可以在运行时访问的文件系统上的方法。
但是,在这种情况下,有一些相互关联的问题:
- gem 需要在
pg
操作系统上安装软件包,并且文件在构建时可用 pg
gem 本身不会安装依赖项
这意味着使用层比理想的要简单一些。
对于您的问题,请尝试以下操作:
- 创建一个名为的新目录
pg_layer
- 在该目录中,创建一个名为
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
- 更改您的
template.yaml
文件,并将以下内容添加到您的Resources
部分:
PGLayer:
Type: AWS::Serverless::LayerVersion
Properties:
CompatibleRuntimes:
- ruby2.7
ContentUri: 'pg_layer'
Metadata:
BuildMethod: makefile
- 在
template.yaml
文件中,更改您的函数定义以将以下内容添加到Properties
:
Layers:
- !Ref PGLayer
- 从
pg
你的函数的 Gemfile 中删除(它会因为层而自动可用,并且将它留在那里会阻止你构建函数)
当您准备好构建时,请使用命令sam build --use-container
。要使用图层在本地运行 lambda 函数,请使用sam local start-api
. 当您准备好部署sam deploy
时,将推送您的整个应用程序,包括层,并配置功能以使用层。
推荐阅读
- tensorflow - 进程终止后释放 GPU 内存
- ruby-on-rails - 如果在 after_create 中未调用函数,如何在 Ruby on Rails 中引发错误
- python - 从维基百科抓取链接
- vue.js - 如何在Vue.JS中将数组放入多选中
- ios - UI标签读取为零?
- javascript - 在不使用循环、内置方法或 javascript 中的 .length 属性的情况下查找字符串的长度?
- oracle - 为什么使用count时bridge sql developer命令失败
- c# - C# 异步函数投影到属性
- linux - 如何使用 Golang 安装 Gin
- javascript - Mocha - Chai Unit Terst 报告生成 - NodeJS