Python & Serverless FrameworkでLambdaファンクションをサクッと作ってデプロイする
Serverless FrameworkはAmazon AWSの開発&管理を補助するフレームワークです。 最近アルバイト先でserverlessを用いたアプリケーションに関わり、その際に使いかたを軽く勉強したので、ブログに書き残しておきます。
環境
- Node.js 10.6.0
- Python 2.7.15
- serverless 1.29.2
Installation
ServerlessはNode.jsのアプリケーションとして配布されており、npm
コマンドからインストールできます。
npm install -g serverless # 確認 serverless --help sls --help # slsという短縮コマンドが自動でエイリアスされるらしい
サービスを作ってデプロイ
インストールが完了したので、簡易的なLambdaのファンクションを作成してAWSにデプロイするところまでやってみましょう。 今回は毎朝8時にLINE Notificationを送ってくれる目覚ましファンクションを作ってみます。
サービスの新規作成
sls create
コマンドでサービスを新規作成できます。
このとき-t
オプションでアプリのテンプレートを、-p
オプションでサービスを保存するパスを指定できます。
テンプレートはaws-python
*1、保存先は適当な作業ディレクトリ上のlambdaMezamashi
というディレクトリにします。
cd /path/to/working/dir #適当な作業ディレクトリに移動 sls create -t aws-python -p lambdaMezamashi cd lambdaMezamashi ls # => handler.py serverless.yml
コマンドを打つと、lambdaMezamashi
というディレクトリが作成され、handler.py
とserverless.yml
という2つのファイルが自動生成されます。
handler.py
はLambdaのファンクションを書くファイルで、serverless.yml
は設定ファイルになります。
とりあえず動かす
アプリが完成したのでとりあえず動かしてみます。
テンプレートにはhello
という関数名で簡単なメッセージを返す関数が定義されています。
sls invoke local -f {関数名}
で指定した関数名の関数をローカル環境で実行できます。
sls invoke local -f hello # => { # => "body": "{\"input\": {}, \"message\": \"Go Serverless v1.0! Your function executed successfully!\"}", "statusCode": 200 # => }
LINE Notificationを送る関数を記述
LINE Notificationの使いかたはこちらの記事でも解説しています。
まず、LINE Notifyのページからアクセストークンを取得し、環境変数LINE_NOTIFY_TOKEN
に書き入れます。
export LINE_NOTIFY_TOKEN=XXXXXXXXX # bash zsh等の場合 set -x LINE_NOTIFY_TOKEN XXXXXXXXX # fishの場合
次に以下のようにhandler.py
を書き換え、LINE NotifyのAPIを叩くコードを追加します。
# -*- coding: utf-8 -*- import os import json import requests def mezamashi(event, context): output_url = "https://notify-api.line.me/api/notify" token = os.getenv("LINE_NOTIFY_TOKEN", "") headers = {"Authorization" : "Bearer "+ token} payload = {"message" : "こんにちは"} response = requests.post(output_url ,headers = headers ,params=payload) return response.json() def hello(event, context): body = { "message": "Go Serverless v1.0! Your function executed successfully!", "input": event } response = { "statusCode": 200, "body": json.dumps(body) } return response
次にpip
コマンドでrequests
をインストールします。
pip install requests
次にserverless.yml
を書き換え、mezamashi
関数に関数名を割り当てます。
service: lambdaMezamashi provider: name: aws runtime: python2.7 environment: # LINE Notifyのアクセストークンを記入 # invoke localで実行する場合はこれを記述しなくても動作するが、デプロイ時に必要となる LINE_NOTIFY_TOKEN: XXXXXXXXXXXXXXXX functions: hello: handler: handler.hello mezamashi: handler: handler.mezamashi
そうしたら、serverless invoke local
を用いて動作確認を行います。
sls invoke local -f mezamashi # => { # => "status": 200, # => "message": "ok" # => } # (LINEに通知が来る)
スケジュール実行の設定
Lambdaファンクションの実装が完成したので、これをスケジュール実行するように設定を書きます。
serverless.yml
のfunctions
の部分にイベント設定を追記するだけです。
functions: #<中略> mezamashi: handler: handler.mezamashi events: # イベントの設定を記述 - schedule: cron(0 23 * * ? *) # cron式で日本時間の朝8時を指定
ついでにAPI Gatewayも使う
LambdaはAPI Gatewayと組み合わせることでwebアプリのバックエンドとして使用するケースもよくあります。 少し脱線しますが、ymlを用いてLambdaファンクションをAPI Gatewayと結びつける方法も説明しておきます。
events
の項目に- http: {メソッド} {APIのURI}
の形式で記述します。
こうすることでデプロイした際に自動でAPI Gatewayが作成されます。
functions: hello: handler: handler.hello events: - http: GET hello
オフラインでテストする
ファンクションが書けたので早速デプロイと行きたいところですが、その前にローカルホストでLambdaファンクションをホストして、APIのテストを行う方法を解説します。 これは、業務でデバッグやAPIのテストコードを走らせる場合にも必要なことなので覚えておいて損はありません。
まず、必要なプラグインをインストールします。インストールはsls plugin install -n {プラグイン名}
で行います。どうやらこのコマンドはnpm i --save-dev
をラップしてnode_moduleをインストールしつつ、serverless.yml
にプラグイン情報を追記してくれるものらしいです。
sls plugin install -n serverless-offline npm install serverless-offline-python --save-dev # slsコマンドからインストールできないためnpmを直接使う
次にserverless.yml
の末尾に以下のように書き込んでserverlessとプラグインを紐付けます*2。
plugins: - serverless-offline - serverless-offline-python
serverless-offline
とserverless-offline-python
をインストールしたことで、serverless offline
というコマンドが使えるようになります。これによりローカル環境でcurlコマンド等を用いてAPIのデバッグが可能になります。
sls offline #=> Serverless: Starting Offline: dev/ap-northeast-1. #=> (中略) #=> Serverless: Offline listening on http://localhost:3000 # =====他のterminal窓から以下を実行===== curl localhost:3000/hello #=> helloファンクションが動く
ちなみにserverless-offline-scheduler
というオフライン環境でスケジュール実行のデバッグができるプラグインがありますが、Node.jsで書いたものしか動かないみたいです*3。
デプロイする
最後にデプロイの方法を説明します*4。
AWSアカウントの設定
最初にAWSアカウントの設定をします。
AWSのマネジメントコンソールにログインし、IAMから新規ユーザーを追加します。
ユーザー名を適当に設定し、「プログラムによるアクセス」にチェックを入れます。
「既存のポリシーを直接アタッチ」から「AdministratorAccess」を選択します*5 *6。
ユーザーの作成が完了したら、「アクセスキーID」と「シークレットアクセスキー」を控えておきます。シークレットアクセスキーはこのときにしか確認できないため、忘れた場合には再度アカウントを作成する必要があります。
これを、sls config credentials
コマンドを用いて設定します。XXXXXの箇所は適宜アクセスキー、アクセスキーシークレットに書き換えてください。
sls config credentials --provider aws --key XXXXX --secret XXXXX
デプロイ、実行、削除
アカウントの設定が済んだら遂にデプロイです。
Serverless Frameworkはsls deploy
コマンドを実行するだけで簡単にデプロイできるようになっています。
しかし、今回のようにPythonで実装している場合は、自分で書いたコードだけでなくサードパーティ製のライブラリも一緒にデプロイする必要があります。
serverless-python-requirements
というプラグインをインストールするとデプロイ時に自動でこの作業をやってくれるため、今回はこのプラグインを利用することにします。
sls plugin install -n serverless-python-requirements # プラグインのインストール pip freeze > requirements.txt # 依存関係をrequirements.txtというファイルに書き出す
上記のコマンドを実行したら、デプロイします。
sls deploy #=> Serverless: Installing requirements of requirements.txt in .serverless... #=> Serverless: Packaging service... #=> (中略) #=> service: lambdaMezamashi #=> stage: dev #=> region: ap-northeast-1 #=> stack: lambdaMezamashi-dev #=> api keys: #=> None #=> endpoints: #=> GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello #=> functions: #=> hello: lambdaMezamashi-dev-hello #=> mezamashi: lambdaMezamashi-dev-mezamashi
これで完成です。毎朝8時にLINEに通知が来るようになりますし、https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/hello
のURIにcurl
コマンドやAjax通信でアクセスするとhello
ファンクションをWeb APIとして叩くことができます。
デプロイしたアプリの削除も簡単に行うことができ、sls remove
コマンドを実行するだけです。
sls remove #=> Serverless: Getting all objects in S3 bucket... #=> Serverless: Removing objects in S3 bucket... #=> Serverless: Removing Stack... #=> Serverless: Checking Stack removal progress... #=> ............................. #=> Serverless: Stack removal finished...
さいごに
今回はServerless Frameworkの使い方を軽く説明しました。 Serverless Frameworkは他にもDynamoDBやS3といったサービスを操作することができ、その名の通りサーバレスなwebアプリケーションを構築することができます。
S3でwebページをホストし、Lambda & API Gatewayでバックエンドの処理を行い、DynamoDBやCognitoでユーザ情報を管理するという構築にすればどんなWebアプリでも作れそうですね。
参考資料
- 今から始めるServerless Frameworkで簡単Lambda開発環境の構築 | Developers.IO
- Rate または Cron を使用したスケジュール式 - AWS Lambda
- Serverless - AWS Guide
*1:was-python3だとローカルで動かす際にpyenv等を用いてver 3.6のPython環境を用意する必要があります。今回は面倒なので2.x系で我慢
*2:# sls plugin ~~ コマンドを走らせた際に自動で追記してくれるため、serverless-offline-python以外は不要かも
*3:実際にソースコードを確認したところ、Lambdaファンクションが記述されたjsファイルをrequireで読み込んで実行するという実装がされているようだった https://github.com/ajmath/serverless-offline-scheduler
*4:これ以降の部分で解説するコマンドを実行するとLambdaファンクションがAPI Gatewayを通して全世界から実行可能な状態になります。Lambdaファンクションに脆弱性が存在した場合には思わぬ被害を被る可能性があることを心に止めておいてください。
*5:公式ドキュメントでもAdmin権限を設定する(https://serverless.com/framework/docs/providers/aws/guide/credentials/)という解説されています。
*6:Serverless Frameworkは開発中でやれることがどんどん増えています。そのためAdmin権限でないと機能に制限がかかり、開発が面倒になる可能性があります。Amdin権限で開発しつつ、製品を公開する際に権限を必要最低限に絞るような運用が望ましいと思われます。