AWS CDK で Lambda 関数 (Python) の Snapstart を設定してみた

AWS CDK で Lambda 関数 (Python) の Snapstart を設定してみた

Clock Icon2024.12.13

こんにちは、製造ビジネステクノロジー部の若槻です。

先月に AWS Lambda で Python および .Net ランタイムの Lambda 関数でも SnapStart がサポートされるアップデートがありました。

https://dev.classmethod.jp/articles/snap-start-support-python-and-dotnet/

これにより Lambda の次のマネージドランタイムで SnapStart が利用可能になり、レイテンシの短縮を図ることができるようになりました。

  • Java 11 以降
  • Python 3.12 以降
  • .NET 8.0 以降

そして AWS CDK でも v2.167.0 から L2 Construct で同ランタイムでの SnapStart の設定が可能となりました。

lambda: add supportsSnapStart config to dotnet8 and python 3.12 (#32112) (53f4713)

今回は、実際に AWS CDK で Lambda 関数 (Python) の Snapstart を設定してみました。

やってみた

CDK パッケージのアップデート

AWS CDK モジュールを v2.167.0 以上にアップデートします。

npm i -D aws-cdk-lib@latest aws-cdk@latest @aws-cdk/aws-lambda-python-alpha@latest

@aws-cdk/aws-lambda-python-alpha は Python ランタイムの Lambda 関数を実装するのに便利な Alpha モジュールです。

Lambda 関数の CDK 実装

AWS CDK で Lambda 関数を実装します。

Lambda 関数のハンドラーとなる Python ファイルを作成します。

src/lambda/hello/index.py
def handler():
    return {
        'statusCode': 200,
        'body': 'Hello, CDK!'
    }

Python スクリプトを Lambda 関数として実装します。snapStart プロパティが Python ランタイムの Function クラスでも利用可能となっており、ON_PUBLISHED_VERSIONS を指定することでデプロイ時点で公開された関数バージョンに対して SnapStart を有効化できます。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { PythonFunction } from '@aws-cdk/aws-lambda-python-alpha';
import { Construct } from 'constructs';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    new PythonFunction(this, 'HelloFunction', {
      runtime: lambda.Runtime.PYTHON_3_13,
      entry: 'src/lambda/hello',
      handler: 'handler',
      snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, // SnapStart を有効化
    });
  }
}

上記実装を CDK デプロイして Lambda 関数を作成します。

作成された Lambda 関数を確認すると、SnapStart が有効化されていることが確認できました。

ちなみに SnapStart では過去の関数バージョンやエイリアスに対しても有効化できますが、現状の CDK の L2 Construct ではそれらに対しては有効化できません。しかし Lambda 関数をコードのアップデート含めて CDK で管理している場合に関数バージョンやエイリアスを使うケースは稀であると思われるため、この仕様は大きな問題にはならないかと思います。むしろこれにより未使用の関数バージョンで不用意に SnapStart が有効化されたままとなることを避けられるのではないかと思います。

SnapStart サポート外の設定をした場合

SnapStart はサポート対象にいくつかの制限があり、CDK 実装上でそれらの制限を超える設定をした場合にはバリデーションエラーが発生するようになっています。

ランタイムに Python 3.12 未満を指定

SnapStart がサポートされているのは Python ランタイムの場合は 3.12 以降です。

それ未満のバージョンを指定してみます。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { PythonFunction } from '@aws-cdk/aws-lambda-python-alpha';
import { Construct } from 'constructs';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    new PythonFunction(this, 'HelloFunction', {
      runtime: lambda.Runtime.PYTHON_3_11, // SnapStart サポート外のランタイムを指定
      entry: 'src/lambda/hello',
      handler: 'handler',
      snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS,
    });
  }
}

CDK Synth の実行が SnapStart currently not supported by runtime python3.11 というバリデーションエラーとなります。

$ npx cdk synth Main
[+] Building 2.6s (6/6) FINISHED                                                                                                  docker:rancher-desktop
 => [internal] load .dockerignore                                                                                                                   0.0s
 => => transferring context: 2B                                                                                                                     0.0s
 => [internal] load build definition from Dockerfile                                                                                                0.0s
 => => transferring dockerfile: 1.32kB                                                                                                              0.0s
 => [internal] load metadata for public.ecr.aws/sam/build-python3.11:latest                                                                         2.6s
 => [1/2] FROM public.ecr.aws/sam/build-python3.11@sha256:dd58cefe5c40306ff292861b5ff36f920a37a4424ceb56e4288aa387aa761334                          0.0s
 => CACHED [2/2] RUN     python -m venv /usr/app/venv &&     mkdir /tmp/pip-cache &&     chmod -R 777 /tmp/pip-cache &&     pip install --upgrade   0.0s
 => exporting to image                                                                                                                              0.0s
 => => exporting layers                                                                                                                             0.0s
 => => writing image sha256:01200a10f90709e2c5acd6f7b484763712dcef19185c34f0331739d89febdbbb                                                        0.0s
 => => naming to docker.io/library/cdk-f050a7c94a31348de7eacbbabf5aada3ef388d87dcd5d98554ad9f5dee4cb9fe                                             0.0s
/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/lib/main-stack.ts:10
    new PythonFunction(this, 'HelloFunction', {
    ^
ValidationError: SnapStart currently not supported by runtime python3.11
    at path [Main/HelloFunction] in @aws-cdk/aws-lambda-python-alpha.PythonFunction

    at new MainStack (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/lib/main-stack.ts:10:5)
    at Object.<anonymous> (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/bin/cdk_sample_app.ts:7:1)
    at Module._compile (node:internal/modules/cjs/loader:1241:14)
    at Module.m._compile (/Users/wakatsuki.ryuta/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/wakatsuki.ryuta/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Function.Module._load (node:internal/modules/cjs/loader:938:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12)
    at phase4 (/Users/wakatsuki.ryuta/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/src/bin.ts:649:14)
Subprocess exited with error 1

512 MB を超える一時ストレージを指定した場合

さらに SnapStart は 512 MB を超える一時ストレージをサポートしていません。

試しに 1GB の一時ストレージを指定してみます。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { PythonFunction } from '@aws-cdk/aws-lambda-python-alpha';
import { Construct } from 'constructs';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    new PythonFunction(this, 'HelloFunction', {
      runtime: lambda.Runtime.PYTHON_3_13,
      entry: 'src/lambda/hello',
      handler: 'handler',
      snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS,
      ephemeralStorageSize: cdk.Size.gibibytes(1), // SnapStart でサポートされていないサイズを指定
    });
  }
}

CDK Synth の実行が SnapStart is currently not supported using more than 512 MiB Ephemeral Storage というバリデーションエラーとなります。

$ npx cdk synth Main
[+] Building 2.7s (6/6) FINISHED                                                                                                  docker:rancher-desktop
 => [internal] load build definition from Dockerfile                                                                                                0.0s
 => => transferring dockerfile: 1.32kB                                                                                                              0.0s
 => [internal] load .dockerignore                                                                                                                   0.0s
 => => transferring context: 2B                                                                                                                     0.0s
 => [internal] load metadata for public.ecr.aws/sam/build-python3.13:latest                                                                         2.6s
 => [1/2] FROM public.ecr.aws/sam/build-python3.13@sha256:c63f213cf30674c89e9bc1e4115ccc3306b0ac36e11f520ebb6eed32e82c3ddb                          0.0s
 => CACHED [2/2] RUN     python -m venv /usr/app/venv &&     mkdir /tmp/pip-cache &&     chmod -R 777 /tmp/pip-cache &&     pip install --upgrade   0.0s
 => exporting to image                                                                                                                              0.0s
 => => exporting layers                                                                                                                             0.0s
 => => writing image sha256:333ca9b5c22974f11f71ccd5e29da69249064451bd3268f600d8061ad0b33bbf                                                        0.0s
 => => naming to docker.io/library/cdk-f637d873b037b331d5f62de8721764d26f3cea87179096d3ded2e704b7a4180f                                             0.0s
/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/lib/main-stack.ts:10
    new PythonFunction(this, 'HelloFunction', {
    ^
ValidationError: SnapStart is currently not supported using more than 512 MiB Ephemeral Storage
    at path [Main/HelloFunction] in @aws-cdk/aws-lambda-python-alpha.PythonFunction

    at new MainStack (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/lib/main-stack.ts:10:5)
    at Object.<anonymous> (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/bin/cdk_sample_app.ts:7:1)
    at Module._compile (node:internal/modules/cjs/loader:1241:14)
    at Module.m._compile (/Users/wakatsuki.ryuta/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/wakatsuki.ryuta/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/src/index.ts:1621:12)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Function.Module._load (node:internal/modules/cjs/loader:938:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12)
    at phase4 (/Users/wakatsuki.ryuta/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/src/bin.ts:649:14)
Subprocess exited with error 1

トラブルシュート

SnapStart はあまり関係ないですが、今回 @aws-cdk/aws-lambda-python-alpha を使用して Lambda 関数を実装する際に当初次のようなエラーが発生しました。

$  npx cdk synth Main
[+] Building 1.3s (4/4) FINISHED                                                                                                  docker:rancher-desktop
 => [internal] load build definition from Dockerfile                                                                                                0.0s
 => => transferring dockerfile: 1.32kB                                                                                                              0.0s
 => [internal] load .dockerignore                                                                                                                   0.0s
 => => transferring context: 2B                                                                                                                     0.0s
 => ERROR [internal] load metadata for public.ecr.aws/sam/build-python3.12:latest                                                                   1.2s
 => [auth] aws:: sam/build-python3.12:pull token for public.ecr.aws                                                                                 0.0s
------
 > [internal] load metadata for public.ecr.aws/sam/build-python3.12:latest:
------
Dockerfile:4
--------------------
   2 |     # passed as build arg. The default allows to do `docker build .` when testing.
   3 |     ARG IMAGE=public.ecr.aws/sam/build-python3.7
   4 | >>> FROM $IMAGE
   5 |
   6 |     ARG PIP_INDEX_URL
--------------------
ERROR: failed to solve: public.ecr.aws/sam/build-python3.12: pulling from host public.ecr.aws failed with status code [manifests latest]: 403 Forbidden
/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/aws-cdk-lib/core/lib/private/asset-staging.js:2
`).map((line,idx)=>`${idx===0?firstLine:padding}${line}`)};const reason=proc.signal!=null?`signal ${proc.signal}`:`status ${proc.status}`,command=[prog,...args.map(arg=>/[^a-z0-9_-]/i.test(arg)?JSON.stringify(arg):arg)].join(" ");throw new Error([`${prog} exited with ${reason}`,...prependLines("--> STDOUT:  ",proc.stdout)??[],...prependLines("--> STDERR:  ",proc.stderr)??[],`--> Command: ${command}`].join(`
                                                                                                                                                                                                                                            ^
Error: docker exited with status 1
--> Command: docker build -t cdk-375be3842f70a9cc0874735334b0f998a4a046e1afdc33d4028a5238225c3070 --platform "linux/amd64" --build-arg "IMAGE=public.ecr.aws/sam/build-python3.12" "/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-cdk/aws-lambda-python-alpha/lib"
    at dockerExec (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/aws-cdk-lib/core/lib/private/asset-staging.js:2:237)
    at Function.fromBuild (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/aws-cdk-lib/core/lib/bundling.js:1:4761)
    at new Bundling (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-cdk/aws-lambda-python-alpha/lib/bundling.ts:102:39)
    at Function.bundle (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-cdk/aws-lambda-python-alpha/lib/bundling.ts:61:44)
    at new PythonFunction (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/node_modules/@aws-cdk/aws-lambda-python-alpha/lib/function.ts:73:22)
    at new MainStack (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/lib/main-stack.ts:10:5)
    at Object.<anonymous> (/Users/wakatsuki.ryuta/projects/cm-rwakatsuki/cdk_sample_app/bin/cdk_sample_app.ts:7:1)
    at Module._compile (node:internal/modules/cjs/loader:1241:14)
    at Module.m._compile (/Users/wakatsuki.ryuta/.npm/_npx/1bf7c3c15bf47d04/node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
Subprocess exited with error 1

ECR の古いログイン情報が残っていたようです。次のコマンドを実行すれば解消しました。

$ docker logout public.ecr.aws
Removing login credentials for public.ecr.aws

おわりに

AWS CDK で Lambda 関数 (Python) の Snapstart を設定してみました。

私は今のところ Lambda 関数は Node.js ランタイムで実装することが多く今まで SnapStart にあまり着目して来なかったので、制限や料金体系含めていい勉強になりました。

参考

https://dev.classmethod.jp/articles/building-python-lambda-function-with-aws-cdk-typescrip/

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.