Serverless Java Containerをやっていく
きっかけ
AWS Lambdaちからが欲しい…!というわけでAlexaスキルをちょいちょいやっていたけど、これではギョーミングLambdaちからが育たない…というわけで
Serverless Java ContainerでギョーミングLambdaをやっていこう。
Serverless Java Containerって?
コレダッ!
https://github.com/awslabs/aws-serverless-java-container
といってもわけわかんないです。
ReadMe見ただけでどんなものなのかわかる人いますけど、どうなってんですかね。
https://github.com/awslabs/aws-serverless-java-container/wiki
AWS LambdaとAmazon API Gatewayを使用して、Spring、Jersey、またはSparkアプリケーションを簡単に実行できます。
解説動画もあるよ!
わかりやすい…ありがてぇ…
サーバレスで王道 Web フレームワークを使う方法|AWS Summit Tokyo 2017 - YouTube
サーバレスでAPI作り出すとLambdaがとんでもない量になるので、Spirngとかで作りたくなる気持ちよくわかる。
Spring Bootのクイックスタートを試す
ご丁寧にSpring Bootでのチュートリアルがあるのでやっていきましょう。 Quick start Spring Boot · awslabs/aws-serverless-java-container Wiki · GitHub
クイックスタートを試す(その通りにやるとは言ってない)
そのままサンプルプロジェクトをcloneしてきて手順通りやるのもよいのですが、せっかくなので自分で作りましょう。
そっちのほうがお勉強になりますからね。
というわけで、いつも通り、Spring Initializrでプロジェクトを作成。
https://start.spring.io/
依存はWeb
とDevTools
を入れました。
build.gradleに例のライブラリを追加。
compile('com.amazonaws.serverless:aws-serverless-java-container-spring:1.1.4')
Lambdaのハンドラを作る
Spring部分にリクエストを送るハンドラを作る。
ハンドラ
class StreamLambdaHandler : RequestStreamHandler { private var handler: SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse>? = null init { try { handler = SpringLambdaContainerHandler.getAwsProxyHandler(LambdaconteinerApplication::class.java) } catch (e: ContainerInitializationException) { // if we fail here. We re-throw the exception to force another cold start e.printStackTrace() throw RuntimeException("Could not initialize Spring framework", e) } } @Throws(IOException::class) override fun handleRequest(inputStream: InputStream, outputStream: OutputStream, context: Context) { handler!!.proxyStream(inputStream, outputStream, context) // just in case it wasn't closed by the mapper outputStream.close() } }
あとは、動作確認用のコントローラをつくる。
この辺はもうSpringの世界の話なのでなれたものですね。
@RestController class SpringController { @GetMapping("") fun printMessage(): String { return "こんにちは!" } }
デプロイしよう!
Lambda関数の作成と、モジュールをzipで固めてアップロード。
この辺Serverless Frameworkみたいにひゅーんとコマンド一発でできると良いんだけれども、方法がわからんのでAWSのコンソール画面から心を込めてアップロードしました。
20180912追記: コメントいただいたおかげで、Serverless Frameworkでもできました! 記事の最後に追記してます。
zipの固め方は過去にこのへんで書きました。
takeda-san.hatenablog.com
今回呼び出すハンドラは、com.example.lambdaconteiner.StreamLambdaHandler::handleRequest
。
動作確認のためのテストを作成します。
今回だとAPI Gateway AWS Proxy
を選んで、Controllerに合わせてリクエスト内容を編集します。
ルートにてGETでリクエストをうけとるので、こんな感じ。
"httpMethod": "GET",
"path": "/"
いざ、テスト。
{ "statusCode": 200, "headers": { "Content-Encoding": "UTF-8", "Content-Length": "18", "Content-Type": "text/html;charset=UTF-8" }, "body": "こんにちは!", "base64Encoded": false }
おー、やった。
ちゃんとログにもSpringのログが出てます。
がっつりバッチ処理とかはメモリとか処理時間の関係で無理かもですが、軽めのやつなら良いかも。
20180912追記:Serverless Frameworkでやっていく
コメントにてServerless Frameworkでやっていく方法を教えてもらったので、いざ実践。
(id:nkgrさんありがとうございます!)
sls create --template aws-java-gradle --path [プロジェクト名] cd [プロジェクトのフォルダ] gradle wrapper --gradle-version 4.9
gradleのwrapper作り直してるのはこの辺の話を参照。
んで、ソースコードをエイヤッとコピー。
あと、Spring Boot関連のgradle設定を移植、serverless.ymlのhandlerを自分で作ったクラスのFQCNで編集。
ビルドを通して、zipを生成したらレッツデプロイ。
sls deploy -v
無事Lambda関数ができたら、AWSのコンソールから動作確認。
{ "statusCode": 200, "headers": { "Content-Encoding": "UTF-8", "Content-Length": "18", "Content-Type": "text/html;charset=UTF-8" }, "body": "こんにちは!", "base64Encoded": false }
やった、次からデプロイが高速でできるぞ。
未来を感じる。