環境
- MacOSX
- SAM CLI, version 0.41.0
- python3.8
下記内容はsam init
で作成されたものそのまま使用しています。
違いはrequirements.txt
の内容のみです。
現象
以下のような状態でpip installをしてsam local invoke
をすると invalid ELF headerが発生する。
$ cat sam-app/hello_world/requirements.txt
requests
pysftp
$ pip install -r requirements.txt -t ./
$ sam local invoke
Invoking app.lambda_handler (python3.8)
(中略)
{"errorType":"Runtime.ImportModuleError","errorMessage":"Unable to import module 'app': /var/task/bcrypt/_bcrypt.abi3.so: invalid ELF header"}
これについてはモジュールに含まれているバイナリファイルがAmazonLinux2ではないための環境要因とのこと。
Error in AWS Lambda: invalid ELF header #117
https://github.com/Cyan4973/xxHash/issues/117
AmazonLinux2内で実行する、もしくはそこで実行したものを持ってくれば一応は解決すると言う感じっぽい。
ただそのためにEC2を立ち上げるのはやはり面倒な上に(と言うかお金もかかるし)、
記事投稿時点でAnazonLinuxの標準のPythoはPython2なのでその辺もなんとかする必要があり手間が大きい
解決
sam build
を行なって実行すればLambda(AmazonLinux2?)用の環境に作られたライブラリがインストールされる。
$ sam build
Building resource 'HelloWorldFunction'
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
Build Succeeded
(中略)
$ sam local invoke
Invoking app.lambda_handler (python3.8)
(中略)
{"statusCode":200,"body":"{\"message\": \"hello world\"}"}
ただし、buildをした場合は、作成される.aws-sam/build
の方のコードが実行されるので、
毎回buildが必要となりインタプリタ系の言語のお手軽さが失われてしまう。
なので、
.aws-sam/build
にinstallされたモジュールを現在開発しているディレクトリに移動し.aws-sam/build
を削除する。
こうすることで毎回buildする必要がなくbuild前の元の方のコードが実行することができる。
$ ls .aws-sam/build/HelloWorldFunction/
PyNaCl-1.3.0.dist-info certifi-2019.11.28.dist-info idna-2.9.dist-info requests
(以下省略)
$ cp .aws-sam/build/HelloWorldFunction/ ./hello_world/
$ sam local invoke
Invoking app.lambda_handler (python3.8)
(中略)
{"statusCode":200,"body":"{\"message\": \"hello world\"}"}
(未解決)サブディレクトリにモジュールを配置したい
上記の方法ではbuild時にinstallされるモジュールは指定場所直下になるみたいです。
なのでcpの際にはモジュール以外の自分の書いたソースコードも含まれています(上記では取り除いてませんが)
これについてはまだ現時点で解決にたどり着けていません。
.aws-sam/build/
から持ってくる際は.lib
ディレクトリを作成してそこにコピー、
以下を記載することでlib配下のモジュールを取ってこれるのでこれで開発中は多少ごちゃごちゃ感がなくなると思います。
sys.path.append("./lib/")