📦

ProjectRefからGitHub Packagesへ:社内Scalaライブラリの管理を改善した話

に公開

1. はじめに

株式会社ZOZOの計測プラットフォーム開発本部計測システム部に所属しているでぃーのです。主にバックエンド開発を担当しています。

本稿では、計測システムのバックエンド開発で共同利用している社内ScalaライブラリをProjectRefを使って参照する方法から、GitHub Packagesでパッケージとして管理し参照する方式に移行した話を紹介します。

背景①どうして社内Scalaライブラリが必要なのか?

そもそもどうして社内Scalaライブラリが必要なのかを簡単に説明します。

計測バックエンドはチームの特性上、1つのチームで複数のプロダクトのバックエンド開発・運用を担当します。その時の状況によっては、チームメンバーそれぞれが別のアプリケーションを実装することもあります。そんな時にAWSなど外部サービス呼び出しのための実装やUtilパッケージと呼びがちな処理が各アプリケーションで実装されるのはメンバーそれぞれの時間を奪っているとも考えられます。

共通ライブラリに知識を集約することで、チームメンバーがアプリケーションのコアの実装に時間を使えるようになることを目的として、計測バックエンドでは社内Scalaライブラリを開発しています。

背景②社内Scalaライブラリの配布における課題

これまで、この社内Scalaライブラリは、参照側のアプリケーションでsbtのProjectRefを使って依存として追加していました。

参照側アプリケーションの実装イメージ

lazy val sharedLibrary = ProjectRef(uri("ssh://社内ScalaライブラリのGitHubリポジトリ"), "root")
val root = (project in file(".")).dependsOn(sharedLibrary)

このアプローチの場合、ライブラリをパッケージにして配布する方式と比較して、開発サイクルは速くなることが多いように思います。一方で、参照側のアプリケーションが増えてくると、このアプローチではいくつかの課題が発生します。

1. 開発時のコンパイルやCICDビルドの非効率性

ProjectRefを使うアプローチでは参照側のアプリケーション毎に社内Scalaライブラリをcloneしキャッシュします。そのため、別プロジェクトで同じバージョンの社内Scalaライブラリを利用していてもコンパイルが実行されます。

$ ls -lh ~/.sbt/1.0/staging/
total 0
drwxr-xr-x  29 user  11  98 11:47 08e3359dc4c225f0651b
drwxr-xr-x  22 user   8  810 02:00 7eea639738e2105accb2
drwxr-xr-x  20 user   8  814 29:00 71a9c543019325e47726
drwxr-xr-x  10 user   7  715 15:00 750dccf980aff67ca3ab
drwxr-xr-x  25 user   6  618 51:00 4938f8c792d66af0e237
drwxr-xr-x  11 user   9  99 32:00 cb63d7acda9450568e22
drwxr-xr-x   2 user   7  711 48:00 fd5045a94de00948d3f4

# 各ディレクトリ内に社内Scalalライブラリが重複してキャッシュされている
# 合計サイズ: 約55MB

2. 依存関係自動更新ツールなど周辺ツールを活用しにくい

私たちのチームでは依存関係自動更新ツールを使ってライブラリの更新を省力化しています。ProjectRefを使うアプローチだと、この流れに乗ることができません。

本記事の目的:「GitHub Packagesで解決する方法」を紹介

本記事では、Scalaプロジェクトにおける社内ライブラリの配布・管理の課題を、GitHub Packagesを使って解決する方法を紹介します。

従来のProjectRefを使った方法から脱却し、より効率的で安全な運用方法へ移行するための具体的な手順と、実際に導入して得られたメリットをお伝えします。

この記事を読むことで、以下のことが理解できます:

  • 現在のライブラリ配布方法の課題と改善の必要性
  • GitHub Packagesと他の代替案の比較
  • GitHub Packagesの具体的な設定手順
  • 導入後に得られる実務上のメリット

想定読者・前提(sbtを使っている人向け)

本記事は、以下のような方を対象としています:

想定読者

  • Scala/sbtを使った開発経験がある
  • 社内向けのプライベートライブラリを複数のプロジェクトで共有している
  • 現在の依存関係管理に課題を感じている
  • より効率的な開発フローを構築したい

前提知識

  • sbtの基本的な使い方(build.sbtの編集、依存関係の追加など)
  • GitHubの基本操作(リポジトリ管理、アクセストークンの概念)

環境

  • sbt
  • GitHub
  • GitHub Packages

2. 代替案の検討

社内ライブラリの配布方法として、いくつかの選択肢がありました。それぞれの特徴を理解した上で、自社に最適な方法を選択することが重要だと思います。

今回は以下の3つの選択肢で比較し、最終的にGitHub Packagesでの管理を採用しました。

  1. GitHub Packages
  2. 社内でMaven構築・運用
  3. ライブラリのOSS化・Maven Central

比較表+選定理由(GitHub Packages採用の決め手)

各選択肢を以下の観点で比較します。

項目 GitHub Packages 社内Maven構築 Maven Central
初期コスト ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐
運用コスト ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐
CI/CD連携 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
柔軟性 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐
社内限定利用 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ❌ 不可

GitHub Packagesを選定する主な理由

既にGitHub、GitHub Actionsを利用していたので、移行における初期コストは無視できると考えました。GitHub Packagesのアクセス制御は、パッケージがホストされているリポジトリから継承されることもあり、その辺りの設定を追加でする必要がないのも地味に嬉しいポイントでした。

3. 実際の設定手順

ここからは、GitHub Packagesを実際にScala/sbtプロジェクトで利用するための具体的な設定手順を解説します。

3.1 GitHub Packages用のPAT(Personal Access Token)発行

GitHub Packagesにアクセスするには、Personal Access Token(PAT)が必要です。

手順

  1. GitHubにログインし、右上のプロフィールアイコンから Settings を開く

  2. 左メニューから Developer settings を選択

  3. Personal access tokensTokens (classic) を選択

  4. Generate new tokenGenerate new token (classic) をクリック

  5. トークンの設定を行う:

    • Note: トークンの用途(例:sbt-github-packages
    • Expiration: 有効期限を設定(90日、1年、無期限など)
    • Select scopes: 以下の権限を選択
      • read:packages - パッケージの読み取り
      • write:packages - パッケージの書き込み(publish用)
      • delete:packages - パッケージの削除(必要に応じて)
      • repo - プライベートリポジトリにアクセスする場合は必要
  6. Generate token をクリックし、表示されたトークンを安全な場所に保存

セキュリティのベストプラクティス

  • トークンは環境変数や.gitignoreに追加したファイルに保存し、リポジトリにコミットしない
  • チーム開発では、各メンバーが個別のトークンを発行する
  • 定期的にトークンをローテーションする
  • 最小権限の原則に従い、必要な権限のみを付与する

3.2 build.sbt・credentials.sbt の設定例

GitHub Packagesからライブラリを読み込む(依存関係として使用する)設定と、GitHub Packagesにライブラリを公開する(publish)設定を行います。

パッケージを読み込む側の設定

build.sbt

// GitHub Packagesをリゾルバーとして追加
resolvers += "GitHub Package Registry" at "https://maven.pkg.github.com/OWNER/REPOSITORY"

// 依存関係に社内ライブラリを追加
libraryDependencies += "com.example" %% "your-library" % "1.0.0"

OWNERはGitHubのオーナー名(organization または個人のユーザー名)、REPOSITORYはリポジトリ名に置き換えてください。

~/.sbt/1.0/credentials

realm=GitHub Package Registry
host=maven.pkg.github.com
user= // GitHubユーザー名
password= // 発行したPAT

環境変数を設定:

export GITHUB_USER="your-github-username"
export GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxx"

パッケージを公開する側の設定

ライブラリ側のプロジェクトで以下の設定を追加します。

build.sbt

organization := "com.example"
name := "your-library"
version := "1.0.0"

// GitHub Packagesへの公開設定
publishTo := Some(
  "GitHub Package Registry" at s"https://maven.pkg.github.com/OWNER/REPOSITORY"
)

credentials += Credentials(
  "GitHub Package Registry",
  "maven.pkg.github.com",
  System.getenv("GITHUB_USER"),
  System.getenv("GITHUB_TOKEN")
)

// 公開に必要な基本設定
publishMavenStyle := true
publishConfiguration := publishConfiguration.value.withOverwrite(false)

GitHub PackagesはMavenをサポートしているため、publishMavenStyleをtrueに設定して、Maven形式でパブリッシュするようにします。また、現在はSnapshotバージョンも利用していないため、publishConfiguration.value.withOverwrite(false)を指定して既存のパッケージを上書かないようにしています。

公開コマンド

sbt publish

これで、GitHub Packagesにライブラリが公開されます。

3.3 CI/CD(GitHub Actions)での設定

GitHub Actionsを使って、自動的にパッケージをビルド・公開する設定例です。

GitHub Actionsのワークフローは、特定のブランチやタグへのpushをトリガーにして、自動でビルドと公開を実行するように設定できます。

以下は、vで始まるタグがpushされた際に sbt publish を実行するワークフローの主要な部分です。

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write # GitHub Packagesへの書き込み権限

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      # JDKやsbtのセットアップ
      # ...

      - name: Publish to GitHub Packages
        run: sbt publish
        env:
          GITHUB_USER: ${{ github.actor }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

ポイント

  • secrets.GITHUB_TOKENは、GitHub Actionsが自動的に提供するトークンで、特別な設定は不要です。
  • permissionsセクションでpackages: writeを明示的に指定する必要があります。
  • actions/setup-javasbt/setup-sbt などの具体的なアクション名を省略し、処理内容をコメントで示すことで、詳細な技術スタックの公開を避けています。

4. 導入後のメリット

ビルド時間短縮・キャッシュ最適化

開発時の複数のリポジトリを行き来する必要がある際にキャッシュの最適化によるコンパイル時間の短縮は感じられました。

Before

$ ls -lh ~/.sbt/1.0/staging/
total 0
drwxr-xr-x  29 user  11  98 11:47 08e3359dc4c225f0651b
drwxr-xr-x  22 user   8  810 02:00 7eea639738e2105accb2
drwxr-xr-x  20 user   8  814 29:00 71a9c543019325e47726
drwxr-xr-x  10 user   7  715 15:00 750dccf980aff67ca3ab
drwxr-xr-x  25 user   6  618 51:00 4938f8c792d66af0e237
drwxr-xr-x  11 user   9  99 32:00 cb63d7acda9450568e22
drwxr-xr-x   2 user   7  711 48:00 fd5045a94de00948d3f4

# 各ディレクトリ内に社内ライブラリが重複してキャッシュされている
# 合計サイズ: 約55MB

After

$ ls -lh ~/Library/Caches/Coursier/v1/https/maven.pkg.github.com/OWNER/
total 0
drwxr-xr-x   1 user  10 1210 37:00 shared-library

# 単一のキャッシュディレクトリで管理
# 合計サイズ: 約670KB

自動更新(依存関係自動更新ツール対応)

GitHub Packages管理に移行したことで、無事、社内Scalaライブラリが依存関係自動更新ツールのバージョン更新対象になりました。社内Scalaライブラリの新しいバージョンをGitHub Packagesにパブリッシュするだけで、自動で各アプリケーションのリポジトリにバージョン更新PRが作成されるようになりました。

依存関係自動更新ツールで自動作成されたバージョン更新PRのスクリーンショット

5. まとめ

本稿では、ScalaプロジェクトにおけるProjectRefベースの社内ライブラリ管理から、GitHub Packagesを使ったパッケージ管理への移行について紹介しました。

この移行によって、複数アプリケーションを跨いだ開発が必要な場合のビルド効率の向上や依存関係自動更新ツールによるバージョン管理の自動化などの成果を得ることができました。

特に、既にGitHubとGitHub Actionsを利用している環境であれば、少ない移行コストで実現できることがわかりました。

本稿が、同様の課題を抱えている方々の参考になれば幸いです。ご質問やフィードバックがあれば、ぜひコメントでお知らせください。

一緒に働きませんか?

私たち計測バックエンドチームと密に働く機会の多い計測システム部SREチームでは、ZOZOの計測システムを支えるSREを募集しています。

https://hrmos.co/pages/zozo/jobs/1809846973241688303

カジュアル面談も歓迎です。お気軽にご応募ください!

GitHubで編集を提案
株式会社ZOZO

Discussion