【AWS Lambda+Python】外部ライブラリのレイヤーを作る→importでエラー

AWS

最初に言っておくと、AWSもLambdaもPythonも初心者です。

LambdaでSFTPをやりたくて、調べたところpythonのparamikoが良さそう。
PythonでSFTPを利用してファイル転送する方法を現役エンジニアが解説【初心者向け】

ということでLambda関数のランタイムをpython3.8(この時点で最新)にして、import paramiko を記述するとエラー。

Unable to import module ‘lambda_function’: No module named ‘paramiko’

ここまでは良い。すぐ分かった。
Lambdaに標準で入っていないライブラリは外部ライブラリとして読み込む必要があると。
lambdaに外部モジュールを読み込ませる

して、問題はここから。ネットの情報を参考にparamikoを外部レイヤーとして読み込んだがどーにもこーにも上記エラーが解決しない

  • Windowsで外部モジュール(zip)つくるとダメかも。→macでやってもダメ
  • 圧縮するとき、ディレクトリの中身を圧縮すればイケる。→ダメ

pythonのバージョンの問題なのかな?paramikoのバージョンの問題なのかな?OS含めた環境の問題なのかな?色々試したいことはあっても如何せん全てが初心者なので、いちいち時間がかかる。たまにエラーの内容が下記に変わって横道にそれちゃったり(結局、上に書いたエラーに戻ったが・・)。

Unable to import module ‘lambda_function’: cannot import name ‘_bcrypt’ from partially initialized module ‘bcrypt’ (most likely due to a circular import) (/opt/python/bcrypt/__init__.py)
Unable to import module ‘lambda_function’: /opt/python/bcrypt/_bcrypt.abi3.so: invalid ELF header

ちなみにparamikoではなく他のライブラリ(requests)とかで試しても同じ事象(No module named)だったので、途中からparamikoのバージョンなのか?という疑念はなくなりました。

解決したが・・

最終的に、解決はした。トリガーでLambda関数が起動され、paramikoでSFTP通信が行われるところまで確認できた。

でも正直、根本的な原因は分かっていない・・・

ネットで見かけた情報を色々と組み合わせていく中で、下記3つの条件を満たした外部モジュールのzipを作るとうまく読み込めるみたい。という結論に至る。

①Python3.7でやる

ローカル環境のpythonを3.7.7にしてparamikoの外部モジュール(zip)を作成する。Lambda関数のランタイムも3.7で実行する。

途中からpythonのバージョン(3.8)のせいなんじゃないかと思い、3.7に落としたらうまくいった。ただし他要因との絡みがあるかもしれないので、バージョンのせいだけなのかは定かではない。

②Amazon Linuxで外部モジュール(zip)を作成する

Amazon LinuxのEC2を作成して、python3.7.7をインストール。その環境でparamikoのインストールからzip圧縮までを実施。

Lambdaで No module named が出た人の事象に対して、Linuxでzip作れ と回答している人がちらほら。さらには Amazon Linuxでやらねばダメよ という情報もあり。
AWS LambdaでPythonのparamikoを使う方法
途中からAmazon Linuxでしかやってなかったので、その他のOSだと本当にダメなのかは不明。

EC2も初めてだったから調べながら・・
[初心者向け] 初めてのEC2ログイン:Linux編

なおEC2で作成したzipは、mac側からscpコマンドでダウンロードして、awsにアップロードした(EC2から直接Lambdaに渡す方法がよく分からなかったので・・)。
SCPコマンドでEC2へファイルのアップロード&ダウンロード

③親ディレクトリ名は”python”にして圧縮する

“python”という名前のディレクトを作成して、そこにparamikoを(targetで)インストールする。zipで固める時は、”python”ディレクトリごと圧縮する。

これはたまたまなのか、何か理由があるのか、全く不明。”python”じゃないとダメなのか、”python”以外の名前にしていた時が悪かったのか、それも分からない。とりあえず、自分の場合はそういう名前にするとエラーなく外部モジュールが読み込めた。

ちなみにLambdaレイヤーにアップロードするzipの名前はpython.zipにしてる。関係なさそうな感じもするが・・・

おわりに

本当だったら色々と真偽を確かめたいし、原因も追求したいけど、疲れた・・・あまりにも難儀したので忘れないように書き残し。リンクをペタペタ貼っているのはほぼ自分の見返し用ですが、参考になれば。

その他参考リンク
【初心者向け】Amazon EC2にSSH接続する【Windows、Macintosh】
EC2のIPアドレスを調べる方法(超初心者向け)
EC2(Amazon Linux 2)にPython 3.8, Pip 3.8をインストールする
MacOSでのPythonのバージョン切り替え方法を現役エンジニアが解説【初心者向け】

コメント

タイトルとURLをコピーしました