Yoshi.dev

技術系の趣味、またはやった仕事やそこから学んだことを忘れないために

【QUARKUS】KotlinとGradleでサンプル作ってネイティブ起動するところまで

はじめに

QUARKUS触ってみたいなーと前々から思っていたので、KotlinとGradleを使ったQUARKUSのサンプルを作ってみました QUARKUSのドキュメントではmavenのほうが情報が厚そうだったのですが、pom.xml書きたくない、スクリプトで依存性管理したいと思ったのでGradleを選択しました とりあえず今回はネイティブイメージをビルドするところまでです また、自分はmacを使っているのでmacユーザー向けに書いていきます

作成したコードのリポジトリはこちらになります https://github.com/yoshi10321/sample-quarkus-app

GraalVMのインストール

まずGraalVMをインストールします https://github.com/oracle/graal/releases macの場合 graalvm-ce-darwin-amd64-{バージョン名}.tar.gz というファイルをダンロードして解凍します

解凍したディレクトリを /Library/Java/JavaVirtualMachines に移動しておきます

/usr/libexec/java_home -V コマンドを叩くとインストールしてあるJavaのバージョンが見れます GraalVMがあればOK

環境変数にセットしてGraalVMを使うようにします

export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
export PATH=$JAVA_HOME/bin:$PATH

次にネイティブイメージ作成用にnative-imageツールをインストールしておきます

gu install native-image

ここまでやったらGraalVMのインストールは完了です

Gradleプロジェクトの作成

mavenだと便利なQUAKUSプロジェクト作成用のコマンドが用意されているようですが、現状Gradleではまだそういった便利なものは用意されてなかったので自分で作っていきます

まず好きなディレクトリを作成してそこに移動しておきます

mkdir sample-quarkus-app
cd sample-quarkus-app

下記のコマンドでgradleのkotlinプロジェクトが作成できます

gradle init --type=kotlin-application

QUARKUSの設定を追加していく

まずQUARKUSのGradle pluginがまだGradle Plugin Portalに上がってないから./settings.gradle.ktsに下記のコードを追加します

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
    resolutionStrategy {
        eachPlugin {
            if (requested.id.id == "io.quarkus") {
                useModule("io.quarkus:quarkus-gradle-plugin:${requested.version}")
            }
        }
    }
}

次にbuild.gradle.ktsの中身はこんな感じになりました

import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet

plugins {
    // Apply the Kotlin JVM plugin to add support for Kotlin on the JVM.
    id("org.jetbrains.kotlin.jvm").version("1.3.31")
    id("org.jetbrains.kotlin.plugin.allopen") version "1.3.41"
    java
    id("io.quarkus") version "0.19.1"
}

allOpen {
    annotation("javax.ws.rs.Path")
    annotation("javax.enterprise.context.ApplicationScoped")
    annotation("sample.quarkus.app.MyAnnotation")
}

repositories {
    jcenter()
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation(enforcedPlatform("io.quarkus:quarkus-bom:0.19.1"))
    implementation("io.quarkus:quarkus-resteasy")
    implementation("io.quarkus:quarkus-resteasy-jsonb")
    implementation("io.quarkus:quarkus-kotlin")
    testImplementation("org.jetbrains.kotlin:kotlin-test")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
    testImplementation("io.quarkus:quarkus-junit5")
    testImplementation("io.rest-assured:rest-assured:3.1.0")
}

quarkus {
    setSourceDir(project.projectDir.resolve("src/main/kotlin").absolutePath)
    setOutputDirectory(project.projectDir.resolve("build/classes/kotlin/main").absolutePath)
}

kotlin.sourceSets["test"].kotlin.srcDirs("test")

build.gradleの設定で自分が少しハマったところを書いておくと

  • sourceDirを設定しないと./gradlew quarkusDevで起動した時にエラーが発生します
  • implementation("io.quarkus:quarkus-resteasy-jsonb")
    これを入れないと
@GET
@Produces(MediaType.APPLICATION_JSON)
fun hello() = Greeting("hello")

このコードのようなjsonフォーマットでレスポンスを返すときのjsonシリアライズでコケました

  • implementation("io.quarkus:quarkus-kotlin")
    これを入れないとkotlinで書いたコードのホットリロードがうまく動かなかったです
  • kotlinのクラスはデフォルトでfinalクラスになってしまうのでallopenプラグインを使ってopenにします。ただなぜかApplicationScopedアノテーションを付けたクラスでうまく効いてくれなかったので、別途手動でopenをつけたりもしました。(原因調べきれてないです、すいません)

下記のコマンドで起動することで、ホットリロードが有効な状態で起動できます

./gradlew quarkusDev

ブラウザでlocalhost:8080/helloにアクセスするとjsonのレスポンスが返ってくるのが確認できます

Kotlinのコードはgithubの方を参照していただければと思います https://github.com/yoshi10321/sample-quarkus-app

ネイティブイメージのビルド

環境変数GRAALVM_HOMEをセットしておく必要があります macの場合は下記のように設定します

export GRAALVM_HOME=$HOME/Development/graalvm/Contents/Home/

docker向けにネイティブビルドする場合は下記のコマンドを叩きます

./gradlew buildNative --docker-build=true

実際にDockerにデプロイしていきます Dockerfileを作成して

FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY build/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

下記のコマンドでDocker build&runしていきます

docker build -f Dockerfile -t sample/quarkus-app .
docker run -i --rm -p 8080:8080 sample/quarkus-app
-> % docker run -i --rm -p 8080:8080 sample/quarkus-app
2019-07-21 16:50:38,190 INFO  [io.quarkus] (main) Quarkus 0.19.1 started in 0.013s. Listening on: http://0.0.0.0:8080
2019-07-21 16:50:38,191 INFO  [io.quarkus] (main) Installed features: [cdi, kotlin, resteasy, resteasy-jsonb]

0.013秒で起動したというログが確認できました。 Kotlinで書いたコードがこの速さで起動するのは感動ものです

終わりに

少しハマったところもありましたがQUARKUSのアプリケーションをKotlinとGradleを使ってネイティブ起動するところまでいけました ネイティブコードで実行することでJVMの起動が遅い問題が回避できるため、Kubernetes上で起動させたときのオートスケーリング時のパラメータ設定にそこまで気を使わなくても良くなるんじゃないかなということを期待しています 今後も特にQUARKUS, GraalVM周りの情報には期待していきたいですね。