そこそこ以上の規模のプロジェクトを作る際、どうしても複数プロジェクト間で共有する共通ライブラリ(*.jar
など)を作りたいことがあると思うのですが、GitLabには GitLab Package Registry という 共通ライブラリをGitLabに登録できる便利な機能 があります。
通常であれば、 Sonatype Nexus や JFrog といったアーティファクトマネージャを別個で立てなければならないのですが、これを使えばGitLab一つで済むので非常に楽です。
従来は有料版のみの機能だったのですが、なんと 13.3 から全エディションで利用可能になっています。
そういうことで、実際に仕事で使ってみたのですが、ややドキュメントが分かりづらかったので、概要を適当にまとめておきます。
結局 GitLab Package Registry とはどういう機能なのか?
公式ドキュメント: https://docs.gitlab.com/ee/user/packages/package_registry/
GitLab上に *.jar
(Maven) や *.dll
(.NET) などを登録できるプライベートなパッケージレジストリを持つことができます。自前でGitLabを運用している場合は他機能と同様、パッケージファイルそのものはS3上にオフロードすることが可能です。
ここでいうパッケージというのは、下記を指します。
- Maven (Java)
- NPM (JavaScript)
- NuGet (.NET)
- PyPi (Python)
- 汎用ファイル置き場
- 以下はまだ開発中 (2022/01/11時点)
- Ruby Gems (Ruby)
- Composer (PHP)
- Go (プロキシ)
- Debian packages
- Conan (C/C++)
- Helm chart
この記事ではMaven (Gradle)で構成していきます。
パッケージ種類ごとにかなり設定値や方法が異なるので、他のパッケージを登録する際はドキュメントをチェックしてください。
一般的な利用方法としては、リポジトリ上に共有ライブラリプロジェクトを作成して、そのプロジェクトのCIがパスしたらビルドパイプラインの最後にそのプロジェクトのパッケージレジストリに、バージョン付きでライブラリバイナリをpushして利用するのがほとんどだと思います。
弊社でも画面とAPIの共通仕様を共有ライブラリプロジェクトとして作成して、両者のコード生成に利用しています。
Maven レジストリの場所(エンドポイント)・認証方法
プライベートなパッケージレジストリなので、利用にはレジストリのURLおよび、レジストリにログインするためのユーザIDとパスワードによる認証が必要です。
レジストリのURL (エンドポイントURL)
リポジトリレベルのレジストリ (登録・参照用)
パッケージはすべてプロジェクト内のレジストリに登録していきます。
ドキュメントを見ると、グループやインスタンス(GitLab)レベルでレジストリが生えてそうな気がしますが、そいつらは参照専用のレジストリであって、結局のところパッケージはプロジェクト以外には登録できません。ハマりポイントです。
具体的には下記のようなURLがプロジェクトの(登録用の)MavenレジストリのURLになります。
https://gitlabのURL/api/v4/projects/プロジェクトID/packages/maven
# e.g. プロジェクトID=100であれば
# https://gitlabのURL/api/v4/projects/100/packages/maven
グループ・インスタンス(GitLab)レベルのレジストリ (参照用)
各プロジェクトに登録されたパッケージを参照する際はプロジェクト単位・グループ単位・GitLab全体(インスタンスレベル)といった複数の粒度でパッケージを参照することができます。
これは、Mavenがたまたまそうなっているだけで、他のパッケージの種類だと使えない粒度があります。たとえば、npmだとグループレベルのレジストリはありません。
具体的には下記のようなURLで参照することが可能です。
(プロジェクト単位のURL形式はさっきと同じ)
グループ単位
https://gitlabのURL/api/v4/groups/グループIDもしくはグループ名/-/packages/maven
# e.g. グループID=64であれば
# https://gitlabのURL/api/v4/groups/64/-/packages/maven
# e.g. グループ名=foo/barであれば
# https://gitlabのURL/api/v4/groups/foo%2Fbar/-/packages/maven
GitLab全体(インスタンスレベル)
https://gitlabのURL/api/v4/packages/maven
※ Mavenの場合は "パッケージ名" = "グループ名/プロジェクト名" という一致をしているパッケージ名じゃないとインスタンスレベルのURLは利用不可
(要らぬ制約のように見えますが、gitlab.comをホスティングする運用を考えれば当然の制約ではあります)
Mavenのパッケージを登録する時はプロジェクト単位のURL、参照する時はグループ単位のURLを使うのが一般的 かなと思います。別にプロジェクトのリポジトリをグループ内で使いまわしてもいいですが……
レジストリの認証方法
Mavenパッケージレジストリにおいて、ログインのための認証情報は下記の3パターンのいずれかを利用します。
- プライベートトークン
- ユーザID:
Private-Token
- パスワード: GitLabのユーザ設定より
api
スコープをつけたプライベートトークンを発行したもの
- ユーザID:
- デプロイトークン
- ユーザID:
Deploy-Token
- パスワード: プロジェクトの設定より発行した
read_package_registry
/write_package_registry
スコープをつけたデプロイキー
- ユーザID:
- CIトークン
- ユーザID:
Job-Token
- パスワード: CI/CDパイプライン中のジョブ実行中、
CI_JOB_TOKEN
という環境変数に入っている値 - (※ トークンの権限範囲はリポジトリにpushしたユーザに準じます)
- ユーザID:
ローカルの開発環境ではプライベートトークン、GitLab CI/CD実行中はCIトークンを使えば問題ありません。
デプロイトークンは外部コントリビューターとのパッケージ読込・登録を行う際に利用すればいいでしょう。
GradleでGitLab Package Registry (Maven)を使ってみよう
Gradle (Groovy) でGitLab Package Registryを使ってみます。
手動でパッケージ登録してみよう
下記を build.gradle
なりに記述して ./gradlew publish
を実行するだけです。
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
repositories {
maven {
url "https://GitLabのURL/projects/プロジェクトID/packages/maven"
credentials(HttpHeaderCredentials) {
name = "Private-Token"
value = "プライベートトークン"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
}
なお、実際プライベートトークンをそのまま build.gradle
に記述するのはセキュリティ上大いに問題があるので、 ~/.gradle/gradle.properties
などの外部ファイルに記述を移すことをおすすめします。(Gradleから読み込めれば記述場所はなんでもいいです)
credentials(HttpHeaderCredentials) {
name = "Private-Token"
value = myPrivateToken // <= "プライベートトークン"
}
myPrivateToken=プライベートトークン
Gradle からパッケージを参照してみよう
グループレベルでパッケージを参照してみます。 リポジトリの部分に下記を追加すればOKです。
maven {
name "GitLab"
url "https://GitLabのURL/api/v4/groups/グループID/-/packages/maven"
credentials(HttpHeaderCredentials) {
name = "Private-Token"
value = "プライベートトークン"
}
authentication {
header(HttpHeaderAuthentication)
}
}
登録同様、 "プライベートトークン"
部分は build.gradle
に書かないほうがいいでしょう。
GitLab CI/CD させてみよう
上記までの例では、プライベートトークンのみ利用していましたが、build.gradle
にプライベートトークンベタ書きでもしない限り、この設定をGitLab CI/CDにはそのまま使えません。
GitLab CI/CDでは CI_JOB_TOKEN
という環境変数に入っている値を Job-Token
というユーザー名とともに使用する必要があります。
なので、やや冗長ですが、 build.gradle
上では下記のような記述で Private-Token
と Job-Token
両者を共存させる必要が出てきます。
maven {
name "GitLab"
url "https://GitLabのURL/api/v4/groups/グループID/-/packages/maven"
credentials(HttpHeaderCredentials) {
def ciToken = System.getenv("CI_JOB_TOKEN")
// CI_JOB_TOKEN が指定されている場合とされていない場合で指定を分ける
if (ciToken) {
name = "Job-Token"
value = ciToken
} else {
name = "Private-Token"
// myPrivateToken をそのまま参照すると
// ~/.gradle/gradle.properties に指定がない場合に落ちるので間接的に参照する
value = project.properties["myPrivateToken"]
}
}
authentication {
header(HttpHeaderAuthentication)
}
}
もしくは、事前に ~/.gradle/gradle.properties
にユーザ名とパスワードを用意しておく構成にしてもいいです。CIではビルド前にこのファイルを用意するステップを追加すればいいでしょう。
(こちらの手法であれば、さらにDockerでコンテナをビルドしたいといった場合に RUN --mount=type=secret
を使ってシークレットを一時的にマウントする手法にも応用できます)
gitlabRepositoryUsername=foo
gitlabRepositoryPassword=プライベートトークン (or ジョブトークン)
maven {
name "GitLab"
url "https://GitLabのURL/api/v4/groups/グループID/-/packages/maven"
credentials(HttpHeaderCredentials) {
name = gitlabRepositoryUsername
value = gitlabRepositoryPassword
}
authentication {
header(HttpHeaderAuthentication)
}
}
ちなみにCI/CDで登録したパッケージは契機になったブランチ・コミットハッシュが表示されるようになります。便利ですね!
(上段が手動、下段がCI/CDで登録)
まとめ
そういうことでGitLab Package Registryの簡単な使い方でした。
これのほかにも、GitLabには
- Dockerイメージを登録できる GitLab Container Registry
-
docker pull
のキャッシュを取ってくれる Dependency Proxy- 将来的にいろんなパッケージに対応してくれるのを期待
- Terraformのtfstateの管理をしてくれる GitLab managed Terraform State
といったソフトウェア開発を支援する機能があり、GitLab一本でソフトウェアプロジェクト周りの管理が完結できるようになってきています。
規模の小さいプロジェクトであればGitLab一つあれば完結するのではと思います。GitLabの今後にますます期待です。