2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWS Lambda 用の Java11 コードを docker-lambda 環境でローカル開発するメモ

Posted at

Docker に慣れちゃうと、別にインストールしても問題ないものまでコンテナ上で動かしたくなりません?特に更新が激しいものはアップデートの導入が面倒なので、つい Docker image を探しがち。

というわけで、AWS Lambda で実行する Java 11 コードを、docker-lambda を用いてローカル環境で開発・テスト実行させてみました。Docker 以外はインストール不要なので、気軽に試せて良い感じです。

ググってみても python や nodejs の説明ばかりヒットする気がしたので、簡単なメモとしてまとめておきます。

docker-lambda とは

docker-lambda は AWS Lambda 開発環境を Docker ベースで提供するものです。以下、概要部分を簡単に訳しておきますね。

インストールされているソフトウェアとライブラリ、ファイル構造と権限、環境変数、コンテキストオブジェクトと動作を含む「ライブ AWS Lambda 環境」をほぼ同じように複製するサンドボックス化されたローカル環境。ユーザーと実行中のプロセスも同じです。
image.png
docker-lambda を使用することで、同じ厳密な Lambda 環境で関数を実行し、ライブでデプロイしたときに同じ動作を示せます。AWS Lambda に存在するライブラリバージョンと同様にネイティブ依存関係をコンパイルし、AWS CLI を使用してデプロイすることもできます。

サンプルコードの導入

テスト用のフォルダ(ディレクトリ)を作成し、docker-lambda/examples/java/ にあるファイルを配置します。該当リポジトリ を丸ごと clone もしくは zip 形式でダウンロードして、該当部分だけをコピーすると楽でしょう。

サンプルコードのビルド

ダウンロードしたサンプルは Java のソースコード です。テスト用のフォルダに移動し、Docker コマンドでビルド(コードのコンパイル)を実施します。

docker run --rm -v $PWD:/var/task lambci/lambda:build-java11 gradle build

なお私は Windows 環境なので $PWD が使えないため、実際のフォルダ (今回は c:/work/java/docker-lambda) を指定しました。

docker run --rm -v c:/work/java/docker-lambda:/var/task lambci/lambda:build-java11 gradle build

問題無く実行されれば build フォルダが作成され、その中に幾つかのフォルダが生成されるはずです。この中の docker フォルダに、コンパイルされたクラスのバイトコードと、実行に必要なライブラリが格納されています。
image.png

サンプルコードの実行

作成された実行クラスは、build/docker/ フォルダ内にあります。以下のコマンドで実行してみます。

docker run --rm -v $PWD/build/docker:/var/task \
  lambci/lambda:java11 org.lambci.lambda.ExampleHandler \
  '{"some": "event"}'

Windows 環境では改行を使わず、JSON の指定方法も修正して、実際には以下のように実施しています。

docker run --rm -v c:/work/java/docker-lambda/build/docker:/var/task lambci/lambda:java11 org.lambci.lambda.ExampleHandler "{\"some\": \"event\"}"

AWS SDK API を利用してみる

サンプルの実行だけで終わるのも寂しいですので、S3 のバケット一覧を取得してみます。

サンプルコードの修正

AWSのガイド を参考に、まずは import 文を追加します。

src/main/java/org/lambci/lambda/ExampleHandler.java
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.Bucket;
import java.util.List;

そして handleRequest 関数の終わり (Return文の前) に以下のコードを追加します。

src/main/java/org/lambci/lambda/ExampleHandler.java
        logger.log("Your Amazon S3 buckets are:\n");
        final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
        List<Bucket> buckets = s3.listBuckets();
        for (Bucket b : buckets) {
            logger.log("* " + b.getName() + "\n");
        }

この段階でビルドを実施すると、S3 関連の SDK ライブラリが見つからずエラーになります。テスト用フォルダにある build.gradle にビルド用の設定(2行)を追加します。

build.gradle
dependencies {
    implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.99') // この行を追加
    implementation (
        'com.amazonaws:aws-lambda-java-core:1.2.0',
        'com.amazonaws:aws-lambda-java-events:2.2.7', // カンマ追加
        'com.amazonaws:aws-java-sdk-s3' // この行を追加
    )
}

これで先ほどと同じコマンドで、ビルドできるようになりました。

修正したサンプルコードの実行

さきほどと同様にコードを実行しようとすると、権限エラーになります。以下のように -e オプションで AWS_ACCESS_KEYAWS_SECRET_ACCESS_KEY の値を渡してあげましょう。

docker run --rm -v $PWD/build/docker:/var/task \
  -e AWS_ACCESS_KEY_ID=XXX -e AWS_SECRET_ACCESS_KEY=XXXXXX \
  lambci/lambda:java11 org.lambci.lambda.ExampleHandler \
  '{"some": "event"}'

Windows の場合は1行にまとめて、JSON 表記など修正して以下のように実行します。

docker run --rm -v c:/work/java/docker-lambda/build/docker:/var/task -e AWS_ACCESS_KEY_ID=XXX -e AWS_SECRET_ACCESS_KEY=XXXXXX lambci/lambda:java11 org.lambci.lambda.ExampleHandler "{\"some\": \"event\"}"

こんな感じで s3 バケットのリストが得られれば成功です。
image.png

AWS_ACCESS_KEYAWS_SECRET_ACCESS_KEY は、AWS でユーザーを作成して、その「認証情報」タブから作成・取得ができます。なんの権限もない新規ユーザーを作成し、開発対象である Lambda 関数と同じアクセス権限(ロールやポリシー)を与えて利用するのが良さそうです。

stay-open モードで開発する

4つのオプションを追加して、更に便利に開発していきましょう。

  • 環境変数 DOCKER_LAMBDA_STAY_OPEN=1 で API 待ち受けモードになる
  • -p 9001:9001 オプションで待ち受けするポートを指定する
  • 環境変数 DOCKER_LAMBDA_WATCH=1 でファイルの変更を監視し、サービスの再スタートを実施する
  • --restart on-failure Dockerオプションでエラー時に自動的に再起動する (Java 11では必須ではない)

以下のようなコマンド実行になります。

docker run -v $PWD/build/docker:/var/task \
  --restart on-failure \
  -e DOCKER_LAMBDA_WATCH=1 -e DOCKER_LAMBDA_STAY_OPEN=1 -p 9001:9001 \
  -e AWS_ACCESS_KEY_ID=XXX -e AWS_SECRET_ACCESS_KEY=XXXXXX \
  lambci/lambda:java11 org.lambci.lambda.ExampleHandler \
  '{"some": "event"}'

Windows の場合は以下のように実行します。

docker run -v c:/work/java/docker-lambda/build/docker:/var/task --restart on-failure -e DOCKER_LAMBDA_WATCH=1 -e DOCKER_LAMBDA_STAY_OPEN=1 -p 9001:9001 -e AWS_ACCESS_KEY_ID=XXX -e AWS_SECRET_ACCESS_KEY=XXXXXX lambci/lambda:java11 org.lambci.lambda.ExampleHandler "{\"some\": \"event\"}"

別なターミナル画面を開き、以下のように curl などでアクセスしてみましょう。

curl -d "{}" http://localhost:9001/2015-03-31/functions/myfunction/invocations

以下のように Return 文の内容 "Hello World!" が返ってくれば動作は成功です。ログは Docker を実行したほうのターミナルのほうに表示されています。
image.png

試しにソースコードを修正してビルドを実行すると、/build/docker フォルダの変更を感知して、サービスが自動的に再始動します。

おわりに

Docker 環境されあれば docker-lambda を用いてローカルで AWS Lambda 関数の開発を実施できます。好みのエディタでサクサク開発でき、テストも容易です。いろんなコードを書いて、試してみましょう!

それではまた。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?