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化することが推奨されています。
図のように、ディレクトリ内のファイルを選択してzipにして下さい。
コマンドでzipにする。(LinuxまたはMac)
以下のコマンドでzipにできます。
$ cd [実行ファイルのディレクトリ]
$ zip -r zip_file ./*
zip_file.zip
というファイルができているはずです。
ファイル名は適宜変更して構いません。
zipコマンドの詳細はこちら。
AWS Lambdaを用意する
続いてAWS Lambdaを用意していきます。
Lambda関数を作成する
AWSコンソールのサービスからLambdaを選びます。 「ダッシュボード」か「関数」から「関数の作成」ボタンを押してLambda関数を作成します。 この後は「一から作成」の手順を解説します。
それぞれ項目を記入していきます。
Pythonのランタイムは2.7、3.6、3.7とあり利用したいバージョンを選びます。 バージョンは後からも変更可能です。 (図では3.7を選んでいますが3.6で前回作ったことを思い出して、後で変更しました。)
ロールは既存のロールを選択して、「microService」を選んでみました。 DynamoDBの操作と定期実行するためのCloudWatch Eventsを利用できます。
下図は関数を作成後の初期画面です。 左がLambdaを実行するトリガー、右がLambdaが操作できるサービスです。 選択できるサービスはロールの「microService」が権限を持つものです。
CloudWatch Eventsを設定して定期実行する
定期実行するために左のトリガーからCloudWatch Eventsを選択します。
CloudWatch Eventsがトリガーとして追加されました。 CloudWatch Eventsをクリックすると実行する時間を設定できます。
cron(2/30 * * * ? *)
利用するOpenWeatherMapのAPIの更新頻度が30分間隔なので、スケジュールも30分ごとに設定しました。 ちょうどだと更新出来ていないことがあるので、2分待ってから取得する設定です。
AWS公式による設定の詳細はこちら。
設定が終わるとこうなります。
追記:Eventの詳細で実行した日時の記録が見れました。設定は間違っていないようです。
Lambdaの設定は以上です。
zipファイルをLambdaにアップロードする
間が空きましたが、作成したzipファイルをLambdaにアップロードします。
「アップロード」ボタンからzipファイルを選んでアップロードします。
ファイルサイズの制限とAmazon S3経由でのアップロード
この方法では、ファイルサイズに10MBまでの制限があります。 それ以上に大きい場合は、一度S3を経由してLambdaへアップロードすることになります。 「コード エントリ タイプ」を変更して、Amazon S3 のリンク URLを張り付けます。
ハンドラの設定
「ハンドラ」はLambdaが実行する関数を指定する箇所です。
デフォルトではlambda_function.lambda_handler
となっています。
これはlambda_function.py
のlambda_handler()
という関数を実行します。
前回作ったコードもデフォルトに合わせてあります。 また、zipファイルを作成するとき階層を意識してzip化したのもこのためです。
アップロードが終わったら、上部の「保存」を押してコードを保存して下さい。
Lambda関数をテストしてみる。
以上で実行できるはずです。 大丈夫かどうかテストしてみます。
「保存」ボタンの横に「テスト」があるので押します。
こんな感じになりますが、今回のコードはパラメータを受け取るタイプではないので適当に作っても実行できます。 イベント名をつけたら保存します。
先ほど作ったテストイベントを選んで「テスト」を押すと実行できます。
成功するとこうなります。
詳細を開くとprint()
で出力したログが出るのでちゃんと動いているか確認できます。
処理に失敗した場合
失敗した場合はエラーログを確認してください。
よくあるのはpermission denied
でファイルの実行権限がない。また、「ファイルもしくは関数が見つかりません」です。
ディレクトリ構造と権限を見直して何度が試してみてください。
スケジュール実行は待ってみて結果が解ると思います。
おわりに
以上で定期的に気象データを取得してDynamoDBに貯めることが出来ました。
zipでLamdaにあげる以外にも、zappaを使ってコマンドで行う方法もあります。 zappaはモジュールをまとめるだけでなく、API Gatewayなども自動で用意させることも出来ます。 そちらを知りたい方は、Zappaを使ってPythonのコードをAWS Lambdaにデプロイするを見てください。