きっかけ
Quarkusの存在を知ったのは2020年ごろ(たしか、日本語ドキュメントが公開された時期)だったと思うのだが、当時はまだ(というか今でも)Java + Gradle + SpringBootで開発することに不自由がなかったため、かるーくQuarkusのチュートリアルなプログラムを動かした程度で興味を失っていた。
その後、SpringBoot3がリリースされてGraalVM対応したり、生成AIが登場したり、マイクロサービス化が加速したりとかいろいろあって、JavaであってもSpringBoot以外のスキル(ArmeriaとかJetty/Jerseyとか)を求められることがとても多くなった。
これを機会に、Quarkusにも正式に入門しようと思って記事にまとめておく。主に自分向けの備忘録のつもりだが、だれかの役に立つかもしれないのでQiitaの記事として投稿することにした。
Quarkusって何?
最近はGeminiやGPTなどのAIが優秀なので、Quarkusの詳しい説明はAIに任せるとして、自分が理解したQuarkus登場までの時代背景はざっとこんな感じ
- 2013年
- Dockerが登場してコンテナ化が話題になる
- (JavaがJVMというVM上で動くという特性ゆえの利点が薄れ始める)
- 2014年
- マイクロサービスが提唱される
- SpringBootも登場。ビルドされたTomcat内包しているjarファイルだけでWebサービスが動くことに俺ビビる
- StrutsとかSpringFrameworkとかXML地獄だったのが嘘みたいに感じた記憶
- 依存するjarファイルをclasspathに設定してリリースドキュメントに別途必要なjarファイルを明示して・・・みたいなことが不要になって感涙した記憶
- 2015年 kubernetes登場
- コンテナオーケストレーションなどマイクロサービスに関係した技術が次々に登場する
- 一方で、JavaはSpringBootであれば1jarファイルになるのでコンテナ化しやすいけど起動遅いしリソースをバカ食いするからマイクロサービスとかには向いてないって言われてた
- PayaraMicroとかコンテナ化を意識したパッケージが登場し始めたのもこの頃だった気がする
- 2019年
- Quarkus登場。起動速くてメモリ最適化でコンテナ向きなJavaがついに実現
必要な環境
最近はasdfやmiseなどがあるので、開発ツールのバージョン管理やインストールが簡単になった。MacならHomebrewとか使ってもいいけど、とにかく以下をインストールする。
- OpenJDK 21
- Gradle 9
- Quarkus 3.26.3
GraalVM
今回はネイティブビルドで動作確認しないのでGraalVMは不要
Gradleでプロジェクト雛形作成
専用のCLIが提供されていて、quarkus
コマンドでプロジェクトの雛形を作成できるけど、デフォルトだとMavenが選択されてしまう。
quarkus create app --gradle-kotlin-dsl hello
などオプション指定でGradleで雛形を作ることもできるが、そもそも https://plugins.gradle.org/plugin/io.quarkus を導入するとquarkus
コマンドなしでも開発できるので、今回はGradleだけで雛形作ってみた。
$ mkdir sample
$ cd sample
$ gradle init --type java-application ## gradleのjavaアプリ雛形作成
> デフォルトのままEnter連打
$ tree .
.
├── app
│ ├── build.gradle.kts
│ └── src
│ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ └── example
│ │ │ └── App.java
│ │ └── resources
│ └── test ## 今回はテスト使わないので削除しておk
│ ├── java
│ │ └── org
│ │ └── example
│ └── resources
├── gradle
│ ├── libs.versions.toml
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
Gradle Plugin追加、依存パッケージ追加
https://plugins.gradle.org/plugin/io.quarkus に従い、Gradleでquarkus開発できるようになるプラグインを導入する。
依存ライブラリはbom
が提供されているのでこれを追加するのが簡単。JAX-RS
でHello Worldするのでquarkus-restも追加する。
plugins {
application
id("io.quarkus") version "3.26.3" // 追加
}
repositories {
mavenCentral()
}
dependencies {
implementation(enforcedPlatform("io.quarkus.platform:quarkus-bom:3.26.3")) // 追加
implementation("io.quarkus:quarkus-rest") // 追加
//// gradle initで生成されたものは使わないのでコメントアウト
// testImplementation(libs.junit.jupiter)
// testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// implementation(libs.guava)
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
//// gradle initで生成されたmainClassは使わないのでコメントアウト
// application {
// mainClass = "org.example.App"
// }
tasks.named<Test>("test") {
useJUnitPlatform()
}
コーディング
gradle initが生成したApp.java
は消して、JAX-RSなApp.java
をコーディングする。
package org.example;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/hello")
public class App {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello from Quarkus REST";
}
}
ビルド&実行
ネイティブビルドせずjavaで動かすなら
$ gradle clean assemble
$ java -jar app/build/quarkus-app/quarkus-run.jar &
$ curl http://localhost:8080/hello
Hello from Quarkus REST%
ネイティブビルドしたいとき
Quarkusを使うならネイティブビルドして爆速を経験したいはず。ただしネイティブビルドするにはGraalVMをインストールしなければならない。(GraalVMはJavaコードをビルドしてネイティブ実行ファイルを作ってくれるやつ)
ひとことでGraalVMといってもいろんなディストリビューションがあって、初見だと何がどう違うのかわからないし、ネイティブビルドできる環境を整えるってことは、ほぼC言語の開発環境と同等の依存ライブラリ群をインストールすることになって開発環境が汚れるので、ちょっと試すだけに支払う代償が大きすぎると思ったので今回はここでやめた。(Quarkusの"コーディング"に興味があるだけならここまで知っていれば十分)
それでもネイティブビルドしたいとき
と言いつつも、結局ネイティブビルドまでやってみたので、以下にネイティブビルドしてつまずいた項目をQ&A形式でまとめておく
- Q: GraalVMのディストリビューションは何を使えばいいの?
- A: Quarkus用のGraalVMとしてMandrelというディストリビューションが公開されているので、これを使うのがいい
- Q: Mandrelって別途apt/dnfでインストール必要なパッケージがたくさんあって環境汚したくないんだけど
- A: asdfを使っているなら
asdf list all java | grep mandrel
で探せばjdkと一緒に簡単きれいにインストールできる - A: Dockerがあればここで公開されているイメージでMandrelをコンテナで使える
- A: asdfを使っているなら
- Q: ネイティブビルドもGradleから実行したいんだけどどうすればいい?
- A:
buildNative
っていうタスクがあるからそれでビルドできる-
./gradlew buildNative
→./app/build/hello-1.0.0-SNAPSHOT-runner
が生成されているはず
-
- A:
- Q: ネイティブビルドしたものをDockerfileでCOPYしても
glibc
がないコンテナだと動かせないの嫌だ- A: glibcでなくmuslで動くように頑張っているみたい。だけどまだ実験的な段階で厳密なテストなしに使うのはやめといたほうがいい→ https://ja.quarkus.io/guides/building-native-image#build-fully-static-native-executables