AWS CDK - Lambda で既設の EFS マウント


# AWS CDK - Lambda で既設の EFS マウント

久しぶりに記事を書きます。  
IaCとしてAWS CDKを採用して開発をはじめ、その運用・保守が約2年になろうとしています。  
アプリケーションエンジニアを自負していたのに、すっかりインフラエンジニアっぽくなってきました。  

当初ローンチから追加で生えてきたマイクロサービスをLambdaで追加していましたが、一部リソースは手動でコンソールから準備して参照するような構成にしていたりして一部ちぐはぐなところがありました。  
そういったちぐはぐさは解決するべき課題として残り続けるとして、少しでも良くしようと考えるわけです。  

LambdaでEFSをマウントしてファイル操作をあれこれするという処理があって、Lambdaから既に存在するEFSをマウントしてリソース管理するCDKを書く必要がありました。この時思いのほかハマったので記事にしました。  
意外とドンピシャの記事がなくて苦労しました。こういった方法がアンチパターンなんでしょうか？  
もし同じことでお困りの人がいたら参考にしてください。ネットの波を泳いで私も解決方法を見つけただけです。

## 改修前

```typescript
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as efs from 'aws-cdk-lib/aws-efs';
import * as lambda from 'aws-cdk-lib/aws-lambda';

～～省略～～
    // 実装
    this.lambdaSample = new lambda.Function(scope, 'LambdaSample', {
      functionName: 'LambdaSample',
      description: 'sampleです',
      runtime: lambda.Runtime.PYTHON_3_9,
      code: lambda.Code.fromAsset('lambda/apisample'),
      handler: 'lambda_function.lambda_handler',
      timeout: cdk.Duration.seconds(60),
      role: rr.XXXX,
      memorySize: 128,
      logRetention: logs.RetentionDays.ONE_MONTH,
    });
```

## 改修後

```typescript
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as efs from 'aws-cdk-lib/aws-efs';
import * as lambda from 'aws-cdk-lib/aws-lambda';

～～省略～～

    // 準備
    let MainVPC = ec2.Vpc.fromLookup(scope, 'Vpc', { isDefault: false, vpcId: props?.VPCIDMain });
    let Lambdasg = ec2.SecurityGroup.fromSecurityGroupId(scope, 'SecurityGroup', props?.SGLambda!);
    let MainEFS = lambda.FileSystem.fromEfsAccessPoint(
      efs.AccessPoint.fromAccessPointAttributes(scope, 'ap', {
        accessPointId: props?.EFSAPId,
        fileSystem: efs.FileSystem.fromFileSystemAttributes(scope, 'efs', {
          fileSystemId: props?.EFSId,
          securityGroup: Lambdasg,
        }),
      }),
      '/mnt/data',
    );

～～省略～～
    // 実装
    this.lambdaSample = new lambda.Function(scope, 'LambdaSample', {
      functionName: 'LambdaSample',
      description: 'sampleです',
      runtime: lambda.Runtime.PYTHON_3_12,
      code: lambda.Code.fromAsset('lambda/apisample'),
      handler: 'lambda_function.lambda_handler',
      timeout: cdk.Duration.seconds(60),
      role: rr.XXXX,
      memorySize: 128,
      logRetention: logs.RetentionDays.ONE_MONTH,
      environment: props.XXXX,
      layers: [props.XXXX],
      architecture: lambda.Architecture.ARM_64,   
      
      // ---EFSマウントのため既存リソースの参照---
      vpc: MainVPC,
      securityGroups: [Lambdasg],
      filesystem: MainEFS,
    });
```

## 解説

VPCとElasticFileSystem、AccessPointは先にある前提です。SecurityGroupは既にあるものでも、適当に作ってもいいです。  
入れ子になってて少しわかりづらいですが、以下の流れです：

1. `efs.FileSystem.fromFileSystemAttributes`でEFS属性からアクセスポイント用の`fileSystem`を取得
2. `efs.AccessPoint.fromAccessPointAttributes`でアクセスポイントを取得
3. `lambda.FileSystem.fromEfsAccessPoint`でLambdaでマウントできるFileSystemを取得

ともあれこれでEFSマウントしたLambdaが無事にできます。  
こんなの簡単にできそうなのに、CDKのバグ、準備不足なのか直感的にコードを書いていってもエラーになったり、実行時エラーになったりして期待通りにならなくて、過去の議論にもCDKのIFの設計がかみ合ってないのか少しうまくいかない、とだけ書いてあったりで意外と情報が少なくて悩みました。

## 環境

- Windows 11 Pro
- Node v18.18.2
- AWS CDK 2.134.0

## 参考

このあたり参考にさせていただきました：

- [Qiita Article by takmot](https://qiita.com/takmot/items/346ca1a0fd95737a4445)
- [GitHub Issue #10711](https://github.com/aws/aws-cdk/issues/10711)