LambdaでRuntime.ImportModuleErrorが発生した時の対処

5月 12, 2020AWS,Lambda

概要

  • 今回は、LambdaでRuntime.ImportModuleErrorが発生した時の対処方法をまとめます。LambdaでImportに関する情報は典型的かもしれませんが、私の場合はインターネット上の情報だけではエラーを解決できず、調査に時間が掛かりました。今後の方のために、本記事にまとめたいと思います。
  • 本記事では、先ずRuntime.ImportModuleErrorを対処するための3つのポイントを記載しております。
  • そして、ベースとなるLambdaの開発環境構築からLambda関数にデプロイパッケージをデプロイするまでの手順をやさしく説明しております。開発環境は、EC2 に、Amazon Linux2のインスタンスを起動した環境です。言語はPython を使用します。Lambdaで開発を始めるエンジニアの参考にしてください。
 

Runtime.ImportModuleErrorの対処方法

  • 今回、初めてLamndaに標準以外のライブラリを使用しました。後にご紹介する開発環境を構築し、デプロイパッケージを作成したにも関わらず、下記のエラーとなり、Lambdaが実行できません。
    • [ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function’: No module named 'pyminizip’
 
  • 以下に、Runtime.ImportModuleErrorの対処方法をまとめます。ポイント1、ポイント2はインターネット上の他資料にも記載がありましたが、今回はポイント3にハマっておりました。詳細は、後述のLambdaにコードをデプロイする3つのポイントを参照ください。
    • ポイント1: 開発環境で、Lambdaで使用する(標準以外の)ライブラリを追加したデプロイパッケージ(ZIPファイル)を作成する。
    • ポイント2: デプロイパッケージをアップロードした後、Handler名を指定する必要あり。Handler名は、「コードのファイル名.Handlerのメソッド名」とする。
    • ポイント3: 開発環境に合わせて、ランタイムのバージョンを指定する必要あり。
 

Lambda開発環境の構築方法

  • 今回は、Amazon Linux2のインスタンスに環境構築を行います。その他のMac、WSL(Windows Subsystem for Linux)+ Ubuntuでも環境構築は可能です(多少手順が変わります)。
  • 今回、開発環境にAmazon Linux2を使用する理由は、Lambdaと同じAWSアカウント内に起動したAmazon Linux2を使用することで、IAMロールなどの環境依存の確認も合わせて行うことができるからです。
  • 先ず、PythonでAWSリソースにアクセスするための、boto3ライブラリをインストールします。必須ではありませんが、事前準備としてpipのアップグレードを実施しています。rootでpythonを実行する場合は、必要に応じてsudo を付けてください。

$ pip install --upgrade pip
$ pip install boto3
$ pip list
Package         Version
--------------- --------
boto3           1.9.143
botocore        1.12.143
docutils        0.14
jmespath        0.9.4
pip             20.1
python-dateutil 2.8.0
pytz            2019.1
s3transfer      0.2.0
setuptools      39.0.1
six             1.12.0
urllib3         1.24.3
 
  • 次に、この後の検証で使用するライブラリ(pyminizip)のインストールに必要なパッケージをインストールします。こちらは、sudoが必要ですね。

$ sudo yum install -y gcc zlib-devel
$ yum list installed gcc zlib-devel
 
  • 次は、使用したいライブラリ(pyminizip)をインストールします。こちらもrootでpythonを実行する場合は、必要に応じてsudo を付けてください。

$ pip install pyminizip
Defaulting to user installation because normal site-packages is not writeable
Collecting pyminizip
  Downloading pyminizip-0.2.4.tar.gz (258 kB)
     |????????????????????????????????| 258 kB 12.7 MB/s
Could not build wheels for pyminizip, since package 'wheel' is not installed.
Installing collected packages: pyminizip
    Running setup.py install for pyminizip ...
Successfully installed pyminizip-0.2.4
$ pip list
Package         Version
--------------- --------
boto3           1.9.143
botocore        1.12.143
docutils        0.14
jmespath        0.9.4
pip             20.1
pyminizip       0.2.4
python-dateutil 2.8.0
pytz            2019.1
s3transfer      0.2.0
setuptools      39.0.1
six             1.12.0
urllib3         1.24.3
 
  • 私の場合は、Pythonのソースと同じカレントディレクトリにもライブラリをインストールします。次のステップで行うデプロイパッケージの作成に使用します。

$ cd work-dir
$ pip install pyminizip --target .
Collecting pyminizip
  Using cached pyminizip-0.2.4.tar.gz (258 kB)
Could not build wheels for pyminizip, since package 'wheel' is not installed.
Installing collected packages: pyminizip
    Running setup.py install for pyminizip ...
Successfully installed pyminizip-0.2.4
$ ls
lambda-s3-make-passwdzip.py              pyminizip.cpython-36m-x86_64-linux-gnu.so
pyminizip-0.2.4-py3.6.egg-info
   

Lambdaにコードをデプロイする3つのポイント

ポイント1: デプロイパッケージの作成

  • 前述の環境構築の手順で、開発環境にLambdaで使用する標準以外のライブラリをインストールしたかと思います。開発したソースとカレントディレクトリにインストールしたライブラリをアーカイブしたデプロイパッケージを作成します。ここでのポイントは、上位のディレクトリをZIP圧縮するのではなく、カレントディレクトリ内のファイルのみをZIP圧縮することです。
  • 念のため、unzip -l コマンドを使用し、ZIPファイルを展開せず中身を確認します。

$ cd work-dir/
$ zip -r ../lambda-s3-make-passwdzip.zip .
  adding: pyminizip.cpython-36m-x86_64-linux-gnu.so (deflated 62%)
  adding: pyminizip-0.2.4.dist-info/ (stored 0%)
  adding: pyminizip-0.2.4.dist-info/top_level.txt (stored 0%)
  adding: pyminizip-0.2.4.dist-info/WHEEL (deflated 3%)
  adding: pyminizip-0.2.4.dist-info/METADATA (deflated 61%)
  adding: pyminizip-0.2.4.dist-info/RECORD (deflated 35%)
  adding: pyminizip-0.2.4.dist-info/INSTALLER (stored 0%)
  adding: lambda-s3-make-passwdzip.py (deflated 50%)
$ unzip -l ../lambda-s3-make-passwdzip.zip
Archive:  ../lambda-s3-make-passwdzip.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
   439880  05-11-2020 00:46   pyminizip.cpython-36m-x86_64-linux-gnu.so
        0  05-11-2020 00:46   pyminizip-0.2.4.dist-info/
       10  05-11-2020 00:46   pyminizip-0.2.4.dist-info/top_level.txt
      104  05-11-2020 00:46   pyminizip-0.2.4.dist-info/WHEEL
     2680  05-11-2020 00:46   pyminizip-0.2.4.dist-info/METADATA
      502  05-11-2020 00:46   pyminizip-0.2.4.dist-info/RECORD
        4  05-11-2020 00:46   pyminizip-0.2.4.dist-info/INSTALLER
     1475  05-07-2020 21:33   lambda-s3-make-passwdzip.py
---------                     -------
   444655                     8 files
 
  • 出来たデプロイパッケージをLambda関数にアップロードします。10MBを超える場合は、S3 経由でアップロードが必要となります。
     

ポイント2: Handler名を指定する

  • デプロイパッケージをアップロードした後、Handler名を指定する必要があります。Handler名は、「コードのファイル名.Handlerのメソッド名」となります。デフォルトのHandler名は、lambda_function.lambda_handlerですね。   

ポイント3: ランタイムのバージョンを指定する

  • 開発環境に合わせて、ランタイムのバージョンを指定する必要があります。今回、開発環境はPython 3.6 であり、ランタイムがPython 3.7 となっていたためRuntime.ImportModuleErrorが発生しました。
   

参考資料

 

AWS,Lambda

Posted by takaaki