schedule2019-02-06

AWS LambdaにPythonをモジュール毎zipでアップロードする方法

Pythonで書いたコードをzipにまとめてAWS Lambdaで実行する方法について紹介します。 pipでインストールしたモジュールも一緒にLambdaにアップロードします。

個人的な興味として、気象情報を取得してDynamoDBに保存するコードを定期的に実行する方法も書きます。こういったバッチ処理を切り出すとメインサーバの負荷が減ったり、コードの見通しが良くなり保守性も上がります。

この2つの続きであり、目標は気象データのAPIを作成することです。

環境

  • Linux Mint (Mac, Windows 10でも動作確認済み)
  • Python 3.6

Lambdaで動かすための準備

ローカルにて作成したコードをLambdaで動かすための準備をします。

Lambdaで外部モジュールを利用するには?

LambdaではPythonコードを直接書いて(インラインコード)実行することが出来ます。 ただし、この場合は外部モジュールをpipでインストールすることは出来ません。 そこで、コードとモジュールをzipでまとめてアップロードする必要があります。

手作業でzipにまとめる場合は、まずモジュールをコードと同じディレクトリにインストールします。

pipでカレントディレクトリにインストールする

pipでコードと同じディレクトリにインストールします。 前回作成したコードに必要なモジュールを用意していきます。 以下の2つをインストールする。

  • boto3
  • requests

実行ファイルのあるディレクトリに移動して、オプション-tで指定の場所にモジュールをインストールする。

$ cd [実行ファイルのディレクトリ]
$ pip install boto3 -t ./
$ pip install requests -t ./

そうすると以下のようなファイルが置かれます。 lambda_function.pyは前回製作したLambdaで実行するメインコード。

$ ls
bin                           chardet                  jmespath                         s3transfer
boto3                         chardet-3.0.4.dist-info  jmespath-0.9.3.dist-info         s3transfer-0.1.13.dist-info
boto3-1.9.86.dist-info        dateutil                 lambda_function.py               six-1.12.0.dist-info
botocore                      docutils                 __pycache__                      six.py
botocore-1.12.86.dist-info    docutils-0.14.dist-info  python_dateutil-2.7.5.dist-info  urllib3
certifi                       idna                     requests                         urllib3-1.24.1.dist-info
certifi-2018.11.29.dist-info  idna-2.8.dist-info       requests-2.21.0.dist-info

一度、lambda_function.pyを実行して確認してみてください。

実行権限を変更する

Lambdaが実行できるようにファイルの権限を変更します。

755をつけます。 実行と読みこみの権限があれば大丈夫です。

$ chmod -R 755 ./*

-Rはディレクトリ内も再帰的に処理します。

zipに圧縮してまとめる

続いて、Lambdaにアップロードするためコードとモジュールをzipにまとめます。 コマンドでも圧縮ツールでまとめるてもどちらでも良いです。

この時、コードのディレクトリ内のファイルを選択してzipにして下さい。 ディレクトリを選択してzipにすると、1階層分深くなりLambdaのハンドラが読めません。 (Lambdaの設定で回避できそうだが、上手くいかなかった。)

ツールで圧縮する。

ツールで圧縮しても大丈夫です。 ただし、Windowsの場合はAWSのドキュメントにある通り7-ZIPでzip化することが推奨されています。

windows-zip

図のように、ディレクトリ内のファイルを選択してzipにして下さい。

コマンドでzipにする。(LinuxまたはMac)

以下のコマンドでzipにできます。

$ cd [実行ファイルのディレクトリ]
$ zip -r zip_file ./*

zip_file.zipというファイルができているはずです。 ファイル名は適宜変更して構いません。

zipコマンドの詳細はこちら

AWS Lambdaを用意する

続いてAWS Lambdaを用意していきます。

Lambda関数を作成する

AWSコンソールのサービスからLambdaを選びます。 「ダッシュボード」か「関数」から「関数の作成」ボタンを押してLambda関数を作成します。 この後は「一から作成」の手順を解説します。

それぞれ項目を記入していきます。

lambda-setting

Pythonのランタイムは2.7、3.6、3.7とあり利用したいバージョンを選びます。 バージョンは後からも変更可能です。 (図では3.7を選んでいますが3.6で前回作ったことを思い出して、後で変更しました。)

ロールは既存のロールを選択して、「microService」を選んでみました。 DynamoDBの操作定期実行するためのCloudWatch Eventsを利用できます。

下図は関数を作成後の初期画面です。 左がLambdaを実行するトリガー、右がLambdaが操作できるサービスです。 選択できるサービスはロールの「microService」が権限を持つものです。

lambda-init

CloudWatch Eventsを設定して定期実行する

定期実行するために左のトリガーからCloudWatch Eventsを選択します。

selected-cw-events

CloudWatch Eventsがトリガーとして追加されました。 CloudWatch Eventsをクリックすると実行する時間を設定できます。

setting-cw-events

cron(2/30 * * * ? *)

利用するOpenWeatherMapのAPIの更新頻度が30分間隔なので、スケジュールも30分ごとに設定しました。 ちょうどだと更新出来ていないことがあるので、2分待ってから取得する設定です。

AWS公式による設定の詳細はこちら

設定が終わるとこうなります。

set-cw-events


追記:Eventの詳細で実行した日時の記録が見れました。設定は間違っていないようです。

cron


Lambdaの設定は以上です。

zipファイルをLambdaにアップロードする

間が空きましたが、作成したzipファイルをLambdaにアップロードします。

zip-upload

「アップロード」ボタンからzipファイルを選んでアップロードします。

ファイルサイズの制限とAmazon S3経由でのアップロード

この方法では、ファイルサイズに10MBまでの制限があります。 それ以上に大きい場合は、一度S3を経由してLambdaへアップロードすることになります。 「コード エントリ タイプ」を変更して、Amazon S3 のリンク URLを張り付けます。

via-s3

ハンドラの設定

「ハンドラ」はLambdaが実行する関数を指定する箇所です。

デフォルトではlambda_function.lambda_handlerとなっています。 これはlambda_function.pylambda_handler()という関数を実行します。

前回作ったコードもデフォルトに合わせてあります。 また、zipファイルを作成するとき階層を意識してzip化したのもこのためです。

アップロードが終わったら、上部の「保存」を押してコードを保存して下さい。

Lambda関数をテストしてみる。

以上で実行できるはずです。 大丈夫かどうかテストしてみます。

「保存」ボタンの横に「テスト」があるので押します。

test

こんな感じになりますが、今回のコードはパラメータを受け取るタイプではないので適当に作っても実行できます。 イベント名をつけたら保存します。

先ほど作ったテストイベントを選んで「テスト」を押すと実行できます。

success

成功するとこうなります。 詳細を開くとprint()で出力したログが出るのでちゃんと動いているか確認できます。

処理に失敗した場合

失敗した場合はエラーログを確認してください。 よくあるのはpermission deniedでファイルの実行権限がない。また、「ファイルもしくは関数が見つかりません」です。 ディレクトリ構造と権限を見直して何度が試してみてください。

スケジュール実行は待ってみて結果が解ると思います。

おわりに

以上で定期的に気象データを取得してDynamoDBに貯めることが出来ました。

zipでLamdaにあげる以外にも、zappaを使ってコマンドで行う方法もあります。 zappaはモジュールをまとめるだけでなく、API Gatewayなども自動で用意させることも出来ます。 そちらを知りたい方は、Zappaを使ってPythonのコードをAWS Lambdaにデプロイするを見てください。

こちらもどうぞ