LoginSignup
49
8

Quarkus+CloudRunで作る爆速アプリケーション

Last updated at Posted at 2023-12-20

はじめに

Retail AI Adventurers Advent Calendar 2023の21日目の投稿です。
昨日は@t-hiroyukiさんの「M1チップ搭載のMac & RancherDesktop環境下におけるTestcontainersを使用したテスト失敗の原因の考察とその解決策」でした。
彼と話していると何だか癒されます。

自己紹介

Retail AIの基盤チーム(Infrastructure Systems Development Group)に所属しています。
興味がある方は、以下を参照下さい。
会社HP:https://www.retail-ai.jp/
採用ページ:https://recruit.jobcan.jp/retail-ai/
今年に入って自作キーボードを5つ(ErgoArrows、CHARYBDIS、keyball61、keyball39、killer whale)購入し、現在2個故障中、1つ未作成です。

目次

  • 背景
  • Quarkusについて
  • Kotlinでの実装
  • アプリケーションの作成
  • DockerImageの作成
  • CloudRunにデプロイ
  • まとめ

背景

4〜5ヶ月前だったか社内プロジェクトにおいて、アサインされて初めて知りました。
「かーかす?何ですか、それ?」
PHP歴10数年の私が、それ以来簡単なアプリを作るときに「Quarkusで作るにはどのJavaのライブラリ・・・」なんて考えるようになるとは。

直近では自分用にバーコード(JANコード)やQRコードを生成するものを作りました。

Quarkusについて

Quarkusは、Java用のフルスタックKubernetesネイティブフレームワークで、Javaのマイクロサービスアプリケーションの開発と運用に特化しています。その主な特徴や他のフレームワークとの違いについて以下の点が挙げられます。

1. コンパイル時最適化: Quarkusはビルド時に多くの処理を行うことで、ランタイムのオーバーヘッドを減少させます。これは、特にコンテナ化されたマイクロサービスやサーバレス環境でのパフォーマンスを向上させるために重要です。
2. メモリ使用量の削減: Quarkusアプリケーションは、従来のJavaアプリケーションに比べてメモリ使用量が少なくなる傾向があります。これは、特にリソースが限られている環境で有利です。
3. 起動時間の短縮: Quarkusは起動時間が非常に短いことで知られており、これもサーバレス環境やマイクロサービスアーキテクチャに適しています。
4. 拡張性と開発者フレンドリー: Quarkusは、多数のライブラリやフレームワークと統合することが可能で、開発者が既存の知識やコードベースを活用できるように設計されています。
5. Kubernetesネイティブ: QuarkusはKubernetesとの統合を重視しており、Kubernetes環境でのデプロイや管理が容易です。

他のフレームワークと比較して、Quarkusは特にコンテナ化された環境やマイクロサービスアーキテクチャに最適化されている点が大きな優位性です。従来のJava EEやSpring Bootなどのフレームワークに比べて、より効率的なリソース利用と高速なスタートアップを実現しています。これにより、クラウドネイティブアプリケーションの開発において重要な要素であるスケーラビリティとパフォーマンスが強化されています。


Kotlinでの実装

KotlinはJava Virtual Machine(JVM)上で動作するモダンなプログラミング言語であり、Javaとの互換性を持っているため、Quarkusのフレームワーク内で効果的に利用することができます。

QuarkusでKotlinを使用する利点は以下の通りです

互換性: KotlinはJavaとの高い互換性を持っており、既存のJavaライブラリやフレームワークをそのまま使用できます。これにより、Quarkusの機能とKotlinの利点を組み合わせて使用することが可能です

簡潔な構文: Kotlinは簡潔で読みやすい構文を持っており、開発者の生産性を高めます。Quarkusと組み合わせることで、開発プロセスがさらに効率的になります。

安全なコード: Kotlinはnull安全な言語設計をしており、NullPointerExceptionのような一般的な問題を回避するのに役立ちます。

コルーチンによる非同期処理: Kotlinのコルーチンは非同期プログラミングを簡単に実現します。これは、リアクティブプログラミングやマイクロサービスアーキテクチャにおいて特に有用です。

QuarkusはこれらのKotlinの特徴を活用し、クラウドネイティブJavaアプリケーションの開発をさらに強化します。したがって、Quarkusフレームワークを使用してKotlinでアプリケーションを作成することは、非常に有効な選択肢です。

SpringBoot3との比較

Javaのフレームワークで有名なSpringBoot3と何が違うのか、調べた範囲で比較します。

Dockerfileの自動生成

SpringBootでDockerfileは手動で生成するか、ビルドプラグインを用いる方法のようです。
OCI イメージのパッケージ化

Quarkusではビルドを実行するとDockerfileが4種類作成されます。
このあたりがクラウドファーストな感じがしますね。

  • legacy-jar
  • jvm
  • native-micro
  • native

コンテナイメージの軽量化

先ほどの4つのDockerファイルの中身を確認して、使用しているイメージをそれぞれ調べました。

  • legacy-jar、jvm
docker pull registry.access.redhat.com/ubi8/openjdk-17:1.16  # 401.94MB
  • native
docker pull registry.access.redhat.com/ubi8/ubi-minimal  # 93.17MB
  • native-micro
docker pull quay.io/quarkus/quarkus-micro-image:2.0  # 28.4MB

Java17のイメージで他に例を出すと

gcr.io/distroless/java17-debian12:latest  #  225.17MB
eclipse-temurin:17-jdk-alpine             #  315.08MB
openjdk:17-jdk-slim                       #  407.74MB

Quarkusのnative-microのイメージ容量があまりにも軽量すぎます。

検証

terraformのコードはこんな感じで

# .tfenvの定数をインポート
variable "credentials" {}
variable "project_id" {}
variable "region" {}
variable "project_name" {}
variable "vpc_name" {}
variable "firewall_name" {}
variable "service_name" {}
variable "container_image" {}

# プロバイダの設定
provider "google" {
  credentials = var.credentials
  project     = var.project_id
  region      = var.region
}

# VPCの作成
resource "google_compute_network" "my_network" {
  name                    = var.vpc_name
  auto_create_subnetworks = false
}

# ファイアウォールの設定
resource "google_compute_firewall" "my_firewall" {
  name        = var.firewall_name
  network     = google_compute_network.my_network.self_link
  source_tags = ["web"]

  allow {
    protocol = "tcp"
    ports    = ["80", "443"]
  }
}

# Cloud Runの設定
resource "google_cloud_run_v2_service" "my_service" {
  name     = var.service_name
  location = var.region
  ingress  = "INGRESS_TRAFFIC_ALL"

  template {
    containers {
      image = var.container_image
    }
    timeout = "1s"
  }
}

data "google_iam_policy" "admin" {
  binding {
    role = "roles/run.invoker"
    members = [
      "allUsers",
    ]
  }
}

resource "google_cloud_run_v2_service_iam_policy" "noauth" {
  name        = google_cloud_run_v2_service.my_service.name
  location    = google_cloud_run_v2_service.my_service.location
  project     = google_cloud_run_v2_service.my_service.project
  policy_data = data.google_iam_policy.admin.policy_data
}

Qurakusのコード
https://github.com/satoshihiraishi/quarkus-helloworld
nativeでイメージを作成し、作成されたイメージは87.9MBでした。

SpringBootのコード
https://github.com/satoshihiraishi/springboot-helloworld
openjdk:17-jdk-slimを使用し、作成されたイメージは457.23MBでした。

スクリーンショット 2023-12-21 2.36.43.png
シンプルに「Hello World!」を表示するだけです。SprngBootはCLIで作成するとこの表示になりますが、Quarkusは異なったhtmlが出力されるので同じように合わせました。
それぞれのイメージを作成し、CloudRunにデプロイしてcurlコマンドで10秒毎に20回アクセスしました。

結果

Cloud Loggingから算出しています。

SpringBoot:平均 5.9 ms
スクリーンショット 2023-12-21 3.12.48.png

Quarkus:平均 5.2 ms
スクリーンショット 2023-12-21 3.14.20.png

比較対象が文字の出力だけなので、もうちょっと違いが出やすい題材にすればとか、
SpringBootのイメージもdistrolessを使えばもう少し早くなってQuarkus超えてたかも、
などの反省は次に活かしたいと思います。

まとめ

Quarkusいいよ。

次回

私が会社に自作キーボードを使ってるのを見て、凄く興味を持ってる@k-yoshigaiさんがGo言語について書く予定です。

49
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
8