Quarkus入門!GitHub ActionsでCI/CDパイプラインを構築して自動ビルドを実現する方法
生徒
「最近よく聞くQuarkusで開発を始めたんですけど、毎回手動でビルドしてテストするのが大変になってきました。自動化する方法はありますか?」
先生
「それはGitHub Actionsを使ってCI/CDパイプラインを構築するのが一番ですね。コードをプッシュするだけで、自動的にビルドやテストが走るように設定できますよ。」
生徒
「GitHub Actionsなら無料で始められそうですね!でも、Quarkus特有の設定とか難しそうで不安です。」
先生
「大丈夫です。Quarkusはモダンなフレームワークなので、GitHub Actionsとの相性も抜群です。基本的なワークフローの書き方から順を追って解説していきますね!」
1. QuarkusとGitHub Actionsを組み合わせるメリット
モダンなJava開発において、Quarkusは「Supersonic Subatomic Java」として知られ、その圧倒的な起動速度とメモリ効率の良さが注目されています。しかし、開発サイクルが速くなるにつれて、手動でのビルドやユニットテストの実行は大きな負担となります。ここで登場するのが、GitHubが提供する自動化プラットフォーム「GitHub Actions」です。
GitHub Actionsを導入することで、開発者がソースコードをリポジトリにプッシュ(push)したり、プルリクエスト(Pull Request)を作成したりするタイミングで、クラウド上の仮想マシンが自動的にJavaの環境を構築し、MavenやGradleを使用してアプリケーションをビルドします。これにより、変更によって既存の機能が壊れていないかを即座に確認できる「継続的インテグレーション(CI)」が実現します。
特にQuarkusはクラウドネイティブな開発を意識しているため、CI/CDパイプラインの中でコンテナイメージの作成や、ネイティブイメージのビルドまで自動化することが可能です。今回は、まず基本となるJava 21環境での自動ビルド設定をマスターしましょう。
2. 自動ビルドに必要なワークフローファイルの基本構成
GitHub Actionsの設定は、プロジェクトのルートディレクトリにある .github/workflows フォルダ内にYAML形式のファイルを作成することで行います。このファイルには、どのようなタイミングで(トリガー)、どのような処理を(ジョブ・ステップ)実行するかを定義します。
Quarkusプロジェクトの場合、Javaの開発環境(JDK)のセットアップと、ビルドツールであるMavenまたはGradleの実行が主なステップになります。GitHub Actionsには公式が提供する setup-java アクションがあり、これを利用することで簡単に最新のJava環境を用意できます。また、Mavenの依存関係をキャッシュする機能も備わっているため、二回目以降のビルド時間を大幅に短縮できるのが魅力です。
まずは、最もシンプルな「コードをプッシュした時にMavenビルドを実行する」設定ファイルの内容を見ていきましょう。この設定だけで、コンパイルエラーやテストの失敗を自動的に検知できるようになります。
# .github/workflows/build.yml
name: Quarkus CI Build
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: ./mvnw package
3. Maven Wrapperを活用した安定したビルド環境
Quarkusのプロジェクトを生成すると、標準で mvnw (Maven Wrapper)というファイルが含まれています。GitHub Actionsのパイプライン上でビルドを実行する際は、サーバーにインストールされているMavenを直接使うのではなく、このWrapperを使用するのがベストプラクティスです。理由は、開発者のローカル環境とCI環境でMavenのバージョンを完全に一致させることができるため、環境差異によるエラーを防げるからです。
CI環境で実行する際は、実行権限の付与が必要になる場合があります。多くの場合はリポジトリにコミットした時点で権限が維持されていますが、もしエラーが出る場合は chmod +x mvnw というコマンドをステップに追加することで解決します。また、Quarkusのビルドでは、依存ライブラリのダウンロードが多く発生するため、GitHub Actionsのキャッシュ機能を有効にすることが非常に重要です。これにより、毎回数分かかっていたビルドを数十秒まで短縮できる可能性があります。
4. Quarkusアプリケーションのユニットテスト自動化
自動ビルドの最大の目的の一つは、テストの自動実行です。Quarkusには @QuarkusTest という非常に強力なテストアノテーションが用意されており、これを利用したテストコードをGitHub Actions上で走らせることができます。ビルドコマンドである ./mvnw package を実行すると、デフォルトでテストも同時に実行されます。
ここで、テストが失敗した際の結果をGitHub上で確認しやすくする方法を紹介します。テストコード自体は標準的なJUnit 5で記述しますが、Quarkusが提供するモック機能などを活用することで、データベースや外部APIに依存する処理も効率よくテストできます。以下のコードは、挨拶を返すシンプルなリソースクラスのテスト例です。
package org.acme;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class GreetingResourceTest {
@Test
public void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello from Quarkus!"));
}
}
このテストをCI上で実行すると、次のような結果がコンソールに出力されます。もし期待値と異なる結果になれば、GitHub Actionsの画面上で赤色のアラートが表示され、マージをブロックすることができます。
[INFO] Scanning for projects...
[INFO] Running org.acme.GreetingResourceTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.5s
[INFO] Build Success!
5. ネイティブイメージビルドの自動化と注意点
Quarkusの真骨頂は、GraalVMを利用したネイティブイメージの生成です。これをGitHub Actionsで行う場合、通常のJavaビルド(JAR生成)よりも多くのCPUリソースとメモリ、そして長い時間を必要とします。GitHub Actionsの標準的なランナー(ubuntu-latest)でも実行可能ですが、タイムアウト制限やメモリ不足に注意が必要です。
ネイティブビルドを自動化するには、Mavenコマンドに -Dnative プロパティを追加します。しかし、全てのプッシュに対してネイティブビルドを行うと、一回あたり10分以上の時間がかかり、GitHub Actionsの無料枠をすぐに使い切ってしまう恐れがあります。そのため、特定のタグを打った時や、リリース用のプルリクエストが作成された時だけ実行するように条件分岐(if文)を設定するのが賢い運用方法です。
# ネイティブビルドを行う場合のステップ例
- name: Build Native Image
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
run: ./mvnw package -Dnative -Dquarkus.native.container-build=true
6. 環境変数とSecretを使用したセキュアなパイプライン
実際の開発では、データベースのパスワードや外部サービスのAPIキーなど、公開したくない情報をビルド時に使用することがあります。これらをYAMLファイルに直接書くのは絶対にNGです。GitHubのリポジトリ設定にある「Secrets and variables」機能を使いましょう。
例えば、ビルドしたJARファイルをDocker Hubにプッシュしたり、クラウドサービスにデプロイしたりする場合、認証情報が必要になります。Secretsに登録した値は、YAML内で ${{ secrets.MY_SECRET_KEY }} という形式で参照できます。これにより、ログにパスワードが表示されるのを防ぎつつ、安全に自動化処理を完結させることができます。Quarkus側でも、 application.properties 内で ${MY_ENV_VAR} のように記述しておくことで、CI環境から注入された値を柔軟に受け取ることが可能です。
package org.acme.config;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class ConfigService {
@ConfigProperty(name = "database.password")
String dbPassword;
public String getMaskedPassword() {
// CIから注入された機密情報を扱う例
return dbPassword.substring(0, 2) + "****";
}
}
7. マルチプロジェクトや高度なビルド戦略
大規模な開発になると、一つのリポジトリに複数のマイクロサービスが含まれる「モノリポジトリ」構成になることがあります。その場合、変更があったディレクトリのサービスだけをビルドするような制御が必要です。GitHub Actionsの paths フィルタを使うことで、特定のフォルダ内のファイルに変更があった場合のみワークフローを起動させることができます。
また、Quarkusは開発モード(Dev Mode)が非常に優秀ですが、CI環境ではあくまで本番に近い状態を確認するための「PRODプロファイル」での動作が基本となります。ビルドログを確認する際は、Quarkusがどのプロファイルで起動しているか、また意図したライブラリが正しくリンクされているかをチェックする癖をつけましょう。エラーが発生した際は、GitHub Actionsのログ画面で「Search logs」を使い、「ERROR」や「FAILURE」のキーワードで検索すると素早く原因を特定できます。
8. GitHub Actionsの実行結果を確認してトラブルシューティング
ワークフローをプッシュした後、正しく動いているかはGitHubの「Actions」タブから確認できます。緑色のチェックマークが付けば成功、赤色のバツ印なら失敗です。初心者が陥りやすいミスとして、 mvnw のパスが間違っていたり、Javaのバージョンがプロジェクトの pom.xml と一致していなかったりするケースがあります。
また、Quarkusのビルド中に発生する「依存関係の競合」は、ローカルでは再現しにくいことがあります。そのような場合は、CIのログに -X オプション(デバッグモード)を一時的に追加して、詳細なスタックトレースを確認するのが解決の近道です。自動化は一度設定してしまえば終わりではなく、ライブラリのアップデートやプロジェクトの成長に合わせて、継続的にメンテナンスしていくものだと心得ましょう。
package org.acme.status;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/status")
public class HealthCheckResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String check() {
// CI/CDの疎通確認用などに使えるエンドポイント
return "Application is running smooth!";
}
}
このエンドポイントを定義しておけば、デプロイ後のパイプラインで curl コマンドを使って、アプリケーションが正常に起動したかを自動チェック(ヘルスチェック)するステップを追加することも可能です。こうした一工夫が、システムの信頼性を大きく向上させます。
9. コンテナイメージの自動生成とレジストリへの保存
Quarkusには quarkus-container-image-docker や quarkus-container-image-jib といった拡張機能があり、MavenビルドのついでにDockerイメージを作成することができます。GitHub Actionsのワークフロー内に、Dockerログインのステップとビルドコマンドを組み合わせることで、最新のイメージをGitHub Container Registry (GHCR) などに自動保存するパイプラインが完成します。
これにより、開発者は「コードを書いてプッシュするだけ」で、最新版のアプリケーションがコンテナとして実行可能な状態で用意されるという、究極の自動化環境を手に入れることができます。コンテナベースのデプロイは、KubernetesやAWS ECS、Azure Container Appsといったモダンなインフラとの相性が非常に良いため、Quarkus開発者ならぜひ習得しておきたいスキルです。