【AWS】Lambda ~ Java / EC2 を操作する ~

 ■ はじめに

Lambda でEC2を開始・停止できるように設定する

 ■ 手順

https://dk521123.hatenablog.com/entry/2017/05/22/233340

では、Mavenを使ったが、今回は、Gradleでやってみる

 今回作成する環境下

 * OS            : Windows10
 * Java          : Java1.8
 * Eclipse       : Oxygen.1a Release (4.7.1a)
 * ビルド ツール : Gradle

※ Buildship: Eclipse Plug-ins for Gradle がインストールされていること

 1)Eclipse / Gradle プロジェクトを作成する

[1-1] Eclipseの[File]-[New]-[Other]-[Gradle]-[Gradle Project]を選択し、「Next」ボタン押下。
     さらに、「Next」ボタン押下。

[1-2] 以下を入力し、「Finish」ボタン押下
 + Project Name   : 任意(今回は「AwsLambdaDemo」)

 2)ビルドスクリプト「build.gradle」の修正

[2-1] Eclipseの対象プロジェクト直下にある「build.gradle」を開き
      以下のサンプルの「build.gradle」を参考にし、修正する

[2-2] Eclipseの対象プロジェクトを右クリックし、[Gradle]-[Refresh Gradle Project]を選択
 => JARをダウンロードしてくる

[2-3] Eclipseの対象プロジェクト内の「src/main/java」「src/test/java」配下にある
     「Library.java」「LibraryTest.java」を削除する

 3)Lambdaファンクションを作成

[3-1] Eclipseの対象プロジェクト内の「src/main/java」を右クリックし、
      [New]-[Other]-[Class]を選択し、Javaソースを作成する

[3-2] 以下のサンプルの「LambdaDemo.java」「Request.java」を参考に、Lambdaファンクションを作成する

 4)Lambdaファンクション用にzip ファイル化
http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/create-deployment-pkg-zip-java.html

を参考に、gradle コマンドを実行して、
.zip ファイルにプロジェクトをビルドおよびパッケージ化する 

[4-1] Eclipseの対象プロジェクトを右クリックし、[Run As]-[Run Configurations...]-[Gradle Project]を選択し
      「ファイルに+アイコン(New Lunch configuration)」を押下

[4-2] 以下の項目を入力し、「Run」ボタン押下
 + Name : 任意(今回は「builder」)
 + Gradle Tasks : build
 + Working Directory : 任意のパス(今回は「${workspace_loc:/AwsLambdaDemo})
 => 【プロジェクト名】/build/distributions 配下に zip ファイルを確認
     (今回は「AwsLambdaDemo/build/distributions/AwsLambdaDemo.zip」)

[4-3] [4-2]のZIPファイルを Amazon S3 上にアップロードする(URLをメモっとく)

注意:ZIPファイルの容量

 * 作成したZIPファイルが大きい(10MB)場合、S3にZIPファイルをあげる必要があることに注意
  => 画面をみてみれば、
    「10MBより大きいファイルの場合は、S3からのアップロードを検討して下さい」と表示されている

# ここで、まず、はまった...

 5)Lambdaファンクションを登録
http://engineer.recruit-lifestyle.co.jp/techblog/2016-11-22-serverless-architecture-lambda/

が参考になる 

[5-1] AWS にログインし、[Lambda]-[今すぐ始める]を選択し、以下を入力する

[5-2] 「設計図の選択」で「Black Function」を選択

[5-3] 「トリガーの設定」で「API Gateway」を選択し、「次へ」ボタン押下

[5-4] 「関数の設定」で以下を入力し、「次へ」ボタン押下
 ~~~~~
 + 名前 : 任意の名前(例「EC2StarterStopper」)
 + 説明 : 任意の名前(例「デモ」)
 + ランタイム : Java8
 + コードエントリタイプ : Amazon S3 からのアップロード(URLは[4-3]のS3のURLを指定) ... ※1
 + ハンドラ : com.sample.LambdaDemo::handleRequest (「パッケージ.クラス名::メソッド」で指定)
 + メモリ:256MB  ... ※2
 + タイムアウト:3分
 ~~~~~

※1 :コードエントリタイプについて

 * AWSマネジメントコンソールのAmazon Lambda上の画面で、
   直接ソースコードをアップロードできるのは、10MBまでの制限ある
 => 作成したコードの合計が10MBを超えるため、コードエントリタイプを変更する必要がある

※2 :メモリ変更について

 * デフォルトの 128MB だと、Out of memoryの例外が発生して実行できなかった
  => 最低、192MB は必要
  => ただし、メモリ増加すると、料金も変わるので注意

 ■ サンプル

 build.gradle

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile (
        'com.amazonaws:aws-lambda-java-core:1.2.0',
        'com.amazonaws:aws-lambda-java-events:1.3.0',
        'com.amazonaws:aws-java-sdk:1.11.248'
    )
}

task buildZip(type: Zip) {
    from compileJava
    from processResources
    into('lib') {
        from configurations.runtime
    }
}

build.dependsOn buildZip

 LambdaDemo.java

// JSON データで stopping : true(EC2停止) / false(EC2開始)で切り替えていくサンプル 
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;

public class LambdaDemo {
  public Object handleRequest(Request request, Context context) {
    LambdaLogger lambdaLogger = context.getLogger();
    lambdaLogger.log("Start!");

    String[] ec2InstanceIds = { "[インスタンスID1]", "[インスタンスID2]" };

    lambdaLogger.log("request.isStopping : " + request.isStopping());
    final AmazonEC2 amazonEc2 = AmazonEC2ClientBuilder.defaultClient();
    if (request.isStopping()) {
      StopInstancesRequest stopInstancesRequest = new StopInstancesRequest();
      stopInstancesRequest.withInstanceIds(ec2InstanceIds);
      amazonEc2.stopInstances(stopInstancesRequest);
    } else {
      StartInstancesRequest startInstancesRequest = new StartInstancesRequest();
      startInstancesRequest.withInstanceIds(ec2InstanceIds);
      amazonEc2.startInstances(startInstancesRequest);
    }

    lambdaLogger.log("DONE!");
    return "DONE!!";
  }
}

 Request.java

package com.sample;

public class Request {
  private boolean isStopping;

  public boolean isStopping() {
    return this.isStopping;
  }

  public void setStopping(boolean isStopping) {
    this.isStopping = isStopping;
  }
}

 テスト

Case1 : EC2を開始させる

{
  "stopping" : "false"
}

Case2 : EC2を停止させる

{
  "stopping" : "true"
}

 参考文献

https://qiita.com/toshihirock/items/80d61813dbf4a8efbd4d
https://dev.classmethod.jp/cloud/aws/ec2-lambda-auto-startstop-java/
https://qiita.com/toshihirock/items/93870fd9eca1bd0b9075

 公式サイト

.zip デプロイパッケージの作成 (Java)
http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/create-deployment-pkg-zip-java.html
Amazon EC2 インスタンスの管理
http://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/examples-ec2-instances.html
https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/StartStopInstance.java

 関連記事

Lambda ~ 基礎知識編 ~
https://dk521123.hatenablog.com/entry/2017/04/05/235618
Lambda ~ Java / EC2 を取得する ~
https://dk521123.hatenablog.com/entry/2017/12/24/232542
Lambda でハマったこと
https://dk521123.hatenablog.com/entry/2017/12/16/231714