SAM Local（Java）でHello Worldをローカルデバッグするまで（メモ）

# はじめに

SAM Local（Java）でHello Worldを作成し、ローカルでデバッグ実行するまでのメモです。
これまでJavaScript（Node.js）は使用したことがあるのですが、Javaでのlambda作成の勉強のために、まずはHello Worldから始めてみました。

環境は以下のとおりです。

- Windows 10
- SAM CLI 0.37.0
- Python v3.6.4（インストール済み）

手順は以下のように進めました。

- AWS SAM CLIのインストール
- Hello Worldアプリケーション作成
  -  プロジェクト作成
  -  アプリケーションをビルド
  -  アプリケーションをローカルでテスト実行
  -  デバッグ実行（EclipseとVSCodeの2パターン）


# AWS SAM CLIのインストール


「[Installing the AWS SAM CLI on Windows ](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install-windows.html)」を参考に環境を構築します。

以下の4ステップを実行する。

1. Create an AWS account.
1. Configure IAM permissions.
1. Install Docker. Note: Docker is only a prerequisite for testing your application locally.
1. Install the AWS SAM CLI.

上の2つは手順省略し、残りの2つをメモする。

Dockerはローカルでデバッグしないなら不要だが、ローカルでデバッグするのが今回の目的なのでインストールする。

今回の環境はWindows10なので「[Install Docker Desktop on Windows](https://docs.docker.com/docker-for-windows/install/)」を参考にDocker Desktopをインストールする。

SAM CLIではプロジェクトディレクトリが共有ドライブに登録されている必要があるため、Dockerの設定を変更する。
Docker Desktopの「Settings」の「Shared Drives」で対象のプロジェクトが存在するドライブを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/a032ef2c-c340-c91a-1d98-be0660edcfaf.png)

ドライブを共有するためには、仮想マシン（10.0.75.2）からホストマシン（10.0.75.1）へポート445で接続できる必要があります。ファイアウォールソフトが有効であれば、該当ポートを空けておきます。

次にようやくAWS SAM CLIをインストールします。
以下のURLからWindows 64ビット版をダウンロードしてインストールします。特に難しいところはありません。

- https://github.com/awslabs/aws-sam-cli/releases/latest/download/AWS_SAM_CLI_64_PY3.msi

インストール後にバージョンを確認すると以下のようになっていました。

```
>sam --version
SAM CLI, version 0.37.0
```


# Hello Worldアプリケーション作成

以下のサイトを参考に、Hello Worldアプリケーションを作成していきます。

- [Tutorial: Deploying a Hello World Application](
https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html)

（SIerが大好きな）Eclipseに「AWS Toolkit for Eclipse」をインストールし、プロジェクト作成・デプロイまで実施する方法もありましたが、上のサイトを参考にしたため、全てコマンドで実行しています。


## プロジェクト作成

sam init コマンドでサンプルアプリケーションを作成します。
※sam init --runtime java8でも良かったようです。


```
> sam init
        SAM CLI now collects telemetry to better understand customer needs.

        You can OPT OUT and disable telemetry collection by setting the
        environment variable SAM_CLI_TELEMETRY=0 in your shell.
        Thanks for your help!

        Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Which runtime would you like to use?
        1 - nodejs12.x
        2 - python3.8
        3 - ruby2.5
        4 - go1.x
        5 - java11
        6 - dotnetcore2.1
        7 - nodejs10.x
        8 - nodejs8.10
        9 - nodejs6.10
        10 - python3.7
        11 - python3.6
        12 - python2.7
        13 - java8
        14 - dotnetcore2.0
        15 - dotnetcore1.0
Runtime: 13

Which dependency manager would you like to use?
        1 - maven
        2 - gradle
Dependency manager: 1

Project name [sam-app]:

Allow SAM CLI to download AWS-provided quick start templates from Github [Y/n]:

AWS quick start application templates:
        1 - Hello World Example: Maven
        2 - EventBridge Hello World: Maven
        3 - EventBridge App from scratch (100+ Event Schemas): Maven
Template selection: 1

-----------------------
Generating application:
-----------------------
Name: sam-app
Runtime: java8
Dependency Manager: maven
Application Template: hello-world
Output Directory: .

Next steps can be found in the README file at ./sam-app/README.md

```

実行すると、以下のフォルダ・ファイルが生成されます。

```
└─sam-app
    │  README.md
    │  template.yaml
    │
    ├─events
    │      event.json
    │
    └─HelloWorldFunction
        │  pom.xml
        │
        └─src
            ├─main
            │  └─java
            │      └─helloworld
            │              App.java
            │              GatewayResponse.java
            │
            └─test
                └─java
                    └─helloworld
                            AppTest.java
```


## アプリケーションをビルド

サンプルアプリケーションはデフォルトでsam-appディレクトリに作成されるので、ディレクトリを移動し、「sam build」コマンドでビルドします。

```
>cd sam-app
>sam build
Building resource 'HelloWorldFunction'
Running JavaMavenWorkflow:CopySource
Running JavaMavenWorkflow:MavenBuild
Running JavaMavenWorkflow:MavenCopyDependency
Running JavaMavenWorkflow:MavenCopyArtifacts

Build Succeeded

Built Artifacts  : .aws-sam\build
Built Template   : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
```

実行結果の最後に以下のように次のコマンドが表示されるのが便利ですね。

```
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
```

## アプリケーションをローカルでテスト実行

sam local invokeコマンドでアプリケーションをローカルでテスト実行することができます。

```
>sam local invoke "HelloWorldFunction" -e events/event.json
Invoking helloworld.App::handleRequest (java8)

Fetching lambci/lambda:java8 Docker container image......
Mounting C:\pleiades\workspace\sam-app\.aws-sam\build\HelloWorldFunction as /var/task:ro,delegated inside runtime container
[32mSTART RequestId: a23f9ec3-614d-1797-4ac8-cec2a544ee2a Version: $LATEST[0m
[32mEND RequestId: a23f9ec3-614d-1797-4ac8-cec2a544ee2a[0m
[32mREPORT RequestId: a23f9ec3-614d-1797-4ac8-cec2a544ee2a     Init Duration: 474.98 ms        Duration: 1333.68 ms    Billed Duration: 1400 ms        Memory Size: 512 MB     Max Memory Used: 75 MB   [0m

{"body":"{ \"message\": \"hello world\", \"location\": \"XXXXXXXXX\" }","headers":{"X-Custom-Header":"application/json","Content-Type":"application/json"},"statusCode":200}

```


## Eclipseでデバッグ

Eclipseでデバッグするなら、最初からEclipseに「AWS Toolkit for Eclipse」をインストールしてプロジェクトを作成すれば簡単だったのですが、コマンドラインから作成したので若干面倒な手順になっています。

まずはMavenプロジェクトをEcilpse用のプロジェクトに変換します。

```
cd sam-app\HelloWorldFunction
mvn eclipse:eclipse
```

変換後、Eclipseでプロジェクトをインポートします。

Eclipseの「デバッグの構成」で「リモートJavaアプリケーション」の構成を以下のように作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/6b701928-6a76-cb64-d415-bc9efbd976f8.png)

「--debug-port 5858」を指定してアプリケーションをローカルで実行します。

```
sam local invoke "HelloWorldFunction" -e events/event.json --debug-port 5858
```

この状態でEclipseで先ほど作成したデバッグ構成を実行すると、通常どおりJavaのデバッグを実行することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/88ec1325-c2f9-a25e-3539-d3cb588958d7.png)


# VSCodeでデバッグ

先ほどはEclipseでリモートデバッグを実行しましたが、今度は同様のことをVSCodeから実行してみます。

メニュー「デバッグ」－「構成を開く」を選択すると、launch.jsonが開きます。
ここで、「デバッグ」－「構成の追加」から、「{} Java: Attach to Remote Program」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/5083be59-db15-5216-d123-a1aad3481f77.png)

選択するとリモートデバッグの項目が追加されるので、"hostName"と"port"だけ書き換えてあげます。

```json
{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        
        {
            "type": "java",
            "name": "Debug (Attach) - Remote",
            "request": "attach",
            "hostName": "127.0.0.1",
            "port": 5858
        },
        {
            "type": "java",
            "name": "Debug (Launch) - Current File",
            "request": "launch",
            "mainClass": "${file}"
        }
    ]
}
```

後はSAM Localでローカル起動し、VSCodeからリモート接続すればデバッグすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/3b6b90a4-16b7-8d5a-f022-78fbe9a046bd.png)

# おわりに

Eclipseを使用するなら、最初から「AWS Toolkit for Eclipse」をインストールすれば、以下のようにデバッグ構成を作成し、Eclipseからローカル実行しそのままデバッグまで実行することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179607/bfe48dd7-ba72-0741-03dc-912f659e9493.png)


# 補足

上述の方法でやりたいことはやれたのですが、Docker DesktopがVirtualBoxと相性が悪いため、一旦Docker Desktopはアンインストールしました。
しかも、アンインストールも失敗する状況に陥ってしまったため、
以下を参考にアンインストールしました。あとHyper-Vも無効化しました。

- [How to completely remove Docker in Windows 10](https://success.docker.com/article/how-to-completely-remove-docker-in-windows-10)

VirualBoxとDocker Desktopを共存させる方法も調べてみましたが、これで大丈夫というのは見つからなかったので、Linuxの環境で再度チャレンジしてみるつもり。


# 参考

- [Installing the AWS SAM CLI on Windows ](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install-windows.html)
- [Install Docker Desktop on Windows](https://docs.docker.com/docker-for-windows/install/)
- [Tutorial: Deploying a Hello World Application](
https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html)