Tutorial: Menjalankan & Membangun Aplikasi Quarkus di GraalVM (Ubuntu 24.04 LTS)
Quarkus dan GraalVM. Kombinasi keduanya menghadirkan ekosistem modern yang mampu menjawab tantangan cloud-native: startup dalam hitungan milidetik, konsumsi memori yang minimal, serta fleksibilitas untuk berjalan di berbagai lingkungan, mulai dari laptop pengembang hingga platform Kubernetes. Artikel ini akan memandu Anda langkah demi langkah membangun aplikasi Quarkus di Ubuntu 24.04 dengan GraalVM, sekaligus menyingkap alasan mengapa keduanya menjadi pasangan ideal bagi developer masa kini.
Proyek contoh: QYBoilerPlate (Repo Link branch: tut_qute_login)
OS: Ubuntu 24.04.1 LTS
Build Tool: Gradle
Dockerfiles: sudah tersedia di src/main/docker/
(Dockerfile.jvm
, Dockerfile.native
, dll.)
Siapkan dan Install paket build-essential:
1. Menjalankan Aplikasi Quarkus di GraalVM
Kenapa pakai GraalVM?
-
Optimisasi JIT lebih baik dibandingkan HotSpot biasa.
-
Bisa menghasilkan native image (Ahead-of-Time compilation).
-
Startup lebih cepat & footprint memori lebih kecil saat jadi native.
-
Mendukung polyglot (Java + JavaScript/Python, dll).
Instalasi GraalVM (rekomendasi: SDKMAN)
# Instal SDKMAN
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
# Cari GraalVM JDK 21
sdk list java | grep -i graal
sdk install java 21.0.2-graalce
sdk use java 21.0.2-graalce
Jalankan Quarkus di GraalVM
Cek hasil:
curl http://localhost:8080/hello
Kelebihan: mudah dipakai untuk dev, performa JVM meningkat, siap menuju native build.
2. Membangun JVM Docker Image untuk Quarkus
2.1 Build aplikasi Quarkus (JVM mode)
sdk install gradle 9.0.0
./gradlew build -x test
2.2 Contoh Dockerfile.jvm
FROM registry.access.redhat.com/ubi9/openjdk-21:1.21
ENV LANGUAGE='en_US:en'
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 build/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 build/quarkus-app/*.jar /deployments/
COPY --chown=185 build/quarkus-app/app/ /deployments/app/
COPY --chown=185 build/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
2.3 Build image
docker build -f src/main/docker/Dockerfile.jvm -t qyboilerplate:jvm .
2.4 Jalankan container
docker run --rm -p 8080:8080 \
-e QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://host.docker.internal:5432/qyboilerplate_db \
-e QUARKUS_DATASOURCE_USERNAME=postgres \
-e QUARKUS_DATASOURCE_PASSWORD=postgres \
qyboilerplate:jvm
Hasil: aplikasi jalan dalam container berbasis JVM. Cocok untuk environment production.
3. Membangun Native Image dengan GraalVM
3.1 Build native secara lokal (butuh RAM besar)
*bila ada unit test tak penting hapus saja dulu.
./gradlew build -Dquarkus.package.type=native
Hasil binary: build/<nama>-runner
Jalankan:
./build/qyboilerplate-1.0.0-SNAPSHOT-runner
3.2 Build native dengan container (lebih aman & konsisten)
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true
Apa yang dilakukan
- Gradle akan build project → compile Java → generate native binary dengan bantuan container (biasanya quay.io/quarkus/ubi-quarkus-mandrel-builder-image).
- Hasil akhirnya: file executable Linux (target/*-runner atau build/*-runner) ada di host machine kamu.
Kapan dipakai
- Kalau mau binary native langsung di host (misalnya untuk deployment tanpa Docker).
- Atau step awal sebelum bikin image Docker.
- Tidak menjalankan container hasil build, hanya menghasilkan file binary.
3.3 Contoh Dockerfile.native
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.5
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root --chmod=0755 build/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
Build & run:
Build
docker build -f src/main/docker/Dockerfile.native -t qyboilerplate:native .
Apa yang dilakukan
- Docker membangun image baru menggunakan Dockerfile.native.
- Biasanya Dockerfile.native akan:
- Copy binary native hasil build (*-runner) ke dalam image base minimal (misal ubi-minimal atau alpine).
- Set entrypoint untuk menjalankan binary itu.
- Output: sebuah Docker image bernama qyboilerplate:native.
Kapan dipakai
- Kalau target deploy kamu pakai container (Kubernetes, Docker Compose, dll).
- Biasanya step ini dilakukan setelah step pertama (karena butuh binary native yang sudah jadi).
run
docker run --rm -p 8080:8080 qyboilerplate:native
Dicase saya error karena container tidak satu network |
Oke, jelas problemnya dari error log:
Connection to localhost:5432 refused.
Check that the hostname and port are correct
and that the postmaster is accepting TCP/IP connections.
Aplikasi Quarkus di dalam container mencoba koneksi ke localhost:5432.
localhost di dalam container ≠ localhost di host machine.
Itu merujuk ke container itu sendiri, bukan ke container PostgreSQL.
Solusi setup saja network yang sama dan assign pada container lalu sesuaikan properties di project nya.
Ringkasan Error di atas
-
localhost
hanya valid kalau Quarkus & Postgres jalan di host yang sama. -
Kalau dua-duanya di container → pakai service name / container name di
JDBC_URL
. -
Kalau Postgres di host → pakai
host.docker.internal
(atau--add-host
di Linux).
Cara handle Error di atasdi bahas disini terkait docker.
Buat Network di Docker
$ docker network create quarkusnet
Tambahkan Network di Docker Container (Mine: lucid_chatterjee)
$ docker network connect quarkusnet lucid_chatterjee
Update application.properties
quarkus.datasource.jdbc.url=jdbc:postgresql://lucid_chatterjee:5432/qyboilerplate_db
Jalankan
docker run --rm --network quarkusnet -p 8080:8080 -e QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://lucid_chatterjee:5432/qyboilerplate_db -e QUARKUS_DATASOURCE_USERNAME=postgres -e QUARKUS_DATASOURCE_PASSWORD=postgres qyboilerplate:native
Selesai
Dengan memanfaatkan Quarkus dan GraalVM, kita bukan hanya membangun aplikasi Java yang modern, tetapi juga mengoptimalkannya untuk kebutuhan cloud-native dengan performa startup yang cepat, jejak memori yang ringan, serta fleksibilitas deployment di berbagai lingkungan.
Langkah-langkah yang telah dibahas — mulai dari setup environment, menjalankan aplikasi di JVM, membangun Docker image, hingga menghasilkan native image — menunjukkan betapa kuatnya ekosistem ini dalam menjawab tantangan pengembangan perangkat lunak masa kini.
Semoga panduan ini menjadi pijakan awal untuk eksplorasi lebih dalam. Karena pada akhirnya, teknologi hanyalah alat; nilai sejatinya terletak pada bagaimana kita memanfaatkannya untuk menghadirkan solusi nyata yang bermanfaat.
Comments
Post a Comment