🐍

Lambda で外部パッケージ追加してるのに"No named module"になる

に公開

現象

Lambda レイヤーを追加したがライブラリが見つからない

Lambda レイヤーにて、外部ライブラリをパッケージ化したものをアップロードし、Lambda に設定を反映させたが、ライブラリが見つからないというエラーが出た。

lambda_function.py と同ディレクトリにライブラリ一式を配置しても見つからない

Lambda レイヤーを使用せず、lambda_function.py と同ディレクトリにライブラリ一式を配置してテスト実行をしてみた。しかし同じエラーが出た。

原因

Python のバージョン不整合

今回使用していた Lambda のランタイムは Python3.11 であった。しかし筆者のローカルPCでは Python3.10 を起動し、このバージョンの Python で pip install を行っていた。これにより Python のバージョン違いによる不整合が発生したと考えられる。

Lambda ランタイムの OS との不整合

筆者の PC は MacOS であった。しかし今回使用している Lambda は Python3.11 でベースの OS が Amazon Linux 2 であった。実行環境の OS が異なることでインストール時のライブラリのビルドの仕方が異なってしまい、不整合が起きていたと考えられる。

状況を図でまとめ

以上のことをまとめて図にまとめた。
今回のエラーの対処法は、図の「理想系」になるように Lambda とライブラリを用意すれば良いとわかる。
今回は Lambda のラインタイムを Python3.12 に変更してライブラリを用意し直した。

対処

CloudShell を起動して環境準備

パッケージを用意するにあたり、以下の記事を参考に進めようとしたが、2024/7/24 でCloud9 の新規利用が終了していた。
そのため、今回は CloudShell(OS は Amazon Linux 2023)環境を利用し、コマンドの実行は記事と同じように実施した。

https://dev.classmethod.jp/articles/aws-lambda-layers-external-and-custom-libraries/

以下コードを実行

# 必要なモジュールをインストール。

sudo dnf groupinstall "Development Tools"

sudo dnf install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel xz xz-devel libffi-devel wget make

# Python 環境管理ツール pyenv を Git からインストール。
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# pyenvのパスを通す
echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc

# .bashrcの修正を反映
source ~/.bashrc

Lambda ランタイムにて使用しているものと同じバージョンの Python をインストールし仮想環境構築

前項の必要なモジュールとPython 環境管理ツールをインストール後、以下コマンドを上から順に実行し、最後のコマンドの結果がインストールしたい Python のバージョン(今回は 3.12.0 )であることを確認する。

# pyenv のバージョンを確認
pyenv --version

# インストール可能な Python3.12 のバージョンを確認
pyenv install --list | grep 3.12

# 最新の Python3.12.0 をインストール
pyenv install 3.12.0

# Python3.12.0 を使用
pyenv global 3.12.0

# Python のバージョンを確認
python -V

必要なパッケージをインストール

先述した記事を参考に、以下のコマンドを順に実行して paramiko ライブラリをインストールした。

# pythonフォルダ作成
mkdir python
cd python

# pandasをpythonフォルダ直下にインストール
pip install paramiko -t .

パッケージをzip化し、ダウンロード後、Lambdaレイヤーにアップロード

最後に python ファイルを以下のコマンドを実行し zip 圧縮する。

cd ../
zip -r python.zip python

zip 圧縮後、ダウンロードする。

ダウンロードした zip ファイルを Lambda レイヤーにアップロードする。

import テスト

import が通り、"No module named" が出力せず、lambda_handler 実行まで到達しているため、今回のエラーは解消されたとわかる。

[実行した Lambda の内容]

[テスト実行結果(今回は SSH 接続先を用意していないため、タイムアウトが正常)]

まとめ

外部ライブラリを用意する際は、Lambdaランタイムの OS と同じ環境にて、同じバージョンの言語でライブラリのインストール及びビルドをして用意する

Discussion