Help us understand the problem. What is going on with this article?

Google App EngineのJava 11アプリをGradleでビルドする(Ktor + Gradle Kotlin DSL)

姉妹記事: Spring Boot版

この記事では、Google App EngineのJava 11ランタイムを使うアプリケーションをGradleでビルド・デプロイする方法を解説します。

この構成は意外と正確な情報がありません。App Engine Java 11ランタイムのサンプルコードはMavenが使われています。Gradleを使うドキュメントもあるものの、プラグインのバージョンが古かったり、不要なはずのwarの設定があったりします。

さらにGradle Kotlin DSLを使う場合の詰まりどころもあるので、Ktor + Gradle Kotlin DSLのGradleプロジェクトをデプロイするまでをまとめておきます。

前提

環境

  • macOS: 10.14.6
  • Ktor: 1.2.4
  • Gradle: 5.6.2
  • Kotlin: 1.3.50

古い情報で混乱しないために知っておくと良いこと

  • Google App EngineのJava 11はStandard環境第2世代のランタイム。
    • 設定には appengine-web.xml ではなく app.yaml を使う。
    • Webアプリケーションコンテナではなく、jarとしてビルドしたものを実行するので、war関連の設定は不要。
  • Gradle 4.0以降では、Google App Engine Gradle plugin 2.xを使う。

手順

1. Ktor Project Generatorでプロジェクトをダウンロード

Ktor Project Generatorを開き、次の設定で「Build」してzipファイルをダウンロードします。

  • Gradle with Kotlin DSL project
  • Server Engine: Nett(デフォルト)
  • Ktor 1.2.4(デフォルト)

2. Gradleを5.xにアップグレード

ダウンロードしたZIPファイルを展開してみると、Gradleのバージョンが4.xとやや古いです。Kotlin DSLサポートはGradle 5.xで改善しているので、次のコマンドで最新版にアップグレードしておきます。

./gradlew wrapper --gradle-version 5.6.2

3. routingを作成して動作確認

動作確認のため src/Application.kt に次のようにroutingを追記します。

Application.kt
package com.example

import io.ktor.application.*
import io.ktor.response.*
import io.ktor.request.*
import io.ktor.routing.get // 追加
import io.ktor.routing.routing // 追加

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    routing { // 追加
        get("/") {
            call.respondText("Hello, Ktor!")
        }
    }
}

次のコマンドで起動します。

./gradlew run

http://localhost:8080 にアクセスして、 Hello, Ktor! と返ってくることを確認します。

4. Gradleで実行可能なFat Jarを作る

App EngineのJava 11ランタイムでは、java -jar <jarファイル>のような形で実行するので、生成するjarファイルにはMain-Classのマニフェストと依存ライブラリを含める必要があります。デフォルトでは実行できないjarファイルが生成されてしまうため、Gradle Shadowプラグインを使ってfat jarを作ります1

build.gradle.kts に次の設定を追記します。

build.gradle.kts
plugins {
    application
    kotlin("jvm") version "1.3.50"
    id("com.github.johnrengelman.shadow") version "5.1.0" // 追加
}

// ...

tasks.assemble {
    dependsOn(tasks.shadowJar) // assembleの依存タスクとしてshadowJarを実行する。
}

tasks.shadowJar {
    archiveClassifier.set("") // fat jarを単独のjarと同じ名前にして上書きする。
}

./gradlew buildを実行した後に、次のコマンドで起動できることを確認しておきます。

java -jar ./build/libs/ktor-demo-0.0.1-SNAPSHOT.jar

5. Google App Engine Gradle pluginを追加

Google App Engine Gradle pluginを使うために、build.gradle.kts に次の設定を追加します。

build.gradle.kts
plugins {
    application
    kotlin("jvm") version "1.3.50"
    id("com.github.johnrengelman.shadow") version "5.1.0"
    id("com.google.cloud.tools.appengine") version "2.1.0" // 追加
}

これだけだとプラグインをロードできないので、 settings.gradle.kts に次の設定を追加します。この設定については、 https://stackoverflow.com/a/48510049 を参照してください2

settings.gradle.kts
pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
    }
    resolutionStrategy {
        eachPlugin {
            if (requested.id.id == "com.google.cloud.tools.appengine") {
                useModule("com.google.cloud.tools:appengine-gradle-plugin:${requested.version}")
            }
        }
    }
}

6. app.yamlを追加

トップディレクトリにapp.yaml を次の内容で作成します。この設定はサンプルコードのapp.yamlからjarファイルの名前だけ変更してます。

app.yaml
runtime: java11
instance_class: F2
entrypoint: 'java -Xmx32m -jar *.jar'

build.gradle.kts に次の設定を追記します。

build.gradle.kts
appengine {
    stage {
        setAppEngineDirectory(".") // app.yamlをトップディレクトリに置く
    }
}

次のコマンドで、デプロイ用の成果物を作成できることを確認します。

./gradlew appengineStage

次のように build/staged-appapp.yaml と jarファイルができていればOKです。

$ ls build/staged-app/
app.yaml            ktor-demo-0.0.1-SNAPSHOT.jar

7. Google App Engineにデプロイ

build.gradle.kts に次の設定を追加します。これらの設定は、プロジェクトIDをgcloudコマンドで設定済みのものにし、バージョンを自動生成するという意味なので、明示的に他の値にしても構いません。

設定についてはGoogle App Engine Gradle pluginのUser Guideを参照してください。

build.gradle.kts
appengine {
    stage {
        setAppEngineDirectory(".") // app.yamlをトップディレクトリに置く
    }
    deploy { // 追加
        projectId = "GCLOUD_CONFIG"
        version = "GCLOUD_CONFIG"
    }
}

次のコマンドでデプロイします。

./gradlew appengineDeploy

https://<プロジェクトID>.appspot.com にアクセスして、 Hello, Ktor! と表示されたら成功です。

なお gcloud コマンドでデプロイしたい場合は、 ./gradlew appengineStage && cd build/staged-app/ && gcloud app deploy とすればOKです。

まとめ

以上でデプロイまで完了です。この記事の実行結果のコードは次のリポジトリにあります。
https://github.com/orangain/appengine-java11-gradle-ktor

参考文献


  1. Spring Bootプロジェクトでは、Spring BootプラグインのbootJarタスクがやってくれるので気にしなくて良いです。 

  2. https://github.com/GoogleCloudPlatform/app-gradle-plugin#how-to-usehttps://stackoverflow.com/a/55075378 のようにbuildscriptapplyを使う方法もありますが、Kotlin DSLではappengine {...}と書けなくなってしまい、代わりに configure<AppEngineAppYamlExtension> {...} と書く必要があります。 

  3. https://cloud.google.com/appengine/docs/standard/java11/gradle-reference にもリファレンスがありますが、projectId が古い project のままになっていたして、やや古いようです。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした