はじめに
2015/10のAmazon re:Invent 2015で、Lambdaに関して幾つかの機能追加が発表されました。
個人的に大きいのは以下の3つです。
- Lambda functionをPythonで記述できる
- Lambda functionをSchedule実行させる事ができる
- Lambda functionの最大実行時間が5分に拡張された (従来は1分)
AWS LambdaをData Pipelineを使ってSchedule Drivenで起動させる記事を以前書いたのですが、Schedule実行の機能はLambdaの標準機能としてサポートされました。この記事ではLambda functionをPythonを使って記述し、Schedule実行させる手順をチラ裏しておきます。
制限事項
今回発表/追加されたLambda + Python + Scheduleの実行環境ですが、気を付けて置くべき制限があります。大きいのは以下の項目です。
- Lambda functionの処理は5分以内に終了させないとErrorになる(なので時間がかかる処理には使えない)
- Schedule実行の最短周期は5分 (なので1分に1回Lambda functionを実行する、とかはできない)
- PythonはVer 2.7のみ対応 (3.xは現時点で対応されていない)
- PythonでPython2.7の標準library以外をimportして使用するには、library毎zip圧縮してUploadする必要がある(手順は後述)
Case1:5分毎にPythonのPrintで出力をしてみる
一番最初のCase studyとして、単にPrintするだけのPython Scriptを、5分毎のSchedule実行させる、という一番ベタなケースです。Schedule実行の結果が正しく出力されているかLogを見てみます。
AWS ConsoleのLambdaから、Create a Lambda functionを選択します。
Step1 雛形(blueprint=青写真)の選択
Lambda functionの雛形が沢山ありますがlambda-canaryを検索して選びます。Lambda function上で、Python scriptをSchedule実行させる雛形です。
Step2 Event sourceの設定
今回はSchedule実行なので、Event sourceにはScheduled Eventを選択します(defaultで選ばれていると思います)。
NameとDescriptionは適当な説明文を入れればOKです。
Schedule expressionはdefaultでrate(5 minutes)になっているはずなのでそのままで良いです。
Step3 Python scriptの設定
Python scriptと、IAM roleの設定を行います。
Pythonのcodeは以下を使います。ひたすらprintするだけのCodeです。
import json, datetime, commands
def lambda_handler(event, context):
print commands.getoutput('cat /proc/cpuinfo | grep -e "processor" -e "model name"')
print commands.getoutput('cat /proc/meminfo | grep MemTotal')
print commands.getoutput('cat /proc/meminfo | grep MemFree')
print datetime.datetime.now().strftime('%Y/%m/%d %H:%M')
print '-------------------------------'
print event
print event['account']
print context.__dict__
print context.memory_limit_in_mb
Python script以外は、以下の設定が必要です。他はDefaultのママで良いです。
-
NameはLambda functionの名前です。(他のLambda functionと被らなければ)適当な文字列で良いです。 -
RoleはLambda functionに付与するIAM roleです。今回は他のAWS Resourceにアクセスしないので、lambda_basic_executionを選択すれば良いです(lambda_basic_executionと言うIAM roleが無い場合には、この名前のroleを作成する事になります)。
Step4 設定確認
最終確認です。Enable nowを選択すると、この設定でSchedule実行がEnableされます。Enable nowを選択しCreate functionを押せば完成です。
Step5 Print出力された結果を確認
Lambda functionの出力結果は、CloudWatch logsに保存されます。
AWS ConsoleのCloudWatchのLogsから、Lambda_Testを選択します。すると、5分毎に実行Logが追加され、printした内容がLogに残っていると思います。
Python scriptの補足
- Python2.7に標準で入って居るLibraryは、
import json, datetime, commandsの様に書けばOKです -
mainというmethodは無く、lambda_handlerというMethodがEntry pointとして(event,contextという引数で)呼ばれます。
Entry pointの関数はConfigurationのHandlerで指定を変える事が可能です
- Entry pointの引数である
event,contextの中身は、何をEvent sourceとするかで違ってきています。printでevent,contextの中身を吐き出しているので、チェックしてみてください。
Case2:Schedule実行の周期を5分毎から10分毎に変えてみる
Step1 古いSchedule実行設定の削除
AWS ConsoleのLambdaから、先ほど作ったLambda_TestのfunctionのEvent sourcesのタブに行きます。
rate(5 minutes)で設定したSchedule実行をxで一旦削除し、Add event sourceを選択します

Step2 10分毎のSchedule実行の設定
Add event sourceのDialogで、Event sources typeにScheduled Eventを選択し、以下の様にDialogを埋めます。
-
NameとDescriptionは適当な説明文を入れる -
schedule expressionでcronを選択し、cron(0/10 * * * ? *)と書く
ここで注意なのは、Lambdaのcronの文法が、いわゆるLinux一般のcronの文法と微妙に違う点です。
この記事を参考にcron(0/10 * * * ? *)と書いてください。
Enable nowを選択すると、この設定でSchedule実行がされます。10分毎に実行LogがCloudWatch logsにあるか確認して見て下さい。
Case3:標準ではないLibraryを入れてみる
numpyやpandasやrequestsと言った、Python2.7標準では無いlibraryをLambda + Pythonで使いたい場合は、Script fileそのものと合わせてLibraryも一緒にzipしてuploadして上げる必要があります。詳細は、AWS公式サイトのCreating a Deployment Package (Python)を参照して下さい。
Step1 Python scriptをfileとして保存
以下のPython scriptをLocalに保存します (ここではLambdaTest.pyと言うfile名で保存する想定で進めます)。
Python Scriptの中身は、requestslibraryを使ってgoogle.co.jpをHTTP GETして、Status CodeとResponse BodyをPrintするものです。
import requests, datetime
def lambda_handler(event, context):
target_URL = 'https://www.google.co.jp'
r = requests.get(target_URL)
print datetime.datetime.now().strftime('%Y/%m/%d %H:%M')
print '-------------------------------'
print r.status_code
print '-------------------------------'
print r.text
requestsと言う、Python2.7標準に無いlibraryが必要なので、このCodeをこのままLambdaに登録するとErrorになります。そのため、requestsのlibrary fileを同じフォルダに置き、zip圧縮して、zipをLambdaに登録します。
Step2 Libraryを含んだzip fileを作成
pip installを-t /PathTo/LambdaTest.py optionで実行すると、指定したフォルダにlibrary fileを配置してくれます。例えば、LambdaTest.pyが/home/hogeに有るとしたら、pip install -t /home/hogeと実行すればOKです。
以下みたいなファイル構成になるはずです。これら(フォルダが2個、ファイルが1個)をzip圧縮して、適当な名前を付けます(LambdaLibraryZip.zipとしたとします)
Step3 Entry Pointの関数名を変更
Lambda functionのCodeをzipでUploadする場合、Entry Pointの関数名(Pythonのmain関数)が*.pyのファイル名 + . + Scriptの中のEntry Pointの関数となります。今回の例で言うと、LambdaTest.lambda_handlerと設定する必要があります。ConfigurationタブのHandlerをLambdaTest.lambda_handlerと設定します
Step4 zip fileをUploadして実行
Codeタブから、Upload a .ZIP fileで、先ほど作成したLambdaLibraryZip.zipをUploadして、Save and testをクリックして、Python Scriptが正しく実行されているか確認してみてください。
最後に
LambdaのPython対応、Schedule実行対応は、Python Loveな私的にはとても良いNewsです。Amazonの掲げる2 tier Architecture、もしくはサーバレスアーキテクチャへの大きな布石になると思います(そしてAmazonにどんどんLockinされていく...)。
ただ、まだLambda + Python + Schedule実行でも置き換えられない領域が幾つかあると思います。
短い周期での実行が必要なケース
Lambdaの最短実行周期は5分です。これで多くのニーズはカバーされると思いますが、『1分毎にStatus Checkや死活監視したい』などの要件もやはりあります。Server-lessで短い周期のSchedule実行を行うAWS serviceを自分は知らないです(知っていたら教えてください)。
Amazonが出してきた提案は、EC2 t2.nano Instanceなのでは、と思っています。現行のt2.microよりも更に安いInstanceを用意してヤッから、これ使ってチラシの裏にでも書いてな、って事です。
処理に時間かかかるケース
Lambdaの最大処理時間は今回5分に拡張されました(従来は1分でした)。1分だった時は、S3のLogをLocalに持って来て、中身をParseして、Errorが見つかったらAlarmを発動しつつ結果をRDSに書き込んでおくと言った処理をLambda functionでする時に、Log sizeが数100MBを超えるとTimeoutするようなケースがありましたが、今回の5分への拡張で多くのニーズはカバーされると思います。が、『大量のDataのDailyのETL Batch処理』などの処理の時間が必要な要件もやはりあります。
自分の知る限り、この手の演算やData転送で処理に時間が掛かる要件には、
- 演算能力が必要無い場合は、Data Pipeline + Pythonを使う
- 演算能力が必要な場合は、Lambda Schedule実行で必要なSpecを持つEC2 (Spot) Instanceを立てる
が良いんじゃないかなぁ、と思っています。








