【AWS】『AWS Toolkit for VSCode』でLambda開発してみよう！

# 自己紹介

こんにちは、2025/3からクラウド戦略チームに参画した佐藤です。
AWSやPythonなどをメインに興味のあることを情報発信できればと思っておりますので、よろしくお願いいたします。

# はじめに

昨今のテキストエディタ、あるいはIDE環境といえば真っ先に思いつくのが **Visual Studio Code（以後VSCode）** なのではないでしょうか。実際私も新しいPCの環境セットアップの中に必ずVSCodeの導入というものがあります。
本記事ではそんなVSCodeでAWSを便利に活用するために提供されている『AWS Toolkit for VSCode』の中でも特に **Lambda** の開発に絞ってお話していきたいと思います。

# 従来の Lambda 開発

Lambda 関数を作成する際に皆さんはどのようにして開発を行っていたでしょうか？
私は以下のような形で開発を行うことが多かったです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/ac6d50ad-0ee2-4234-9d24-2fbb57533531.png)

このフローではローカルで開発したものを Lambda 上に持ってくる形になります。つまり、ローカル環境では期待通りに動くようにしておくことで、AWS 起因のエラー以外は 起きないようにしておこうという考えです。

ここで Lambda コンソール上で無理やり開発してしまうと、逐一 CloudWatchLogs でログを確認し、コードを修正し、と開発するのは非常に大変だと個人的には思います。したがって、Lambda でテストしてコードに問題がある場合は、ローカルの開発環境に戻ってコードを書き換えていきます。そうすることで、Lambda 関数に書かれているコードとローカルにあるコードに不整合が起きることを防ぐことにもつながります。

ただし、昨今のアジャイル開発の流れからコード修正の頻度が増えるにつれ、ローカル環境とクラウド環境の不整合や、開発時に VSCode （ローカル）とマネジメントコンソール（Lambda）の行き来が頻発することによる生産性の低下が問題になります。

これらの問題を解決するため、**AWS Toolkit** および **AWS SAM** を活用していきましょう！

# AWS Toolkit で Lambda 開発！

AWS Toolkit で Lambda 開発を行うことで、以下のようなサイクルで開発を行うことができます。このようにすることで、マネジメントコンソールと VSCode を行き来する回数が格段に減り、開発時のストレスを低減することが期待できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/60af49c3-34ad-49b2-91fd-d760057e3e96.png)

:::note info 
AWS Toolkit で Lambda 関数をローカル開発するには SAM が不可欠です。
少し面倒ですが、SAM を導入しておいてください。
https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/install-sam-cli.html
:::

## AWS SAM を使用してテンプレートからアプリケーションを作成

SAM テンプレートを使用して Lambda の作成を行うことができます。
AWS Toolkit の`Explorer` > `Lambda`を右クリックし、`Create Lambda SAM Application`をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/30c02073-2469-4d4e-a4bd-ab13f1163fa3.png)

ランタイムを選択します。今回は Python3.13 を使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/12b3dafa-d6b6-4432-a5fd-ed664ed4f981.png)

使用するテンプレートを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/71f4002e-7148-4801-ab7d-a8f35908ad2b.png)

アプリを作成するディレクトリを選択します。

:::note warn
後ほど説明ありますが、日本語が含まれるパスを選択しないでください
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/69c846e0-5f55-464b-a64d-0ef294c05f4d.png)

アプリの名前を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/f30b0083-03c8-45cf-8afc-797adb645bed.png)

ターミナルに以下のような出力がされ、指定したアプリ名でフォルダが作成されていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/a6b80c40-bb77-4885-9231-954bf099a8b4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/31f754dc-284a-40eb-9de3-b9640e41fce2.png)

AWS Toolkit の **Application Builder** を開くと、作成したアプリが追加されています。
フォルダの二つ目のアイコン（`Open with Infrastructure Composer`）を開くと、作成するリソースを視覚的に確認できます。
今回は API Gateway は不要なので、消しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/317e1d45-c2c1-403c-94a9-5d2f7ae77fc3.png)

`HelloWorldFunction`の`</>`マークをクリックするとコードを確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/97238794-441f-4a88-8fba-21b1211ed662.png)

関数の名前を変えてみましょう。
先ほどの **Infrastructure Composer** から `HelloWorldFunction` をダブルクリックします。
`LogicalId`を変更して保存すると、自動的に Application Builder 内の名前も変更されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/a59a8508-81fc-46d1-af7c-e7ce8adabc2e.png)

せっかくなのでコードをおいているフォルダ名も変更しましょう。
`hello_world`という名前のフォルダを別の名前に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/f2450432-e094-4459-bd4e-cac013cc1865.png)

Infrastructure Composer から`Source path`を変更し、保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/807c6ba9-95df-4698-93ad-27cd8d367e46.png)

## AWS SAM でビルド

さて、アプリを構築していきましょう！
Application Builder のアプリフォルダにある3つ目のアイコン（`Build SAM Template`）をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/40d42da1-f332-404d-9906-b520e79242b6.png)

`Specify build flag`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/e8028528-c62b-415c-b6fc-7e563c39a5e8.png)

今回は Lambda と VSCode に注視するため各オプションについて深く触れませんが、画像の通り有効化します。
(処理の高速化やコンテナとして Lambda をデプロイするなど)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/fb16bacb-a7c3-4325-80a3-5abb96d514f4.png)

`OK`をクリックすると自動的にターミナルが起動し、画像のように表示されればビルドは成功です。
うまくいかない場合は Docker が原因の可能性があるので確認してみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/f7a1ead4-c18a-4989-a680-06adec63b9b3.png)

## 開発と実行

Application Builder の`▷`ボタンをクリックすると、画面のような表示がされ、マネジメントコンソール上でテストする際と似たような設定項目が表示されます。今回は Payload なしで実行してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/616cdc60-e4c5-450a-96b0-a34900c42701.png)

初回はコンテナの起動に時間がかかりますが、画像のような形でログが出力されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/2e34112e-7aba-4fdc-8bcb-6fab28979db0.png)

コードを編集してみましょう。（`</>`マークをクリックしてコードを編集してファイル保存）
今回はカンマ区切りに入力された数字をすべて足して出力するといったものを作ってみようと思います。

```python
def lambda_handler(event, context):
    result = 0
    for i in event['data'].split(','):
        result += int(i)
    return result
```

再度`▷`ボタンをクリックし今度は Payload に以下のような入力を与えてあげます。

```json
{
  "data": "1,2,3,4,5"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/c839cff6-b349-442c-b7a5-ab5fcfa1149b.png)

上記で`Invoke`するとターミナルが起動し、ログが出力されます。
`REPORT`が表示されるのが非常に便利ですね、タイムアウト値の参考にしたり、コールドスタートの影響を予測するのに役立ちそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/3709c89b-7eb7-418f-990d-9b5075f12be4.png)

## 外部モジュールを利用する

さきほど、python の繰り返し処理を使って合計値を求めましたが、実際リストの合計を出力させるのには numpy を利用することが一般的かと思います。
以下のように書いたほうがなんかかっこいいですよね。

```python
import numpy as np

def lambda_handler(event, context):
    return int(np.sum(list(map(int, event['data'].split(',')))))
```

そこで、標準モジュールではないモジュールの利用方法も確認してみましょう。
作成されたアプリフォルダ（もともと`hello_world`だった場所）に`requirements.txt`があるため、そこに必要なモジュールを追加します。
今回は画像のように numpy を追記します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/f5deb329-b2a4-41a3-8070-34c053808f18.png)

:::note info
処理時間について
今回の場合は Duration （処理時間）は for 文に軍配が上がっていますね。試しに少しローカルで実行時間の比較をしてみましたが、足し算を行う数字の数が増えれば増えるほど numpy のほうが処理時間が早くなりそうです。今回のように5つ程度であれば for 文の方が早い場合があるようです。

| # | `Init Duration` | `Duration` |
| :----- | :------: | :-------: |
| for文 | `0.21ms` | `11931.86ms` |
| numpy | `0.09ms` | `18421.84ms` |
:::

レイヤーを作成するのってちょっとめんどくさかったりするので、コンテナで Lambda を作ると、この辺は楽ですね。

## Lambda をデプロイ！

では実際に Lambda をデプロイしてみましょう！
Application Builder の4つ目のアイコン「Deploy SAM Application」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/c2a0b849-2291-437f-83c2-eff38c3c5733.png)

同期かどうかを選択できます。
今回は開発環境なので`Sync`を選択します。本番環境などの不用意に変更させたくない環境では`Deploy`を選択しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/1c3183d7-eb02-46b8-bb57-b83a4f8d72e6.png)

リージョンを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/b711c785-69a0-4286-8f58-a6b3e4d50e1c.png)

スタック名を指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/e9d1ae46-8e54-4f15-b2e8-7f0c17c5a6ed.png)

AWS SAM が情報を保存する S3 バケットを選択、または作成します。
今回は既存バケットがないので新規作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/623bf4a9-7ff8-422b-a0e9-b17ab5477a4f.png)

最後にオプションを選択します。
`Watch`オプションを有効化しておくことで、コードの変更を監視し、自動的にデプロイすることが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/f05413f1-1a66-4b85-bb8b-ac67c4095263.png)

:::note warn 
UnicodeError が発生した場合
パスに日本語が含まれていると、`samconfig.toml`ファイルに文字化けした絶対パスが追加されている可能性があります。
パスを英語にして文字化けしている部分を書き換えてあげるのが無難かと思います。
:::

同期だけど開発環境であってるよね？という旨のポップアップが表示されるので`OK`を押します。

。。。
。。。

さて、完了するのを待っているとどうやら実行に失敗してしまったようです。
エラーメッセージを確認すると、CloudFormation が`ROLLBACK_COMPLETE`に遷移してしまっていることがわかります。
ではなぜロールバックしてしまったのかを確認します。
ターミナルのログに Cloudformation スタックのステータス遷移のログが出力されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/412d128b-f742-4122-bb3c-421fe50d30b1.png)

確認すると、削除した API Gateway の情報がテンプレートの`Outputs`で参照されてしまっていることが原因だとわかります。今回のエラーメッセージには出ていませんが、`HelloWorldFunctionRole`もないことがわかるので、こちらも併せて修正しておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/8b98e264-1c1e-41b5-a1fc-d08e7b8c241e.png)

再度デプロイしてみましょう。
その前に先ほどロールバックしてしまったスタックを削除するため、以下のコマンドを実行します。

```bash
sam delete --stack-name <スタック名> --profile <プロファイル名>
```

それではもう一度デプロイします。
無事成功したようです！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/1da038ba-375a-449b-965b-41452b367f80.png)

コードを編集してみましょう！

```python
import numpy as np

def lambda_handler(event, context):
    return int(np.sum(list(map(int, event['data'].split(','))))) ** 2
```

上記のように変更して保存してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/5b604462-dc3e-41b3-8140-18d6ddec68ef.png)

保存をしたタイミングで`SAM Sync`ターミナルが動きます。
マネジメントコンソールからも確認すると変更が適用されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/e236e661-2a91-464a-880e-234149f1a22c.png)

これでローカル環境とAWS上でコードの整合性がとれなくなる問題が一気に解決します！感動！

## Lambda をテスト

デプロイ完了後に当然 AWS 上でも正常に機能するかのテストを行う必要があります。
よくある IAM Role に権限が足りなかったなどの AWS 上固有のエラーを防ぐためです。
なんと！これも VSCode 上から可能です！

Application Builder の Lambda 関数を開くと、雲マークの ARN が追加されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/089c8934-4732-4f51-828a-8a9004526c48.png)

右クリックすると画像のようなメニューが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/03ad674e-1364-4cf7-bdea-0e4166768abe.png)

`Invoke in the cloud`をクリックすると、呼び出しメニューが開くので、サンプルイベントを入力し`Remote Invoke`をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/ef62bc7a-75da-44c4-9473-68fc6ae4f39f.png)

ターミナルが起動しログが表示されます。
2乗するように変更していたので225が出力されていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/64c6b4de-5f1d-468b-b35c-26d92372c818.png)

`Search Log`ボタンをクリックすることでログを検索することも可能です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/333a335d-58e3-49b3-8dbb-1ef41e9ece18.png)

## Live Tail

2025/03/04に [AWS Lambda adds support for Amazon CloudWatch Logs Live Tail in VS Code IDE](https://aws.amazon.com/about-aws/whats-new/2025/03/aws-lambda-cloudwatch-logs-live-tail-vs-code-ide/) が発表されました。
せっかくの機会なので試してみましょう！
AWS Toolkit の Explorer または Application Builder から **Tail Logs** をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/b3292390-8ee6-4ecd-91ec-3c8b433d12ea.png)

先ほどと同様の手順で関数を呼び出してみると、開かれたテキストファイルに自動的に、AWS試験風に言うと「ほぼリアルタイム」にログが書き込まれます。
もちろんマネジメントコンソール上から実行しても同様に書き込まれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4026620/da913088-4a4c-4010-be3f-645985f50b31.png)

設定時にフィルタリングも可能なため、エラーログのみ吐かせるなど用途は多そうです。

# 終わりに

今回は前々からもっと効率いい方法あるのはわかってるんだけど、結局毎回従来の方法で開発をしてしまっていた Lambda 関数を VSCode を使用して効率的に開発する方法についてまとめてみました。

特にPCのメモリを圧迫している Chrome と VSCode のメモリ使用量を減らせるんじゃないかというすごく私的なメリットがあったりします（笑）
導入も簡単ですので、ぜひ使ってみてはいかがでしょうか！

それでは、よい Lambda ライフを過ごしましょう！
（作ったものでいらないものは削除をお忘れなく！）

# 弊社では一緒に働く仲間を募集中です！
現在、様々な職種を募集しております。
カジュアル面談も可能ですので、ご連絡お待ちしております！

募集内容等詳細は、是非採用サイトをご確認ください。
https://engineer.po-holdings.co.jp/