こんにちは。DSOC R&Dグループの高橋寛治です。
最近、何かと使っているAWS(Amazon Web Services)で、API GatewayとAWS Lambdaを利用したAPI開発について紹介します。
少しボリュームのある内容になりますので、複数回に分けます。
- API GatewayとAWS Lambdaを知る
- ローカルでの開発環境構築
- エラー処理
- デプロイ
サーバーレスでAPIが簡単に作れる
API GatewayとAWS Lambdaを組み合わせることの最大の特徴は、サーバーレスAPIが簡単に作れるということです。
従来、APIを作成するためには、Webサーバーを立てて、さまざまなセットアップをする必要があり、特にちょっとしたAPIを作成する際には手間がかかっていました。また、負荷対策にロードバランサーを配置して台数調整するなど、いろいろと考慮することが多くなりがちでした。
これに対して、API Gatewayではブラウザ上で簡単にAPIを構築し、AWS Lambdaのコードを呼び出すことで、スケーラブルなAPIを簡単に作ることができます。
API Gateway
API Gatewayはたくさんの特徴を持っています。あえて一言で言うならば、「非常に手軽にAPIが作れるサービス」です。
Webコンソール上でAPIの設定ができてしまう便利さはすさまじいです。
例えば、エンドポイントの設定、どのLambda関数を呼び出すか、アクセス権限をどうするかなどといったことは、簡単に設定することができます。
デプロイも多機能です。デプロイするステージを設定することができ、例えばURLを以下のように設定することができます。
http://hoge-aws.com/stg/path-to-api
http://hoge-aws.com/pro/path-to-api
何と言えばいいのか、恐ろしいほど手軽にエンドポイントが作成できます。
AWS Lambda
AWS Lambdaは、サーバーを構築することなく、アップロードしたコードを実行させることができる従量課金制のサービスです。
ユースケースとしては、AWS上のリソースの読み書きや、データ処理が挙げられます。アプリケーションが常に動作しているのではなく、あるイベントに対して処理をして返すという、箱のイメージです。
AWS内での連携では、トリガーと呼ばれる便利な機能があり、例えばAPI Gatewayで作成したAPIエンドポイントが叩かれると、Lambda関数を実行するといった具合です。
他にも、対象のDynamo DBにデータが書き込まれた際にフックしてLambda関数を動作させる、というようにAWSの各サービスと手軽に連携することができます。
こういった連携処理は、AWSコンソール上でクリックして設定するだけで実現することができます。
Lambdaの環境
対応言語は以下のとおりです。 - Python3.6および2.7 - Node.js v4.3.2および6.10.3 - C# .NET Core 1.0.1 - Java 8
バイナリを実行するときに気になる、Amazon Linux AMIのバージョンは amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2
です。
Lambdaの独特な特徴として、最大実行時間とメモリー容量が設定されていることが挙げられます。
実行時間は5分まで。メモリー容量は、128MBから3008MBまで選択できます。メモリーサイズが大きければ大きいほど、CPUの速度も向上します。
Lambda関数の入出力
基本的には、下記のようなハンドラーメソッドを作成することで、入出力を行います。
def lambda_handler(event, context):
print("print log.")
return {
"message": "Hello World",
}
event
はPythonのdictでパラメータが引数として代入されます。
例えば、API GatewayからPOSTリクエストが下記のようにdictで代入されます。
{
"key": "Hello World!"
}
context
はランタイム情報をハンドラーメソッドに渡します。
print
メソッドの出力は、ログに書き出されます。ログは、CloudWatchで確認可能です。
LambdaでPythonモジュールやバイナリを走らせるには?
Lambda上にアップロードしたスクリプトが動作することは分かったと思いますが、Pythonモジュールのインストールやコンパイルして動かすバイナリについて、どうしたら良いのか、分からなくなってしまいがちです。
Pythonモジュールに関しては、プロジェクトのルートディレクトリー以下にインストールをすることで対応できます。
pip
コマンドには、インストール先指定オプション -t
があります。
ここで、プロジェクトのルートディレクトリーにインストールすると大量にファイルができて、ディレクトリーがごちゃごちゃしてしまいます。
私は、回避策としてプロジェクトのルート以下に python_modules
ディレクトリーを作成し、そこに pip -t python_modules install hogehoge
とインストールしています。1
Pythonコードから python_modules
ディレクトリーをパスに追加することを忘れないよう注意しましょう。
import sys
sys.path.append("./python_modules")
次にコンパイルしたパッケージを走らせたいという場合があると思います。
ここでは、日本語形態素解析器「MeCab」を動作させることを目標に例を示します。
LambdaのAmazon Linux AMIと同じイメージのEC2インスタンスを立て、この中でコンパイルなどの作業を行います。
まず、MeCabと辞書をプロジェクトルート以下の env
2 にインストールします。 $PROJECT_HOME
は、プロジェクトのルートの絶対パスが格納されているという設定です。
# MeCab
cd mecab-0.996
./configure --prefix=$PROJECT_HOME/env --with-charset=utf8 --enable-utf8-only
make && make install
# MeCab-IPAdic
cd mecab-ipadic-2.7.0-20070801
./configure --prefix=$PROJECT_HOME/env --with-charset=utf8 --enable-utf8-only
make && make install
次に、MeCabのPythonバインディングである mecab-python3
をインストールします。
mecab-config
が必要となり、これは先程 ${PROJECT_ROOT}/env/bin
以下にインストールしたため、PATHを追加します。
PATH=${PROJECT_ROOT}/env/bin:${PATH} pip install mecab-python3
実は、 import MeCab
ではまだ動作せず、もう一工夫が必要です。
MeCabをビルドした際に生成された動的リンクライブラリーをロードする必要があります。
import ctypes
import os
# MeCab動作に必要な動的ライブラリを読み込み
libdir = os.path.join(os.getcwd(), 'env', 'lib')
ctypes.cdll.LoadLibrary(os.path.join(libdir, 'libmecab.so'))
import MeCab
# デフォルト辞書を指定
dicdir = os.path.join(os.getcwd(), 'env', 'lib', 'mecab', 'dic', 'ipadic')
rcfile = os.path.join(os.getcwd(), 'env', 'etc', 'mecabrc')
tagger = MeCab.Tagger("-d{} -r{}".format(dicdir, rcfile))
これでMeCabが動作します。
最低限、仕組みを知って実装へ
素早く実装を進めるためには、対象のマシンやサービスがどのような仕組みを持っているかを知る必要があります。
今回は特に、Lambdaの実装面での仕様理解を中心に紹介しました。
次回は、Lambda関数を作る上で何かと厄介な、ローカルでの開発環境の構築について書きたいと思います。
執筆者プロフィール
過去記事
▼第5回
快適なシェル環境の再構築を自動化する
▼第4回
第16回情報科学技術フォーラム(FIT2017)で登壇
▼第2回
R&D論文読み会勉強会
▼第1回
言語処理100本ノック勉強会