概要
- AWS純正のフレームワークであるChaliceを利用して、爆速でAPIサーバを構築しようという話です
- 探せばいくらでも記事が出てくるのですが、情報が散見してるのでまとめてみた
Chaliceとは?
- サーバーレスアプリケーションのためのフレームワーク
- サーバレス環境が簡単に構築できるよ
- コンソールぽちぽちする必要もないし、ymlファイルを書いたりする必要もない
前提
- ~/.aws/config と~/.aws/credential の設定を行なっていること
- pythonが使える環境であること(3.9系で動かしています)
- APIサーバに限らず、他のAWSサービスと連携してもっと色々なこともできるようなのですが、今回は割愛します
手順
基本
①chaliceをインストール
$ pip install chalice
②プロジェクト作成
$ chalice new-project helloworld
こんな感じのディレクトリ構成のフォルダが出来上がると思います
.
├── .chalice
│ └── config.json
├── .gitignore
├── app.py
└── requirements.txt
③ローカル環境でアプリを実行
ルートディレクトリで以下を実行
$ chalice local
Serving on http://127.0.0.1:8000
ブラウザでアクセスしてみると {"hello": "world"} が表示されるはずです。
ディレクトリ構成を変えてみる
- app.pyの中身は以下のようになっています
from chalice import Chalice
app = Chalice(app_name = 'helloworld')
@app.route('/')
def index():
return {'hello': 'world'}
- この状態だと全てのコードを app.py に記載しなければなりません。
- そこで、chalicelib を使ってディレクトリ構成を変えてみます
- chaliceでは、chalicelib と名付けたディレクトリ以下にモジュールを配置できます。
- ここに配置したモジュールはapp.pyでimportして使えるので、共通処理や各APIを切り分けて実装可能です。
- ↓こんな感じで運用するのがいいかもしれない
.
├── .chalice
│ ├── config.json
│ └── custom-policy.json
├── .gitignore
├── app.py
├── chalicelib
│ ├── common
│ │ └── common.py
│ └── function
│ ├── get_device_api.py
│ └── put_device_api.py
└── requirements.txt
- ↓importするときはこんな感じ
from chalice import Chalice
from chalicelib.function import get_device_api, put_device__api
from chalicelib.common import common
app = Chalice(app_name = 'helloworld')
@app.route('/device', methods=['GET'])
def get_device():
res = get_device_api.get_device()
return res
@app.route('/device', methods=['PUT'])
def put_device():
res = put_device_api.put_device()
return res
デプロイ時の環境設定方法
- .chalice/config.jsonから、デプロイする環境ごとにアプリ内で使用したい環境変数を設定することが可能
- stages に記載するステージ名は自由に決められます(stg1 とか stg2 でもよい)
{
"version": "2.0",
"app_name": "demandsrv-api",
"stages": {
"dev": {
"api_gateway_stage": "api-dev",
"lambda_functions": {
"api_handler": {
"environment_variables": {
"HOST_NAME": "***.***.jp",
"REGION_NAME": "ap-northeast-1",
"SECRET_NAME": "arn:aws:******"
}
}
}
},
"stg": {
"api_gateway_stage": "api-stg",
"lambda_functions": {
"api_handler": {
"environment_variables": {
"HOST_NAME": "***.***.jp",
"REGION_NAME": "ap-northeast-1",
"SECRET_NAME": "arn:aws:******"
}
}
}
},
"prod": {
"api_gateway_stage": "api-prod",
"lambda_functions": {
"api_handler": {
"environment_variables": {
"HOST_NAME": "***.***.jp",
"REGION_NAME": "ap-northeast-1",
"SECRET_NAME": "arn:aws:******"
}
}
}
}
}
}
- 実際にデプロイするときは、↓のようにoptionをつける
$ chalice local --stage dev
@app.routeについて
- @app.route()デコレータ直下にあるメソッドが、このパスのリクエストに対するエントリポイントとなる(Flask?)
- ()内の引数に色々設定が可能
- 例えば以下は、GETメソッドのdevicesAPIにcorsの許可設定とapiKey設定をしています
@app.route('/devices', methods=['GET'], cors=True, api_key_required=True)
- 注意:api_key_required=True とすることでapiキー必須になるのですが、肝心のAPIキーや使用量プランは手動で作って紐づける必要があります。なので0から環境構築するときはその辺の設定が必要
- 一度設定してしまえばそれ以降は設定不要。
権限周りの注意点
- Chaliceはデプロイを実行するIAMユーザの権限を使って各種サービスにアクセスする権限を付与します。
- 従って、IAMユーザーにはIAM ロールを作成・編集する権限が必要なので、客先アカウントなどでの運用には注意が必要(IAMポリシーとかロールとかの権限付与したくないという顧客の場合は、、残念😿)
- boto3 の Client class を使うか、 Resource class を使うかによって、付与される権限が異なる
- 個人的にResource classの方が圧倒的に使いやすいんですが、chaliceはデプロイするときにClient classの API を読んでいるかどうかを解析して自動で権限の付与を行なっているようです。
参考:https://michimani.net/post/aws-about-auto-generate-iam-policy-in-chalice/ - なので、Resource classを使う場合は、.chalice/config.jsonを以下のように設定して、自前のポリシーを設定する必要があります
- 個人的にResource classの方が圧倒的に使いやすいんですが、chaliceはデプロイするときにClient classの API を読んでいるかどうかを解析して自動で権限の付与を行なっているようです。
{
"version": "2.0",
"app_name": "chalice-sample",
"stages": {
"dev": {
"api_gateway_stage": "api",
"autogen_policy": false,
"iam_policy_file": "custom-policy.json"
}
}
}
- .chalice/custom-policy.jsonを作る(以下参考)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:Query",
"dynamodb:Scan"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
所感
- 一つの関数としてパッケージ化されてデプロイされるので、ファイルがでかいとコンソール上で中身を見れない
- cloudwatch logsもAPIごとに分けて作成されないので、全てのAPIが一つのログストリームに出力される
- APIとしての用途以外の関数(アラートとかスケジューリング用)をデプロイするというようなことができない(調べた限りでは無理そう)
- 自由度高めな構成で使いたい場合にはSAMとかのほうが良さそう