CDKのBucketDeploymentが作るLambdaはEOL注意！ ランタイム更新の方法まとめ

# はじめに
AWS CDKを使ってS3バケットにファイルをデプロイする場合、BucketDeploymentという便利なクラスがあります。これを使うと、ローカルのファイルやアセットを簡単に指定したS3バケットへアップロードできます。

今回、案件でCDKを使ったLambda開発を進める中で、「Lambdaのランタイム（実行環境）を最新バージョンに更新する」という対応を行っていました。
明示的に作成したLambda関数については、無事に新しいランタイムへ移行できたのですが、その後、BucketDeploymentが自動生成するLambdaのランタイムがPython 3.9になっていることに気付きました。

調べてみると、Python 3.9は **近いうちにEOL（サポート終了）** を迎える状況。
「このまま放置して大丈夫なのか？」「なぜこんな古いバージョンなのか？」とさらに調査を進めた結果、CDKライブラリのバージョンに依存していることが判明しました。

この記事では、

- なぜPython 3.9が使われるのか
- どうやれば新しいランタイムにできるのか

について整理し、同じような場面で悩む方の参考になればと思います。

# Bucket Deploymentとは？
BucketDeploymentは、AWS CDKで提供されているクラスの一つで、ローカルのファイルやディレクトリをS3バケットにデプロイ（アップロード）するために使われます。
このBucketDeploymentを使うと、単にS3への新規アップロードだけでなく、一度アップロードしたファイルの中身を変更して再アップロードすることも可能です。

## ソースコード
以下に、BucketDeploymentを使用したソースコードを記載します。
単にS3バケットにファイルをアップロードするだけならば、以下のプロパティのみ設定すればOKです。
- sources プロパティ
    - 対象オブジェクトが存在するディレクトリパスを指定（CDKプロジェクトのルートディレクトリから見た相対パスで記載します）
    - ディレクトリにはファイルを置くだけでいいです
        - zipファイルにする必要はありません（デプロイ時に、対象ファイルを格納したzipファイルが生成される）
- destinationBucket プロパティ
    - 対象S3バケットを指定
        - 以下ソースコードでは、事前に作成した対象バケットをBucket.fromBucketArn関数で取得し、そのオブジェクトをこのプロパティに指定しています
```s3_bucket_deployment-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Bucket } from 'aws-cdk-lib/aws-s3';
import { Source, BucketDeployment } from 'aws-cdk-lib/aws-s3-deployment';
import { Construct } from 'constructs';

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

    // 既存S3バケットを取得
    const existing_bucket = Bucket.fromBucketArn(
      this,
      "cdk-s3-bucket-deployemnt-test-nk",
      "arn:aws:s3:::cdk-s3-bucket-deployemnt-test-nk"
    );

    const uploadObjectsToS3Bucket: BucketDeployment = new BucketDeployment(this, "uploadObjectsToS3Bucket", {
      sources: [Source.asset("bucket_objects")],
      destinationBucket: existing_bucket,
    });
  }
}
```

## S3へのファイルアップロード処理はLambda関数が行っている
BucketDeploymentの裏側では、AWS Lambda関数が自動的に作成されます。
このLambda関数が、指定されたローカルアセット（ファイル群）を対象のS3バケットにコピーする役割を担っています。

つまり、BucketDeploymentを使うと見た目には「ファイルがS3に置かれるだけ」のように見えますが、内部的には
- アセットを一時的にS3にアップロード
    - アセットを格納したzipファイルを作成し、CDK内部で使用するS3バケットにzipをアップロード
- 自動作成されたLambdaがそれをターゲットバケットにコピー
というステップを踏んでいます。

このLambdaの存在は普段あまり意識しませんが、今回のようにランタイムバージョンの問題が発生するケースでは無視できない要素になります。

# 自動作成されるLambda関数のランタイムに注意
ここまで見てきた通り、BucketDeploymentを使うと内部でLambda関数が自動作成され、アセットのコピー処理を実行しています。
そしてこのLambda関数は **Python** が使用されているのですが、ここで一つ注意点があります。

## LambdaのランタイムバージョンはCDKライブラリのバージョンに依存
このLambdaのランタイムバージョンは、使用しているCDKライブラリのバージョンによって決まります。
筆者の環境では、CDKのバージョンが「2.137.0」であり、このバージョンではBucket DeploymentのLambdaのランタイムは「Python 3.9」に設定されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/34e8c4f3-8d84-4b68-a5b1-ad13d157807f.png)

「CustomCDKBucketDeployment」という文字が関数名に含まれたリソースが、このLambda関数に該当するのですが、下図のようにランタイムがPython 3.9で作成されていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/9609ec8f-d3ad-4731-b81b-9aa08671ac00.png)

## Python 3.9はEOL間近
Python 3.9はAWSから **2025/11/3にサポート終了（EOL）** がアナウンスされており、今後は新しいランタイム（例：Python 3.11など）への移行が求められます。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html

当然、このLambda関数も例外ではなく、ランタイムのバージョンを上げる必要があります。

# ランタイムのバージョンを上げる方法
先述の通り、このLambda関数のランタイムバージョンはCDKライブラリのバージョンに依存しています。
そのため、CDKのバージョンをアップデートすることで、自動的に新しいランタイム（例：Python 3.11）が使われるようになります。
ここでは、CDKライブラリをアップデートして、Lambdaのランタイムバージョンを引き上げる手順を紹介します。

## npm-check-updatesインストール
ライブラリのアップデートにはnpm-check-updatesを使用します。
npm-check-updatesは数ステップでpackage.json内のライブラリを最新バージョンにアップデートできるのでおすすめです。

CDKプロジェクト直下のディレクトリで以下のコマンドを実行し、このライブラリをインストールします。
```bash
npm i -D npm-check-updates
```


## 最新バージョンがあるか確認
以下のコマンドを実行し、package.json内で更新可能なライブラリがあるか確認します。

```bash
npx npm-check-updates
```

以下の図のように、CDKライブラリについて最新バージョンにアップデート可能なことが分かります。
このバージョンにアップデートしていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/0ebdaabd-d575-4e9d-adf0-23f2b10f06b6.png)


## package.jsonを更新（ライブラリのバージョンを最新版に更新）
以下のコマンドを実行し、package.json内のライブラリを最新バージョンに更新します。
```bash
npx npm-check-updates -u
```

## 最新版のライブラリをインストール
package.jsonを更新できたので、以下のコマンドを実行し、CDKプロジェクト内のライブラリを最新バージョンに更新します。
```bash
npm install
```

## cdk diff して想定の差分になっているか確認
**cdk diff** コマンドを実行し、差分が想定通りのものになっているか確認します。
- CDKのライブラリ更新やソースコードを変更した際は、**想定外の差分** が入っている可能性もあります。
-  そのため、**cdk diffで差分内容を細かく確認することが安全です。**
```bash
npx cdk diff --profile <AWSプロファイル名>
```

BucketDeploymentで使用するLambdaのランタイムが「Python 3.11」に更新されるのが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/4496127c-656d-4568-afde-ea1344f34186.png)

### （補足）cdk コマンドの先頭に「npx」を付けている理由
**cdk** コマンドの先頭に **npx** をつけています。
npxをつけない場合、端末にグローバルインストールされているCDKライブラリのバージョンで実行されますが、こっちのバージョンが古いと、CDKプロジェクト内のCDKライブラリのバージョンと互換性がなく、以下のエラーになる場合があります。
```bash
This CDK CLI is not compatible with the CDK library used by your application. Please upgrade the CLI to the latest version.
```

## cdk deploy 実行
想定通りの変更がされることが確認できたので、**cdk deploy** コマンドを実行してLambda関数を更新します。
```bash
npx cdk deploy --profile <AWSプロファイル名>
```

スタックが正常に更新されたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/a6bd4dc4-44f4-4cd6-8c5d-dde997d09dea.png)

<br >

マネジメントコンソール上でLambda関数のランタイムが更新されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/5ecee05c-ac8c-4c72-85b9-bb58d7981d09.png)


# まとめ
- BucketDeploymentは、内部でPythonランタイムのLambda関数を使ってS3へのファイルコピー処理を行っています。
- このLambdaのランタイムバージョンはCDKライブラリのバージョンに依存しており、CDKをアップデートすることで新しいランタイムに自動的に切り替わります。
- LambdaランタイムのEOLに備えるためには、ユーザー自身が作成したLambda関数に加えて、BucketDeploymentのような内部で自動生成されるLambdaにも対応する必要があります。
- CDKライブラリの定期的なアップデートと、cdk diffによる差分確認の習慣が、安全なインフラ運用につながります。

# 参考資料
・ソースコード部分はこちらの記事を参考にさせていただきました。

https://qiita.com/akira__0924/items/5856683d1a6eec19aa91

・BucketDeploymentクラスの公式リファレンスページ

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3_deployment.BucketDeployment.html