Serverless FrameworkでAWS LambdaにJavaをディプロイする方法

私はこれまでEclipseでJavaを開発してきた。
ただ、最近 IntelliJ Ideaを個人で購入したので、そちらを意識的に使おうとしている。しかし、そこで問題になってきたのが、Eclipseには存在する「AWS Toolkit」に相当するプラグインがIntelliJ Ideaにはないのである。これは実際困った。
そこで、隣の人がNode.jsのディプロイに使用していた Serverless Frameworkを使うことで、AWS ToolkitがなくてもJavaアプリケーションをコマンド一発でAWS Lambdaにディプロイできるようになったので、そのまとめを記事にする。

なお、私の実行環境は以下であるが、社内認証プロキシ配下にあるので、プロキシに関する設定も手順の中に含めている。
認証プロキシが原因で、いろいろなことを諦めている人はもしかすると希望が見えるかもしれない。

```
環境
OS Windows10 Pro

インストール前提(Java開発者なら多分すでにインストール済みであろうもの)
JDK Java8
Apache Maven 3.3.9 ※3以降ならバージョンは問いません
Java IDE: 問わない
```

# nodistのインストール
Node.jsをそのままインストールすればよいのだが、Node.jsは更新が早かったり、バージョンによる相性の問題があるので、容易にNode.jsのバージョン管理を行えるnodistをインストールして使用する。
以下よりnodistの最新版をダウンロードする。
https://github.com/marcelklehr/nodist/releases

![image.png](https://qiita-image-store.s3.amazonaws.com/0/161223/b324d670-ce39-f3e7-feb1-f4ffa71cd122.png)

ダウンロードしたexeを実行し、インストールを行う。
デフォルトでは `c:¥program files`となるが、スペースが入っているディレクトリの場合はServerless Frameworkの実行時にエラーとなる可能性があるため、Cドライブ直下などスペースを含まない場所に変更してインストールすることをおすすめする。

# Node.jsのインストール
## Proxyの設定の設定を行う(必要な場合のみ)
私の場合は社内に認証プロキシーがあるので、環境変数に以下の値を設定する。

| 変数名       |       変数値 |    備考    |
|:-----------------|------------------|:------------------:|
| HTTP_PROXY            | http://[ユーザ名]:[パスワード]@サーバー名:ポート |       -        |
| HTTPS_PROXY       | http://[ユーザ名]:[パスワード]@サーバー名:ポート |       -       |

## インストール可能なNode.jsのバージョンの確認
コマンドプロンプトを起動し、以下のコマンドを入力し、Enterを押下

```
e:\nodist>nodist dist
 ```

以下のようにインストール可能なNode.jsのバージョンが表示される

```
8.0.0
8.1.0
8.1.1
```

## バージョンを指定してインストールする
`nodist + version`の形式でインスト－ルを行う。

```
e:\nodist>nodist + 8.9.0
 8.9.0 [===============] 22436/22436 KiB 100% 0.0s
8.9.0
```

## 使用したいNode.jsを選択する

```
e:\nodist>nodist 8.9.0
```

## 使用するNode.jsに合うnpmをインストールする

```
e:\nodist>nodist npm match
npm match
https://codeload.github.com/npm/npm/tar.gz/v5.5.1 [===========    ] 4309/5752 KiB 75% 5.0s

e:\nodist>npm -v
5.5.1
```

# Serverless Frameworkのインストール
Node.jsとnpmのインストールが完了したので、本命のServerless Frameworkを導入する。
`npm install -g serverless`を入力して、Serverless FrameworkをローカルPCにインストールする。

```
e:\nodist>npm install -g serverless

e:\Nodist\bin\serverless -> e:\Nodist\bin\node_modules\serverless\bin\serverless
e:\Nodist\bin\sls -> e:\Nodist\bin\node_modules\serverless\bin\serverless
e:\Nodist\bin\slss -> e:\Nodist\bin\node_modules\serverless\bin\serverless
npm WARN lifecycle The node binary used for scripts is e:\Nodist\bin\node.exe but npm is using e:\Nodist\v-x64\8.9.0\node.exe itself. Use the `--scripts-prepend-node-path` option to include the path for the node binary npm was executed with.
> spawn-sync@1.0.15 postinstall e:\Nodist\bin\node_modules\serverless\node_modules\spawn-sync
> node postinstall
> serverless@1.23.0 postinstall e:\Nodist\bin\node_modules\serverless
> node ./scripts/postinstall.js
+ serverless@1.23.0
added 251 packages in 177.711s
```


# AWS CLIのインスト－ルとセットアップ
Serverless FrameworkはAWS CLIを内部で利用するため、ここでAWS CLIをインストールする。
以下のサイトからインスト－ルファイルををダウンロードし、インストールを行う。
https://aws.amazon.com/jp/powershell/

インスト－ル後にpowershellを管理者で起動し、`aws configure`を実行する。
AWS Lambdaのアップロ－ドに使用する値を事前に定義する。すでに値が設定済みの場合は、以下のように[****BG4A]という表記となり、変更したくない場合は、入力せずにEnterキー押下で当該項目の入力を回避できる。

```
PS E:\awscli> aws configure
AWS Access Key ID [****************BG4A]: 自分のAWS Access Key IDを入力し、Enterキー押下
AWS Secret Access Key [****************BsCe]: 自分のAWS Secret Access Keyを入力し、Enterキー押下
Default region name [us-west-2]: us-east-1
Default output format [None]: json
```

AWS Access Key ID及びAWS Secret Access KeyについてはAWSの以下URLから発行が可能。管理者権限で全てのサ－ビスにアクセスできる権限があれば良いが、ない場合は管理者に適切に権限を付与してもらうように依頼すること。
https://console.aws.amazon.com/iam/home?#/users

# Javaのアプリケーション作成
## Serverless Frameworkを使用して、Java開発用ディレクトリを自動生成する

適切なディレクトリを作成し、そのディレクトリ配下に移動後、`serverless create --template aws-java-maven`を入力し、Enterキーを押下する。

```
E:\>cd workspace
E:\workspace>mkdir serverlesssample
E:\workspace>cd serverlesssample
E:\workspace\serverlesssample>serverless create --template aws-java-maven
Serverless: Generating boilerplate...
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.23.0
 -------'

Serverless: Successfully generated boilerplate for template: "aws-java-maven"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name
```

※上記で作成されたディレクトリを用いて開発を始めても問題ない。しかし、すでにAWS Lambda向けのJavaアプリケーション開発用ディレクトリが存在する場合は、上記で生成された`serverless.yml`をコピーして、pom.xmlと同じディレクトリに配置すればよい。

## ビルドのために、認証Proxyを設定する(必要な場合のみ)
認証Proxy配下にPCが存在する場合はビルドの際に接続エラーとなるので、mavenのsettings.xmlに以下の形式でホスト名、ポート、ID、パスワードを入力する。HTTPとHTTPSの両方を登録しておく。

```settings.xml
<proxies>
 <proxy>
   <id>optional-1</id>
   <active>true</active>
   <protocol>http</protocol>
   <host>ホスト名</host>
   <port>ポート</port>
   <username>ID</username>
   <password>パスワード</password>
   <nonProxyHosts>localhost</nonProxyHosts>
 </proxy>
 <proxy>
   <id>optional-2</id>
   <active>true</active>
   <protocol>https</protocol>
   <host>ホスト名</host>
   <port>ポート</port>
   <username>ID</username>
   <password>パスワード</password>
   <nonProxyHosts>localhost</nonProxyHosts>
 </proxy>
</proxies> 
```

## Jarファイルのパッケージング
AWS Lambdaにアップロードするjarファイルは依存するjarを含めて固める必要がある。
そこで、pom.xmlに以下のpluginの記述をする。


```pom.xml
       <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-shade-plugin</artifactId>
          <version>2.3</version>
          <configuration>
            <createDependencyReducedPom>false</createDependencyReducedPom>
          </configuration>
          <executions>
            <execution>
              <phase>package</phase>
              <goals>
                <goal>shade</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
```
そして、 DOSプロンプトからpom.xmlの存在するディレクトリに移動し、`mvn package shade:shade` を実行する。

```
E:\workspace\serverlesssample>mvn package shade:shade
```

ビルド、パッケージングが成功するとtargetディレクトリ配下にjarファイルが生成される。

#AWS Lambdaへのディプロイ
## serverless.ymlの修正
serverless frameworkを使用してディプロイするためには、`serverless.yml`を一部修正する必要がある。リリースするリージョンやディプロイに利用するIDなどはAWS CLIで設定した値が使用されるため設定ファイルの修正は不要である。
初歩的なアプリケーションの場合は以下の定義で動作すると思われる。

```serverless.yml
service: sevice-name  #サービス名を自分で決めて記載する

provider:
  name: aws
  runtime: java8
  stage: prod

package:
  artifact: target/alexa-skills-kit-samples-1.0.jar #上記手順で生成されたjarを定義

functions:
  AlexaSkillsRecipe: #Function名を記載
    handler: jp.co.saison.lambda.alexa.recipe.RecipeSpeechletRequestStreamHandler #ハンドラをパッケージ含めて記述

environment: #lambdaの環境変数に設定したい項目をKeyとValueを記述する
  ALEXA_APP_ID: ******
  RAKUTEN_APP_ID: *******

```

## Serverlessを使用したディプロイ
PowerShellを管理者で起動し、serverless.ymlを配置したディレクトリに移動する。
`serverless deploy -v`を実行すると、AWS Lambdaに対象jarのディプロイが行われる。

```
E:\workspace\serverlesssample>serverless deploy -v
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - 
CloudFormation - UPDATE_IN_PROGRESS - AWS::Lambda::Function - 
CloudFormation - UPDATE_COMPLETE - AWS::Lambda::Function - 
CloudFormation - UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation:
CloudFormation - UPDATE_COMPLETE - AWS::CloudFormation::Stack - arima-prod
```

# AWSでのlambdaの確認
正しくディプロイが実施されたか否かは以下のURLから、Lambda関数の名前で検索することで確認できる。
https://console.aws.amazon.com/lambda/

※ディプロイしたリージョンと現在表示しているリージョンが異なる場合があるので、その場合は画面右上の地域を変更する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/161223/6f3d5b5c-c840-17b4-7714-fd0cc4cc1365.png)


以上が、Serverless Frameworkを使ってJavaアプリケーションをディプロイする方法である。AWS Lambdaは様々な使い方がすでに存在している。どういう使い方が効果的かなどは、以下の書籍が比較的新しく実践的であるのでおすすめである。
[実践AWS Lambda ~「サーバレス」を実現する新しいアプリケーションのプラットフォーム~](http://amzn.to/2ipAl2T)