1
0

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

【AWS CDK】Pythonで動くLambdaレイヤーをCDKでデプロイする方法

Posted at

はじめに

仕事でLambdaレイヤーをCDKでデプロイする機会がありました。
その辺のナレッジが記載された記事があまりなかったので、
本記事ではLambdaレイヤーをCDKでデプロイする方法を記載します。

環境

OS:Windows 10

前提

以下がインストール済み
 CDK(ver 2.67.0)
 Docker Desktop
 yarn

CDKの言語:TypeScript
AWS CLI:デフォルトプロファイルが設定済み
Docker DesktopはCDKでのデプロイを実行するときに使います。

実装内容

Pythonで動くLambdaレイヤーと、レイヤーを使用するLambdaを実装します。
Lambdaのソースコードは以下です。
numpyライブラリのモジュールを使って、ランダムに乱数を生成するだけのシンプルな内容です。
Lambdaレイヤーには、numpyライブラリを含めて実装します。

index.py
import numpy

def handler(event, context):
    # 乱数を生成
    print(numpy.random.rand())

手順

CDKの初期化とライブラリのインストール

まず、CDKの作業ディレクトリに移動し、以下のコマンドを実行してCDKプロジェクトを作成します。

$ cdk init --lang typescript

次に、以下のパッケージをインストールします。
バージョンは2.83.1-alpha.0を指定します。
(これ以降のバージョンではエラーが出てデプロイに失敗します)

$ yarn add @aws-cdk/aws-lambda-python-alpha@^2.83.1-alpha.0

実装

ここからはコーディングに入ります。
まず、作業ディレクトリ直下にlambdaフォルダを作成し、
lambdaフォルダ内にtestフォルダとlayerフォルダを作成します。
 testフォルダ:Lambda関数を実行するコードを配置するフォルダ
 layerフォルダ:Lambdaレイヤーのデプロイに必要なファイルを配置するフォルダ

作業ディレクトリ/
├ bin/
├ lib/
├ lambda/
   ├ test/
   ├ layer

testディレクトリには上記に記載したLambda関数のファイルを配置します。
layerフォルダにはrequirements.txtを作成します。

作業ディレクトリ/
├ bin/
├ lib/
├ lambda/
   ├ test/
      └ index.py
   ├ layer
      └ requirements.txt

そして、requirements.txtにnumpyを記載します。

requirements.txt
numpy

libディレクトリにあるファイルにコードを追記していきます。
以下は、Lambdaレイヤーとレイヤーを利用するLambdaを実装するCDKスタックのコードです。

lambdalayercdk-stack.ts
import { PythonLayerVersion } from '@aws-cdk/aws-lambda-python-alpha';
import { Stack,StackProps } from 'aws-cdk-lib';
import { ManagedPolicy, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';

import { AssetCode, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

export class LambdalayercdkStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const lambdaParams = {
      functionName: "lambdaFunction",
      lambdaRoleName: "lambdaRole",
      layerName: "lambdaLayer",
      codePath: "lambda/test",
    };

    const lambdaRole: Role = new Role(this, lambdaParams.lambdaRoleName, {
      roleName: lambdaParams.lambdaRoleName,
      assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
      managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")]
    });

    const lambdaLayer: PythonLayerVersion = new PythonLayerVersion(this, lambdaParams.layerName, {
      layerVersionName: lambdaParams.layerName,
      entry: "lambda/layer",
      compatibleRuntimes: [Runtime.PYTHON_3_9],
    });

    const lambdafunc: Function = new Function(this, lambdaParams.functionName, {
      functionName: lambdaParams.functionName,
      runtime: Runtime.PYTHON_3_9,
      code: AssetCode.fromAsset(lambdaParams.codePath),
      role: lambdaRole,
      handler: "index.handler",
      layers: [lambdaLayer],
    });
  }
}

実装する各リソースを以下に解説します。
lambdaRoleは、レイヤーを使うLambdaに付与するIAMロールです。

lambdalayercdk-stack.ts
const lambdaRole: Role = new Role(this, lambdaParams.lambdaRoleName, {
      roleName: lambdaParams.lambdaRoleName,
      assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
      managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")]
});

lambdaLayerが、本記事のメインであるLambdaレイヤーです。
PythonLayerVersionは、Pythonで動くLambdaレイヤーのクラスになります。
(インストールしたaws-lambda-python-alphaライブラリに含まれます)

 entryプロパティに、requirements.txtを配置したディレクトリのパスを記載します(パスは、作業ディレクトリを起点とする相対パス)。

lambdalayercdk-stack.ts
const lambdaLayer: PythonLayerVersion = new PythonLayerVersion(this, lambdaParams.layerName, {
      layerVersionName: lambdaParams.layerName,
      entry: "lambda/layer",
      compatibleRuntimes: [Runtime.PYTHON_3_9],
});

lambdafuncがLambda関数になります。
layersプロパティに、↑で宣言したlambdaLayerを指定します。
layersプロパティは型が配列なので、配列で指定します。

lambdalayercdk-stack.ts
const lambdafunc: Function = new Function(this, lambdaParams.functionName, {
      functionName: lambdaParams.functionName,
      runtime: Runtime.PYTHON_3_9,
      code: AssetCode.fromAsset(lambdaParams.codePath),
      role: lambdaRole,
      handler: "index.handler",
      layers: [lambdaLayer],
});

デプロイ

コードが実装出来たらデプロイします。
カレントディレクトリを作業ディレクトリにした状態で以下のコマンドを実行します。

$ cdk deploy

コマンド実行途中でコンテナイメージが作られていますが、おそらくLambdaレイヤーのイメージが作られており、イメージからレイヤーがデプロイされていると思います。

=> => extracting sha256:d496c62c3cdac34de0a03ca34f6f2835465f8ec740126892e424e66aa1e9b505           27.9s 
 => => extracting sha256:9dd68721861bba63ce3267631073135ae42b5d6596b4f490758403399f2d130c            0.0s 
 => => extracting sha256:c931f6dd56e3be9958949c65cd36fc4a27397b0f31c955e0af5102d1957351b0            0.0s 
 => [2/2] RUN     python -m venv /usr/app/venv &&     mkdir /tmp/pip-cache &&     chmod -R 777 /t  193.9s 
 => exporting to image                                                                               3.2s 
 => => exporting layers                                                                              2.8s 
 => => writing image sha256:1dc7929e19813b04cf2d3ab6e80478c5b17371733138c37f31d7ada3e54b5973         0.0s 
 => => naming to docker.io/library/cdk-a3cf09e124d1012c8446b8fbc9d3fb0af39864821bd92922a198a755b57c  0.0s 

コマンド実行後、以下のメッセージが表示されればデプロイ成功です。

✅  LambdalayercdkStack

✨  Deployment time: 50.91s

デプロイ実行時、エラーが出て失敗するケースがいくつかあります。
以下に、ケース別トラブルシュートを記載します。

トラブルシュート①
cdk deploy実行時、以下のエラーが出る場合
Docker Desktopが起動していないことが原因です。Docker Desktopを起動しましょう。

error during connect: This error may indicate that the docker daemon is not running.: Post "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/build?buildargs=%7B%22IMAGE%22%3A%22public.ecr.aws%2Fsam%2Fbuild-python3.9%22%7D&cachefrom=%5B%5D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&labels=%7B%7D&memory=0&memswap=0&networkmode=default&platform=linux%2Famd64&rm=1&shmsize=0&t=cdk-a3cf09e124d1012c8446b8fbc9d3fb0af39864821bd92922a198a755b57cf1b6&target=&ulimits=null&version=1": open //./pipe/docker_engine: The system cannot find the file specified.C:\data\cdk\lambdalayercdk\node_modules\aws-cdk-lib\core\lib\private\asset-staging.js:4
stderr: ${proc.stderr?.toString().trim()}`):new Error(`${prog} exited with status ${proc.status}`);return proc}exports.dockerExec=dockerExec;
                                            ^
Error: docker exited with status 1
    at Object.dockerExec (C:\data\cdk\lambdalayercdk\node_modules\aws-cdk-lib\core\lib\private\asset-staging.js:4:45)
    at Function.fromBuild (C:\data\cdk\lambdalayercdk\node_modules\aws-cdk-lib\core\lib\bundling.js:1:4198)
    at new Bundling (C:\data\cdk\lambdalayercdk\node_modules\@aws-cdk\aws-lambda-python-alpha\lib\bundling.ts:100:39)
    at Function.bundle (C:\data\cdk\lambdalayercdk\node_modules\@aws-cdk\aws-lambda-python-alpha\lib\bundling.ts:61:44)
    at new PythonLayerVersion (C:\data\cdk\lambdalayercdk\node_modules\@aws-cdk\aws-lambda-python-alpha\lib\layer.ts:63:22)
    at Module.m._compile (C:\data\cdk\lambdalayercdk\node_modules\ts-node\src\index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1180:10)

Subprocess exited with error 1

トラブルシュート②
cdk deploy実行時、以下のエラーが出る場合

failed to get console mode for stdin: The handle is invalid.
[+] Building 2.2s (4/4) FINISHED
 => [internal] load build definition from Dockerfile                            0.1s 
 => => transferring dockerfile: 1.28kB                                          0.0s 
 => [internal] load .dockerignore                                               0.1s 
 => => transferring context: 2B                                                 0.0s 
 => ERROR [internal] load metadata for public.ecr.aws/sam/build-python3.9:late  2.0s 
 => [auth] aws:: sam/build-python3.9:pull token for public.ecr.aws              0.0s 
------
 > [internal] load metadata for public.ecr.aws/sam/build-python3.9:latest:
------
<以下略>
    
Subprocess exited with error 1

有効期限の切れた認証トークンが残ったままになっていて、それを使用してECRのパブリックレジストリにアクセスしたためにこのエラーが出ます。
このエラーは公式ドキュメントにも記載されてます。
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/public/public-troubleshooting.html#public-troubleshooting-authentication

なので、以下のコマンドを実行して認証トークンを削除すればエラーは解消されます。

docker logout public.ecr.aws

Lambdaの確認

Lambdaがデプロイできたか確認します。
Lambdaのコンソールに移動し、デプロイしたLambdaの画面に移動します。
下図のようにLayersが表示されます。
image.png

これをクリックすると、レイヤーに関する情報を確認できます。
image.png

デプロイしたLambdaがちゃんと動くかテストを実行して確認します。
テスト設定はすべてデフォルトで実行します。
image.png

以下のように、乱数が出力されていれば、正常にレイヤーのライブラリを使用できています。
image.png

参考資料

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0