ChaliceをCDKでデプロイする

PythonのサーバーレスアプリケーションフレームワークのChaliceではCDKのサポートもおこなわれています。CDKと一緒に使用することでアプリケーションに必要な他のリソースも同時に管理することが可能になります。
2021.10.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Chaliceについて

Chaliceは軽く説明すると、APIGatewyとLambdaを使用してアプリケーションを作るフレームワークです。Flaskのようにデコレータで書くことができ、あまりインフラレイヤーのことを意識せずに開発ができます。

Chaliceについては以下の記事を読んでみてください。

今回は公式のチュートリアルをもとにデプロイしてみます。

セットアップ

必要なツール、パッケージのインストール

npmでCDKのインストールが必要です。

CDKのインストール

$ npm install -g aws-cdk

Chalice用のCDKパッケージをインストールすると便利です。

Chaliceのインストール

pip3 install chalice
pip3 install "chalice[cdk]"

プロジェクトを作成する

ChaliceではCDK用のボイラープレートが用意されています。 プロジェクトの作成時に選択可能です。

プロジェクトを作成

$  chalice new-project


   ___  _  _    _    _     ___  ___  ___
  / __|| || |  /_\  | |   |_ _|/ __|| __|
 | (__ | __ | / _ \ | |__  | || (__ | _|
  \___||_||_|/_/ \_\|____||___|\___||___|


The python serverless microframework for AWS allows
you to quickly create and deploy applications using
Amazon API Gateway and AWS Lambda.

Please enter the project name
[?] Enter the project name: cdk-example
[?] Select your project type: [CDK] Rest API with a DynamoDB table
   REST API
   S3 Event Handler
   Lambda Functions only
   Legacy REST API Template
 > [CDK] Rest API with a DynamoDB table

Your project has been generated in ./cdk-example

プロジェクトの中身は以下のようになっています

ディレクトリ構造

.
├── README.rst
├── infrastructure
│   ├── app.py
│   ├── cdk.json
│   ├── requirements.txt
│   └── stacks
│       ├── __init__.py
│       └── chaliceapp.py
├── requirements.txt
└── runtime
    ├── app.py
    └── requirements.txt

infrastructureにはCDKのためのコードが入っています。 runtimeにはアプリケーション本体のコードが入っています。

最後にこのプロジェクトに必要なパッケージをインストールすれば準備完了です。

依存関係のインストール

$ ls
README.rst              infrastructure          requirements.txt        runtime
$ pip install -r requirements.txt

プロジェクトのルートディレクトリのrequirements.txtruntimeinfrastructurerequirements.txtをインポートしているので、これだけをインストールすれば大丈夫です。

requirements.txt

-r infrastructure/requirements.txt
-r runtime/requirements.txt

デプロイする

infrastructureに移動します。 その後、CDKのブーとスラップを作成し、デプロイします。 自分の場合は.aws/configにプロファイルを設定しているので、環境変数でプロファイルを指定してから作業します。 途中でデプロイするかの確認が出てくるのでyを入力するとデプロイできます。

true

$ export AWS_PROFILE=XXXXX
$ cd infrastructure
$ cdk bootstrap
Creating deployment package.
 ⏳  Bootstrapping environment aws://XXXXXXXX/ap-northeast-1...
 ✅  Environment aws://XXXXXXXX/ap-northeast-1 bootstrapped (no changes).
$ cdk deploy
Creating deployment package.
Reusing existing deployment package.

----割愛-----

 ✅  cdk-example

Outputs:
cdk-example.APIHandlerArn = XXXX
cdk-example.APIHandlerName = cdk-example-APIHandler-xxxxxx
cdk-example.AppTableName = cdk-example-AppTablexxxxxxx-xxxxxxxxx
cdk-example.EndpointURL = https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/api/
cdk-example.RestAPIId = xxxxxxx

ここではCloudFormationのアウトプットが出力されています。 EndpointURLがAPIGatewayのエンドポイントになります。

確認する

Webブラウザで確認

マネージドコンソールから確認します。 CloudFormationのスタックが作成されていることが確認できました。

アプリケーションの動作を確認

ボイラープレートに含まれているサンプルコードでは以下の二つのメソッドが定義されています。

  • POST: /users
  • GET: /users/{username}

ユーザー名をJSONで登録して、パスパラメータに入れるとその情報が返ってくるといった流れです。 サーバーはAPIGatewayとLambdaで構成されています。

先ほどデプロイ時に出力されたエンドポイントURLにアクセスしてみます。

APIを実行してみる

$ curl -X POST -H "Content-Type: application/json" -d '{"username":"foo"}' httpscurl -X POST -H "Content-Type: application/json" -d '{"username":"foo"}' https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/api/users
{}
$ curl https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/api/users/fooo
{"username":"foo"}

正常に動作しています。

CDKのコードを見てみる

infrastructure/stacks/chaliceapp.py

import os

from aws_cdk import (
    aws_dynamodb as dynamodb,
    core as cdk
)
from chalice.cdk import Chalice


RUNTIME_SOURCE_DIR = os.path.join(
    os.path.dirname(os.path.dirname(__file__)), os.pardir, 'runtime')


class ChaliceApp(cdk.Stack):

    def __init__(self, scope, id, **kwargs):
        super().__init__(scope, id, **kwargs)
        self.dynamodb_table = self._create_ddb_table()
        self.chalice = Chalice(
            self, 'ChaliceApp', source_dir=RUNTIME_SOURCE_DIR,
            stage_config={
                'environment_variables': {
                    'APP_TABLE_NAME': self.dynamodb_table.table_name
                }
            }
        )
        self.dynamodb_table.grant_read_write_data(
            self.chalice.get_role('DefaultRole')
        )

    def _create_ddb_table(self):
        dynamodb_table = dynamodb.Table(
            self, 'AppTable',
            partition_key=dynamodb.Attribute(
                name='PK', type=dynamodb.AttributeType.STRING),
            sort_key=dynamodb.Attribute(
                name='SK', type=dynamodb.AttributeType.STRING
            ),
            removal_policy=cdk.RemovalPolicy.DESTROY)
        cdk.CfnOutput(self, 'AppTableName',
                      value=dynamodb_table.table_name)
        return dynamodb_table

ChaliceにはCDK用のリソースクラスが用意されていて、そこで様々な設定を行うことができます。 このアプリケーションではChaliceとDynamoDBの二つが定義されています。 ちなみにChaliceの細かい設定はstate_configで設定できます。

Chaliceでは内部でSAMを利用しているようで、ChaliceのリソースにCDKからアクセスする際はget_resouceメソッドを使って、aws_cdk.cdk.CfnResourceを取得し、そこからアクセスする必要があるので注意が必要です。

感想

CDKを利用してデプロイすることができました。 Lambda以外のサービスも使いたい場合に管理を一元化できて便利だとおもいます。