ChaliceアプリケーションをCDKでデプロイする方法を記します。
はじめに
おはよう。@bioerrorlogです。
先日、AWS ChaliceをCDKでデプロイする方法を紹介する記事がAWSの公式ブログにポストされました。
私はまだChaliceを触ったことがありませんでしたので、この記事を参考にChaliceアプリケーションをCDKでデプロイしてみます。
なお、本記事のコードはこちらにまとめています。
AWS Chaliceとは
Chaliceは、サーバレスアプリケーションのフレームワークです。
Chaliceを使用することで、API GatewayとLambdaを使用するアプリをすぐにデプロイすることができます。
以下、Chaliceについて参考になりそうな資料:
作業環境
作業はUbuntu上のCloud9で行いました。
各バージョンは以下の通りです。
$ lsb_release -d Description: Ubuntu 18.04.4 LTS $ python --version Python 3.7.5 # 後述のように、Python3.6以下だとエラーが発生するので注意 $ cdk --version 1.31.0 (build 8f3ac79) $ chalice --version chalice 1.13.1, python 3.7.5, linux 4.15.0-1065-aws $ pip show boto3 Name: boto3 Version: 1.12.39
実行手順
前準備: Python3.7のインストール
まず、前準備としてPython3.7をインストールします。
Python3.6以前のバージョンだと、cdk synth
時にcdk-chalice
パッケージで以下のようなエラーが発生してしまうためです*1。
RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII as encoding for the environment. Consult https://click.palletsprojects.com/python3/ for mitigation steps. This system supports the C.UTF-8 locale which is recommended. You might be able to resolve your issue by exporting the following environment variables: export LC_ALL=C.UTF-8 export LANG=C.UTF-8
そしてこちら、単純にエラーメッセージに示される解決策 export LC_ALL=C.UTF-8
と export LANG=C.UTF-8
を実行しても問題は解決しませんでした。
このエラーは、Python3.7をインストールすることで解消します。
以下、Python3.7のインストールと、それに伴い必要となるパッケージをインストールする手順です。
# Python3.7 インストール sudo apt update sudo apt install python3.7 # python3.7-venvのインストール sudo apt install python3.7-venv
前準備は以上です。
Chaliceプロジェクト作成
それではまず、以下のコマンドでChaliceプロジェクトを作成していきます。
# 前準備: CDKのインストール npm install -g aws-cdk # ワークスペースの作成 mkdir users-service cd users-service # Python仮想環境の作成とアクティブ化 python3.7 -m venv .venv # Python3.7で実行する source .venv/bin/activate # Chaliceインストールとプロジェクトの作成 pip install chalice chalice new-project web-api cd web-api
作成したChaliceプロジェクトのディレクトリ構造は以下の通りです。
$ tree -a web-api ├── app.py ├── .chalice │ └── config.json ├── .gitignore └── requirements.txt 1 directory, 4 files
あとは、とりあえず必要なツールをrequirements.txt
に放り込んでインストールすれば、プロジェクトの準備はおしまいです。
echo "boto3" > requirements.txt echo "chalice" >> requirements.txt pip install -r requirements.txt
Chalice appコード
つぎは、Chaliceのコードを書いていきます。
Chaliceプロジェクトの中に作成されたapp.py
に、以下のPythonコードを書き込みます。
import os import boto3 from chalice import Chalice # アプリケーションオブジェクト作成 app = Chalice(app_name='web-api') # DynamoDBの取得 dynamodb = boto3.resource('dynamodb') dynamodb_table = dynamodb.Table(os.environ['DYNAMODB_TABLE_NAME']) # 以下、エンドポイントの設定 # @app.routeに渡した情報がAPI Gatewayに設定される @app.route('/users', methods=['POST']) def create_user(): user = app.current_request.json_body dynamodb_table.put_item(Item=user) return user @app.route('/users/{username}', methods=['GET']) def get_user(username): response = dynamodb_table.get_item(Key={'username': username}) return response['Item'] @app.route('/users/{username}', methods=['DELETE']) def delete_user(username): dynamodb_table.delete_item(Key={'username': username})
DynamoDBテーブルへcreate, get, deleteするAPIが定義されました。
デコレータ@app.route
に渡した情報が、API Gatewayに設定されるという仕組みです。
次は、このChaliceアプリケーションで利用されるAWSリソースをCDKでデプロイします。
CDKプロジェクトの作成
まずはCDKプロジェクトを作成し、下準備を済ませます。
# ワークスペースの作成 cd .. mkdir infra cd infra # CDKプロジェクトの作成 cdk init --language python --generate-only # デフォルトのinfraファイルは削除して、後から新しく作成する rm -rf infra # Construct libraryを作るわけではないのでsetup.pyは不要 rm setup.py # 必要なツールをrequirements.txtに放り込んでインストール echo "aws-cdk.aws-dynamodb" > requirements.txt echo "aws-cdk.core" >> requirements.txt echo "cdk-chalice==0.6.0" >> requirements.txt # 現時点でのlatest version: 0.7.0ではインストールに失敗した pip install -r requirements.txt # 新規のstacksパッケージを作成 mkdir stacks touch stacks/__init__.py touch stacks/web_api.py
これで環境の下準備が整ったので、CDKコードを書いていきます。
CDKコード
まずは、先ほど作成したstacks/web_api.py
にCDK Stackを定義していきます。
import os from aws_cdk import ( aws_dynamodb as dynamodb, aws_iam as iam, core as cdk ) from cdk_chalice import Chalice class WebApi(cdk.Stack): def __init__(self, scope: cdk.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # DynamoDBの作成 partition_key = dynamodb.Attribute(name='username', type=dynamodb.AttributeType.STRING) self.dynamodb_table = dynamodb.Table( self, 'UsersTable', partition_key=partition_key, removal_policy=cdk.RemovalPolicy.DESTROY) cdk.CfnOutput(self, 'UsersTableName', value=self.dynamodb_table.table_name) # LambdaがDynamoDBにアクセスするためのIAMロールを作成 lambda_service_principal = iam.ServicePrincipal('lambda.amazonaws.com') self.api_handler_iam_role = iam.Role(self, 'ApiHandlerLambdaRole', assumed_by=lambda_service_principal) self.dynamodb_table.grant_read_write_data(self.api_handler_iam_role) # web_api_source_dirはChaliceアプリケーションソースコードへのパス # ソースコードはChaliceによってパッケージングされ、 # SAMテンプレートの作成とLambdaデプロイのためのZIP化が行われる web_api_source_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, 'web-api') chalice_stage_config = self._create_chalice_stage_config() # Chaliceの作成 self.chalice = Chalice( self, 'WebApi', source_dir=web_api_source_dir, stage_config=chalice_stage_config) # Chalice Stagesを定義 def _create_chalice_stage_config(self): chalice_stage_config = { 'api_gateway_stage': 'v1', 'lambda_functions': { 'api_handler': { 'manage_iam_role': False, 'iam_role_arn': self.api_handler_iam_role.role_arn, 'environment_variables': { 'DYNAMODB_TABLE_NAME': self.dynamodb_table.table_name }, 'lambda_memory_size': 128, 'lambda_timeout': 10 } } } return chalice_stage_config
これで、DynamoDBとChaliceアプリケーションを作成するCDK Stack WebApi
が定義されました。
次は、CDK StackをもとにCDKアプリケーションをinfra/app.py
に定義します。
import os from aws_cdk import core as cdk from stacks.web_api import WebApi app = cdk.App() # Stackの環境を定義 # 'CDK_DEFAULT_ACCOUNT'と'CDK_DEFAULT_REGION'からは現在のデフォルトが読み込まれる dev_env = cdk.Environment( account=os.environ['CDK_DEFAULT_ACCOUNT'], region=os.environ['CDK_DEFAULT_REGION']) # 本番環境はアカウントidとregionを指定 prod_eu_west_1_env = cdk.Environment(account='123456789012', region='eu-west-1') prod_us_east_1_env = cdk.Environment(account='123456789012', region='us-east-1') # Stackを定義 WebApi(app, 'WebApiDev', env=dev_env) WebApi(app, 'WebApiProdEuWest1', env=prod_eu_west_1_env) WebApi(app, 'WebApiProdUsEast1', env=prod_us_east_1_env) app.synth()
これでCDKコードは完成です。
あとは、このCDKコードをデプロイしていきます。
CDKデプロイ
さっそく、CDKをデプロイしていきます。
# CDKテンプレート生成 cdk synth # CDKデプロイ cdk deploy WebApiDev
デプロイが成功すると、次のようなOutputs
が返ってきます。
Outputs: WebApiDev.UsersTableName = WebApiDev-UsersTable9725E9C8-1HVYW061T3POO WebApiDev.APIHandlerArn = arn:aws:lambda:ap-northeast-1:123456789012:function:WebApiDev-APIHandler-10LR6FLOB1SGV WebApiDev.APIHandlerName = WebApiDev-APIHandler-10LR6FLOB1SGV WebApiDev.RestAPIId = 0oexyzw39c WebApiDev.EndpointURL = https://0oexyzw39c.execute-api.ap-northeast-1.amazonaws.com/v1/
では、Outputs
に表示されたEndpointURL
+ /users
に対してPOSTし、動作を確認してみます。
curl \ -H "Content-Type: application/json" \ -X POST \ -d '{"username":"bioerrorlog", "email":"bioerrorlog@example.com"}' \ https://0oexyzw39c.execute-api.ap-northeast-1.amazonaws.com/v1/users
次のようにレスポンスが帰ってくれば、アプリケーションのデプロイは成功です。
{"username":"bioerrorlog","email":"bioerrorlog@example.com"}
DynamoDBにも、ちゃんとデータが格納されていることが確認できました。
リソースの削除
作成したリソースを削除するのは、ごく簡単です。
以下のコマンドを実行します。
cdk destroy WebApiDev
成功すれば、今回CDKで作成したリソースが削除されます。
おわりに
今回は、CDKを用いてChaliceアプリケーションをデプロイしました。
Python3.6以下ではうまく機能しないなど躓きどころはありましたが、使いこなせればサーバレスアプリケーションの作成にかかる手間が削減できそうです。
とはいうものの、私はまだSAMやServerless Frameworkなどメジャーなサーバレスフレームワークすらまだよく知らないので、そちらの方も手を出していこうと思っています。
[関連記事]
参考
Deploying AWS Chalice application using AWS Cloud Development Kit | AWS Developer Blog
GitHub - aws/chalice: Python Serverless Microframework for AWS
GitHub - alexpulver/cdk-chalice: AWS CDK construct for AWS Chalice