ハカセノオト

moon indicating dark mode
sun indicating light mode

Chalice を CDK でデプロイする際に Stage ごとの Lambda の設定ができなくて困った話

December 21, 2022

先日、Chalice と CDK を使って開発を行ないました。 本記事では、Chalice とは何かという話を簡単に記載して、実際に開発する上で躓いた箇所とその解決策を記載します。

Chalice とは

AWS Chalice とは、AWS によって開発されている AWS 上でサーバーレスアプリケーションを作成するためのオープンソース Python 製フレームワークです。

いくつか思いついた特徴などを箇条書きしてみます。

  • AWS Lambda と API Gateway が利用される
  • インフラのことをあまり意識せずにアプリケーションの開発に集中できるため、開発期間を短縮できる
    • 実際には、Chalice が裏で何を行なっているかや、利用されているインフラを理解していないと、難しい部分はある
  • コマンドラインインターフェースから簡単にビルドやデプロイができる
  • Terraform や CDK との統合をサポートしている

やりたかったこと

CDK を利用してデプロイする際に、ステージごとの AWS Lambda 関数のメモリサイズやタイムアウトを設定をしようとしました。

CDK でデプロイする際の方法は、以下のドキュメントに記載があります。

https://aws.github.io/chalice/tutorials/cdk.html

stage_config を指定することで、./runtime/.chalice/config.json に記載されている設定と統合されると記載があります。

class ChaliceApp(cdk.Stack):
def __init__(self, scope: cdk.Construct, id: str, **kwargs) -> None:
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')
)

stage_config (dict) – Chalice stage configuration. The configuration object should have the same structure as Chalice JSON stage configuration.

ref: chalice.cdk api doc

困ったこと

Chalice では API ハンドラー以外にも Cloudwatch Events によるスケジュールされた非同期処理を作成できます。

作成した特定の Lambda 関数のタイムアウトとメモリサイズを指定しようとしましたが、以下の設定では反映されませんでした。

アプリケーションのコードのサンプルは下記です。

@app.schedule(Cron(0, 16, "L", "*", "?", "*"))
def foo(event, context):
print("hello world")

CDK のコードでは下記のように設定しました。

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
},
"lambda_functions": {
"foo": {
"lambda_timeout": 600,
"lambda_memory_size": 256,
"environment_variables": {"HELLO": "world"},
}
},
},
)
self.dynamodb_table.grant_read_write_data(self.chalice.get_role("DefaultRole"))

デプロイ後に作成された Lambda を確認すると、設定値ではなくデフォルト値 (timeout: 60 sec, memory size: 128 MB) になっていました。

このあたりは、以下の issue にも記載しました。

Lambda Specific Configuration does not work with CDK · Issue #1998 · aws/chalice

解決方法

ソースコードを確認したところ、どうやら CDK でデプロイする際には、このステージ毎の Lambda 設定が読み込まれていないようでした。

https://github.com/aws/chalice/blob/f64bd82a46abbc80fd5b325de503e420884ed8cc/chalice/config.py#L197-L209

CDK 側で設定できないので、CDK でデプロイされるステージ名で ./runtime/.chalice/config.json にステージ毎の Lambda 設定を書けば、設定がデプロイ時に反映されます。

例えば、CDK 側で cdkdemo のアプリ名でデプロイされる場合、下記のようにします。

{
"version": "2.0",
"app_name": "cdkdemo",
"stages": {
"cdkdemo": {
"lambda_functions": {
"foo": {
"lambda_timeout": 200,
"lambda_memory_size": 256,
"environment_variables": {"HELLO": "world2"}
}
}
}
}
}

上記、ステージ毎に Lambda の設定を変える必要がない場合は、./runtime/.chalice/config.json に下記のように記載しておけば、全てのステージに対して設定が適用されます。従って、CDK 側のコードでは Lambda 関数毎に設定することが想定されていない可能性も考えられます (現時点で issue に回答をもらえていないので、真相は不明)。

{
"version": "2.0",
"app_name": "cdkdemo",
"lambda_functions": {
"foo": {
"lambda_timeout": 200,
"lambda_memory_size": 256
}
}
}

その他コメント

  • Chalice 便利ですが、RDS などの他の AWS リソースと連携しようと思った時に IAM Policy など設定する必要があって、Chalice が内部で何をやっているか分かりづらくて、設定で躓きました
  • Chalice の commit 履歴 見ると、最近あまり更新されていないので、開発はそんなに活発でなさそうです (2022-12-18 現在、last commit は 2022-09-02)
  • サクッと Python でサーバーレスなアプリケーションを開発したい時には Chalice はオススメできます

hnishi

hnishi のブログ

ソフトウェアエンジニアです。
誰かの役に立つかもしれないと思って、調べたこと、勉強したこと、躓いた箇所などを記事にしています。
問い合わせはこちらからお願いします。