GitHub PackagesのMaven Repositoryを使ってみる – エキサイト TechBlog.

こんにちは、エキサイト株式会社の平石です。

アドベントカレンダーの3日目を担当します。

qiita.com

今回は、GitHub Packagesの利用方法と、実際に運用としていく上で私が感じた課題をご紹介します。

はじめに

GitHub Packages は、コンテナやその他の依存関係を含むパッケージをホストおよび管理するためのプラットフォームです。
通常、こういったものを管理しようとすると自前でサーバーを立てて運用する必要があります。
しかし、GitHub Packagesを使うことで自前でサーバーを管理する必要がなく、なおかつソースコードの管理とパッケージの提供をGitHubという一つのサービス内で完結させることができます。

環境

本記事のソースコードは以下の環境で動作確認を行っています。
GitHub PackagesのMaven Repositoryを利用します。

  • Java 21
  • SpringBoot 3.4.0
  • Gradle 8.11

事前準備

GitHub Packagesを利用するためには、Personal Access Tokenが必要です。

Generate new token > Generate new token(classic)をクリックし、Select scopesのところでwrite:packagesと必要ならdelete:package の権限を選択してPersonal Access Tokenを作成します。
作成したトークンは忘れないように保存しておいてください。

このトークンを、Gradleから利用できるようにします。

~/gradle/gradle.propertiesまたはプロジェクトルート直下にgradle.propertiesファイルを作成し以下の内容を記述します。

gpr.user=
gpr.key=<先ほど作成したトークン>

~/gradle/gradle.propertiesに記述すると全てのGradleプロジェクトでそのプロパティを利用できます。

プロジェクトルート直下にgradle.propertiesファイルを作成する場合には、誤ってコミットしないように注意しましょう。

こちらで記述したプロパティはbuild.gradleファイルで以下のように参照することができます。

project.findProperty("gpr.key")

また、GitHub Packagesで管理するパッケージはリポジトリと紐づく形になるので、GitHubリポジトリが必要です。
通常は、アップロード対象のパッケージのソースコードを管理しているリポジトリで良いと思います。

Gradleの設定

パッケージとして公開するプロジェクト(サブプロジェクト)のbuild.gradleに以下のように記述します。
今回はパッケージの公開にmaven-publishというプラグインを利用します。

{root}/test_project/build.gradle

repositories {
    mavenCentral()
}

sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21

group = 'com.example'
version = '1.0.0'

apply plugin: "maven-publish"

publishing {
    repositories {
        maven {
            name = "GitHubPackages"
            url = uri("https://maven.pkg.github.com/{ユーザー名またはOrganization名}/{repository名}")
            credentials {
                username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
                password = project.findProperty("gpr.key") ?: System.getenv("ACCESS_TOKEN")
            }
        }
    }
    publications {
        gpr(MavenPublication) {
            artifactId = 'test_project'
            from(components.java)
        }
    }
}

maven-publishプラグインの設定はpublishingの部分に記述します。
アップロード先のMaven Repositoryのurlhttps://maven.pkg.github.com/{ユーザー名またはOrganization名}/{repository名}となります。

また、アップロードには認証が必要なため、credentialsで認証情報を設定しています。
passwordには先ほどプロパティファイルに記述したPersonal Access Tokenを読み込むように設定しています。

GitHub Actionsから利用する際にはgradle.propertiesファイルに記述するより、環境変数に設定する方が扱いやすいです。
そのため、プロパティが見つからない場合にはSystem.getenv("環境変数名")環境変数から値を取得するようにしています。

Graldeプロジェクトを再ロードすると、project1:publishGprPublicationToGitHubPackageRepositoryというGradleタスクでGitHub Packagesにパッケージをアップロードできるようになっています。

./gradlew project1:publishGprPublicationToGitHubPackageRepository

このGradleタスクを実行すると、リポジトリのホーム(https://github.com/{ユーザー名またはOrganization名}/{リポジトリ名})のサイドバーのPackagesという欄にアップロードしたパッケージが表示されています。
そこをクリックすると、以下のようなページでパッケージの詳細を確認できます。

アップロードしたパッケージを利用するには、利用するプロジェクト(サブプロジェクト)のbuild.gradleで以下のように記述します。

project(':project2:controller') {

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'

        
        implementation 'com.example:test_project:1.0.0'
    }
}

ライブラリは一つのサブプロジェクトだけでなく、プロジェクト全体で利用することも多いと思いますので、プロジェクトルートのbuild.gradleでパッケージを取得する先のMaven Repositoryを以下のように宣言しておくと良いでしょう。

allprojects {
    repositories {
        mavenCentral()
        maven {
            url = uri("https://maven.pkg.github.com/{ユーザー名またはOrganization名}/{repository名}")
            credentials {
                username = project.findProperty("gpr.user") ?: System.getenv("USERNAME")
                password = project.findProperty("gpr.key") ?: System.getenv("ACCESS_TOKEN")
            }
        }
    }
}

urlや認証情報の設定はアップロードの時とほぼ同じです。

GitHub Actionsからの利用

GitHub Packagesは、当然ながらGitHub Actionsからも利用できます。
GitHub Actionsを実行しているのと同じリポジトリを対象にパッケージをアップロードまたはダウンロードする場合には、認証時にPersonal Access Token以外にもGITHUB_TOKENを利用できます。

GITHUB_TOKENはActionsのワークフロー内で利用できる期限付きの特別なトークンで、${{ secrets.GITHUB_TOKEN }}と記述することで参照できます。

例えば、パッケージをアップロードするワークフローは、以下のように実現できます。

name: Publish
run-name: publish

on:
  workflow_dispatch

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Publish
        env:
          ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          ./gradlew project1:publishGprPublicationToGitHubPackageRepository

GITHUB_TOKENの代わりにPersonal Access Tokenを利用する場合には、リポジトリのSecretsにトークンを登録して利用することになるでしょう。

利用してみての感想

弊社では、複数のサービスで利用する「社内の共通基盤」のライブラリを各サービスを管理する個々のリポジトリから利用するために、GitHub Packagesの利用を検討していました。

調査をする中でメリットに感じた点と懸念点を以下に共有します。

メリット

GitHubだけで完結できる

ソースコードのバージョン管理にGitHubを利用しているのであれば、ライブラリの管理もGitHubで完結できるのは便利です。
多くのサービスを利用すればするほど、各サービスの管理をする必要がありますし、有料のサービスであればコストもかさみます。

利用が簡単

自前でサーバーを立てることなく、GitHubへの認証だけでライブラリのアップロード、ダウンロードができる点は導入のハードルが低いといえるでしょう。

懸念点

コスト

懸念点の一つにコストの問題があります。
パブリックなライブラリの管理は完全に無料で利用できますが、プライベートなライブラリの管理をしようとするとそうはいきません。

GitHub Packagesではプランごとに無料利用枠が決められており、それを超えると従量課金されていきます。

docs.github.com

課金はストレージと月当たりのデータ転送量の2つに応じて行われます。
ストレージに関しては、Maven RepositoryでのJavaのライブラリでの利用であれば、ほとんどの場合は無料利用枠を超えることはないと思いますが、問題はデータ転送量の方でしょう。

GitHub Actionsを利用する場合はデータ転送は無料と書かれていますが、GitHub Actionsを利用しているとみなされるのはGITHUB_TOKENというトークンを利用した場合だけのようです。
このトークンではリポジトリを跨いだパッケージへのアクセスができません。
そのため、Personal Access Tokenを使うことになりますが、こちらを用いた認証だとGitHub Actionsを利用しているとみなされないようです。
つまり、あるサービスのソースコードを管理しているGitHubリポジトリで実行されるワークフローから、別のリポジトリのPackagesで管理しているライブラリをダウンロードしようとすると課金対象になると考えられます。

したがって、ローカルからのパッケージのダウンロードとGitHub Actionsを使ってデプロイなどを行う際のパッケージのダウンロードが課金対象となるため、頻繁にデプロイ・リリースを行うような場合には無料利用枠を超える可能性は十分にあると思います。

認証方法

もう一つの懸念点が認証方法です。
実はこちらの方が、課題と感じている点です。(コストに関しては、どのようなサービスを利用しても有料なことが多いですし、ある意味仕方ないといえます。)

GitHub Packagesは現在のところGitHub Actionsで利用できるGITHUB_TOKENという一時的なアクセストークンか、個人ごとに作成するPersonal Access Tokenを用いた認証方法しかサポートしていません。

前述の通り、GITHUB_TOKENを用いた認証では別のリポジトリへのアクセスができないようなので、「社内の共通基盤」のようなパッケージを社内の多くのサービスから利用しようとするとPersonal Access Tokenを用いた認証方法しか利用できません。

しかし、このトークンはPersonalとあるようにあくまで「個人」に紐づいたトークンです。
ローカルへのダウンロードならこれでも良いですが、GitHub Actionsを通して利用する場合に個人に紐づいたトークンを積極的に利用したくないことも多いでしょう。
その人が異動や退職でいなくなった場合にアクセストークンが管理できなくなったり、無効になったりするかもしれないですし、Organizatinsの場合何らかの理由で一般のメンバーにはGitHub Packagesへのアクセス権を渡していない場合もあるでしょう。

このようなことから、リポジトリを跨ぐ場合でも使えるPersonal Access Token以外の何かしらのアクセス方法が欲しいと、個人的には考えています。

おわりに

今回は、GitHub Packagesの利用方法と私が感じた課題をご紹介しました。

GitHubという多くの個人や組織が利用しているサービスの上で簡単に利用できて便利ではあるのですが、プライベートなパッケージを管理する上ではコストや認証方法にやや課題が残りそうです。

では、また次回。

参考文献




元の記事を確認する

関連記事