[AWS CDK] NodejsFunctionで共通で行いたい設定(bundling.forceDockerBundlingなど)をカスタムConstructクラスで省略する

2022.04.20

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、NodejsFunctionクラスで共通で行いたい設定(bundling.forceDockerBundlingなど)を、カスタムConstructクラスを作って省略してみました。

NodejsFunctionのローカルビルドに必要な対応

MacOS上でNodejsFunctionクラスのConstructを含むAWS CDK Stackをローカルビルドする際には、次のいずれかの対応が必要です。

  1. Docker Desktopが起動していること
  2. esbuildがインスールされており、NodejsFunctionbundling.forceDockerBundlingpropがfalseに設定されていること

上記対応がなされていない場合、CDKビルドがエラーとなります。

$ cdk synth
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
ERRO[0000] Can't add file /Users/wakatsuki.ryuta/projects/cm-rwakatsuki/aws_cdk_app/node_modules/aws-cdk-lib/aws-lambda-nodejs/lib/bundling.js.map to tar: io: read/write on closed pipe 
ERRO[0000] Can't close tar writer: io: read/write on closed pipe

関数ごとにbundling.forceDockerBundling設定するのは冗長

前述の2.方法で対応する前提とした場合、作成する全てまたはほとんどのLambda関数に共通でbundling.forceDockerBundlingを設定する必要があるのですが、関数の数が増えてくると冗長になってきます。

lib/aws_cdk_app-stack.ts

//(省略なし)
import { Construct } from 'constructs';
import { Stack, StackProps, aws_lambda_nodejs } from 'aws-cdk-lib';

export class AwsCdkAppStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    new aws_lambda_nodejs.NodejsFunction(this, 'HelloWorld1', {
      entry: 'src/lambda/handlers/hello-world-handler.ts',
      bundling: {
        forceDockerBundling: false,
      },
    });

    new aws_lambda_nodejs.NodejsFunction(this, 'HelloWorld2', {
      entry: 'src/lambda/handlers/hello-world-handler.ts',
      bundling: {
        forceDockerBundling: false,
      },
    });

    new aws_lambda_nodejs.NodejsFunction(this, 'HelloWorld3', {
      entry: 'src/lambda/handlers/hello-world-handler.ts',
      bundling: {
        forceDockerBundling: false,
      },
    });

    new aws_lambda_nodejs.NodejsFunction(this, 'HelloWorld4', {
      entry: 'src/lambda/handlers/hello-world-handler.ts',
      bundling: {
        forceDockerBundling: false,
      },
    });

    new aws_lambda_nodejs.NodejsFunction(this, 'HelloWorld5', {
      entry: 'src/lambda/handlers/hello-world-handler.ts',
      bundling: {
        forceDockerBundling: false,
      },
    });

    //and more...
  }
}

カスタムConstructクラスで省略してみる

そこでbundling.forceDockerBundlingの設定を、カスタムConstructクラスを使用して省略してみます。

まずカスタムConstructクラスを別ファイルで作成します。NodejsFunctionbundling.forceDockerBundlingが既定でfalseとなるようにし、またentryは格納パスがsrc/lambda/handlers/で固定であると想定し、ファイル名のみを指定すれば良いようにしています。

lib/custom-construct-class.ts

//カスタムConstructクラス
import { Construct } from 'constructs';
import { aws_lambda_nodejs } from 'aws-cdk-lib';

export interface AwsCdkNodejsLambdaHandlerProps {
  handlerFile: string;
}

export class AwsCdkNodejsLambdaHandler extends Construct {
  public readonly queueArn: string;

  constructor(
    scope: Construct,
    id: string,
    props: AwsCdkNodejsLambdaHandlerProps
  ) {
    super(scope, id);

    new aws_lambda_nodejs.NodejsFunction(this, 'AwsCdkNodejsLambdaHandler', {
      entry: `src/lambda/handlers/${props.handlerFile}.ts`,
      bundling: {
        forceDockerBundling: false,
      },
    });
  }
}

作成したカスタムConstructクラスを使用してLambda関数を定義します。

lib/aws_cdk_app-stack.ts

//(省略あり)
import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';
import { AwsCdkNodejsLambdaHandler } from './custom-construct-class';

export class AwsCdkAppStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    new AwsCdkNodejsLambdaHandler(this, 'HelloWorld1', {
      handlerFile: 'hello-world-handler',
    });

    new AwsCdkNodejsLambdaHandler(this, 'HelloWorld2', {
      handlerFile: 'hello-world-handler',
    });

    new AwsCdkNodejsLambdaHandler(this, 'HelloWorld3', {
      handlerFile: 'hello-world-handler',
    });

    new AwsCdkNodejsLambdaHandler(this, 'HelloWorld4', {
      handlerFile: 'hello-world-handler',
    });

    new AwsCdkNodejsLambdaHandler(this, 'HelloWorld5', {
      handlerFile: 'hello-world-handler',
    });

    //and more...
  }
}

ビルドを行うとエラー無く実行されました。

$ cdk synth
Bundling asset AwsCdkAppStack/HelloWorld1/AwsCdkNodejsLambdaHandler/Code/Stage...

  cdk.out/bundling-temp-e3d6ffa14aa789fb0ae3789c57f95d9554e8d404e91655d711e4df0617e9c42c/index.js  188b 

⚡ Done in 3ms
Resources:
  HelloWorld1AwsCdkNodejsLambdaHandlerServiceRoleDBC2ED23:
  ...

おわりに

NodejsFunctionで共通で行いたい設定(bundling.forceDockerBundlingなど)をカスタムConstructクラスで省略してみました。

そもそも今までbundling.forceDockerBundlingの設定を知らず、NodejsFunctionを作成する開発の際にはデスクトップで必ずDockerを起動するようにしていたのですが、今後はしなくて良くなりました。

参考

以上