業務でLambdaを使用してたんですが、最初は盲目的にPython使ってました。しかし自分以外が使う場合の学習コストとメンテナンス性を考慮すると普段使っていないPythonはどうもよろしくない。というわけで普段使っているKotlinに移行する + ServerlessFrameworkを使うことにしました。その時の備忘録。
下準備
Kotlin projectを作成する
端折ります。この辺を見るといいかと。
Getting Started with IntelliJ IDEA - Kotlin Programming Language
Serverless Framework をインストール
- npmでインストールするので先にインストールしてください
- 自分はnodebrewを使いました。
brew install nodebrew
- インストール
cd hogeProject
npm install -g serverless
Gradle で shadowJar ビルドの設定
shadowJarとはなんぞや?
Gradle Shadowのことです(説明になってない)。ざっくりいうとShadowというpluginを使ってFatJarを作れます。
Lambdaにデプロイする際に、普通に gradle build してデプロイすると依存関係に追加したライブラリが含まれません。含まれない状態でもデプロイできますが、ライブラリがないので実行時エラーになります。
それを防ぐためにライブラリも含めて jar を作っちゃおうということです。
これで出来上がった jar を FatJar といいます。
実装
buildscript {
ext {
kotlinVersion = '1.3.50'
}
repositories {
mavenCentral()
/* == 追記 == */
maven { url "https://plugins.gradle.org/m2/" }
/* ========== */
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
/* == 追記 == */
// shadow plugin
classpath "com.github.jengelman.gradle.plugins:shadow:2.0.1"
/* ========== */
}
}
apply plugin: 'kotlin'
/* == 追記 == */
apply plugin: 'com.github.johnrengelman.shadow'
/* ========== */
repositories {
mavenCentral()
/* == 追記 == */
maven { url "https://plugins.gradle.org/m2/" }
/* ========== */
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
/* == 追記 == */
implementation 'com.amazonaws:aws-lambda-java-core:1.1.0'
implementation 'com.amazonaws:aws-lambda-java-events:2.0.2'
/* ========== */
}
compileKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
jvmTarget = '1.8'
}
}
/* == 追記 == */
build.dependsOn shadowJar
/* ========== */
- shadow plugin を依存関係に追加してます。
-
build.dependsOn shadowJar
でビルド時に shadowJar を実行するようにしてます。こうしないと build → shadowJar実行を毎回やらないといけないので、少し楽になります(気がする)
Lambda関数の実装
package jp.co.valus.sample
class HogeHandler : RequestHandler<Map<String, Any>, Unit> {
override fun handleRequest(input: Map<String, Any>, context: Context) {
LOG.info(input.toString())
// do something
}
}
- RequestHandler を implements する。
- Lambdaが実行されるときに handleRequest がコールされるので、ココを起点に実装していく
serverless.yml の実装
AWSにDeployするための設定を書いていきます。わかりやすいところは説明を省いています。内容が違っていたら指摘してください。
公式はこのへん → Serverless Variables
service: hoge
provider:
name: aws
runtime: java8
stage: ${opt:stage, self:custom.defaultStage}
region: ap-northeast-1
memorySize: 512
iamRoleStatements:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource: arn:aws:lambda:*:*:function:${self:custom.process}
custom:
defaultStage: dev
settings: ${file(./variables-${self:custom.stage}.yml), file(./variables-dev.yml)}
region: ${self:provider.region}
stage: ${opt:stage, self:provider.stage}
prefix: ${self:custom.stage}-${self:service}
package:
artifact: ./build/libs/hoge-1.0.jar
functions:
worker:
timeout: 30
handler: jp.co.valus.sample.HogeHandler
name: ${self:custom.prefix}-worker
vpc:
securityGroupIds:
- ${self:custom.settings.securitygroup}
subnetIds:
- ${self:custom.settings.subnet}
environment:
url: ${self:custom.settings.db.url}
username: ${self:custom.settings.db.username}
password: ${self:custom.settings.db.password}
events:
- schedule: rate(1 minute)
service: hoge
自分の作る Service Name をここに記述します
provider:
後述する function:
で継承できる設定を記述。 Lambda function を複数書く場合、共通する設定をここに記述できる。
今回は aws の ap-northeast-1 リージョンに java8 ランタイム環境で メモリ512MB を指定して、 iamRoleStatements で設定した権限をもたせてデプロイするといった形で書いてある。
stage: ${opt:stage, self:custom.defaultStage}
環境(staging, productionなど) の指定をしている。${} 内は左辺がコマンド引数、左辺がなければ右辺の値が代入される。
環境を指定しているのは各環境で外出しした設定ファイルを読み替えるため。
custom:
カスタム値を記載。ほとんどは環境(stagingとか)毎に名前を変えるために使っているが、settings の項目だけ、外部に置いてある設定ファイルの内容を import するようになっている。
settings: ${file(./variables-${self:custom.stage}.yml), file(./variables-dev.yml)}
アクセスは settings.db.url といった形で行う。
以下のような設定ファイルを参照している。
db:
url: jdbc:mysql://localhost:3308/hoge?useSSL=false&autoReconnect=true
username: hoge
password: 12345678
securitygroup: sg-0xxxxxxxx
subnet: subnet-0xxxxxxxx
package:
デプロイする FatJar を指定。
functions:
デプロイする Lambda 関数をここに記載していく。
-
worker:
Function のタグのようなもの -
handler:
Lambda 関数が呼び出す対象をここで指定する。先に書いた RequestHandler を継承したクラスである必要がある。 -
vpc:
AWS 上で設定したVPCのIDを指定。ここで指定した securityGroup と subnet でLambda が動くので適当に指定したのが private subnet だったりすると外のネットワークに出れなくて、おや?となる。 -
environment:
環境変数を設定できる。DBへの接続設定を settings から代入している。 -
events:
起動イベントを指定できる。- schedule: rate(1 minute)
で一分毎にLambda関数が起動される。
デプロイする
以下のコマンドを打って、クリーンビルドして FatJar 作成 → デプロイ する
./gradlew clean build && sls deploy —stage [環境を指定] —aws-profile [※awsのprofileを指定]
※ aws-cli がインストールされていて、ログインできる前提です。
※ 特に profile 設定してない場合は最後の値は不要です。