📦

【Unity】GCP Artifact RegistryでPrivateなUPMレジストリを構築する

に公開

ゲームエンジンUnityの内製パッケージを社内だけ等、限定配布を行いたい場合、Verdaccioを使う事例が多いと思います。柔軟な設定が出来る(あと他に選択肢があまりない)一方、こうしたサーバーアプリケーションのホスティングは、クライアントエンジニアにはハードルが高いと感じる事も多いでしょう。
そこで今回はGoogleCloudPlatformのArtifactRegistryを使ってPrivateなUPMレジストリを構築し、認証付きでパッケージの配布を行う手順をまとめました。比較的簡単に、かつマネージドサービスなので手間をかけずに構築できます。

環境構築

  • Node.js
    • 現在LTSのバージョンならどれでも大丈夫な筈です(本記事は24.6.0を使いました)
    • 本記事ではnpm npxを使う為です
  • gcloud CLI
    • 課金設定を行ったGCPプロジェクトは作成しておいて下さい

リポジトリ作成

まずはリポジトリ作成を行います。

$ gcloud artifacts repositories create <リポジトリ名(好きにつけてOK)> --repository-format=npm --location=<ロケーション名> --description="Unity Packages"

続いてnpmの設定を書き出すコマンドがあります。

$ gcloud artifacts print-settings npm --project=<プロジェクト名> --repository=<リポジトリ名> --location=<ロケーション名>

標準出力で下記のような設定が出てきます。

# Insert the following snippet into your project .npmrc
registry=https://<ロケーション名>-npm.pkg.dev/<プロジェクト名>/<リポジトリ名>/
//<ロケーション名>-npm.pkg.dev/<プロジェクト名>/<リポジトリ名>/:always-auth=true

コメントには.npmrcに書き出せと書かれていますが、あえてそれ以外のファイル名でテキストファイルを作成して下さい[1](ここではauth.txtとします)

パッケージ公開(Publish)用の認証設定

次にパッケージ公開を行うための認証用アクセストークンを取得します。

$ npx google-artifactregistry-auth --repo-config=./auth.txt --credential-config=./auth.txt

このコマンドを実行すると、先ほど作成したauth.txtに1行追記されます。

//<ロケーション名>-npm.pkg.dev/<プロジェクト名>/<リポジトリ名>/:_authToken=<アクセストークン>

なおこのアクセストークンの有効期限は60分ですので作業中断時はご注意下さい。期限が切れた場合は再度npx google-artifactregistry-authを実行すれば、アクセストークンだけが更新されます。

パッケージの公開

公開したいUnityパッケージのpackage.jsonと同じディレクトリにauth.txtをコピーし、.npmrcという名前にリネームします。そして同ディレクトリ内で以下を実行します。

$ npm publish

エラーが出なければ公開完了です。この時点では認証情報が無いので、まだUnityから参照する事は出来ません。

Unityから参照するための認証設定

UnityからはGCPのサービスアカウントの認証情報を使ってパッケージを参照しましょう。[2]

$ gcloud iam service-accounts create <サービス名(好きにつけてOK)> --display-name="Unity Package Viewer Service Account" --project=<プロジェクト名>

サービスアカウントが出来たら、サービスアカウントにリポジトリの参照ロールを付けます。

$ gcloud artifacts repositories add-iam-policy-binding <リポジトリ名> --location=<ロケーション名> --member="serviceAccount:<サービス名>@<プロジェクト名>.iam.gserviceaccount.com" --role="roles/artifactregistry.reader"

サービスアカウントのJSONキーを取得します。

$ gcloud iam service-accounts keys create ./key.json --iam-account=<サービス名>@<プロジェクト名>.iam.gserviceaccount.com

パッケージ参照用のアクセスキーの取得

ここから少しややこしいです。設定書き出しコマンドでサービスアカウントのJSONキーを読み込ませます。

$ gcloud artifacts print-settings npm --project=<プロジェクト名> --repository=<リポジトリ名> --location=<ロケーション名> --json-key=./key.json

次の出力が得られます。

# Insert the following snippet into your project .npmrc
registry=https://<ロケーション名>-npm.pkg.dev/<プロジェクト名>/<リポジトリ名>/
//<ロケーション名>-npm.pkg.dev/<プロジェクト名>/<リポジトリ名>/:always-auth=true
# Insert the following snippet into your user .npmrc

//asia-northeast1-npm.pkg.dev/studio-app-utility/private-package-sample/:_password="<base64のコード>"
//asia-northeast1-npm.pkg.dev/studio-app-utility/private-package-sample/:username=_json_key_base64
//asia-northeast1-npm.pkg.dev/studio-app-utility/private-package-sample/:email=not.valid@email.com

ここで得られた<base64のコード>をデコードし、下記の様な文字列をつくります。

_json_key_base64:<デコードしたコード>

そしてこの文字列を再度base64にエンコードしたものがアクセスキーとなります。[3]

UnityからPackageを参照する

ユーザーディレクトリ以下に.upmconfig.tomlを作成し、以下のフォーマットで書き込みます。

.upmconfig.toml
[npmAuth."https://<ロケーション名>-npm.pkg.dev/<プロジェクト名>/<リポジトリ名>/"]
_auth = "<アクセスキー>"
alwaysAuth = true

続いて参照したいUnityプロジェクトのPackages/manifest.jsonに書き込みましょう。今回入れたいパッケージはcom.example.sample-package:1.0.0とします。

manifest.json
{
  "dependencies": {
    "com.example.sample-package": "1.0.0"
  },
  "scopedRegistries": [
    {
      "name": "Private Registry",
      "url": "https://<ロケーション名>-npm.pkg.dev/<プロジェクト名>/<リポジトリ名>/",
      "scopes": [
        "com.example"
      ]
    }
  ]
}

これでUnityがプロジェクトを開いていれば、指定したパッケージが依存関係も解決してインポートされます。
作業手順は以上になります。

余談1:npm searchは対応していない

パブリックなOpenUPMなどのレジストリではnpm searchに対応している為、ScopedRegistry対象に存在するPackageの一覧がUPM上で確認することが出来ますが、今回作成したPrivateRegistryはそれに対応していない為、PackageManagerのウィンドウ上から一覧の形で選んでインストール、といった事は出来ません(Package名を知らないとダメという事。尤も用途的に必要になる事はあまりないでしょう)

余談2:npmのScopedレジストリについて

npmについて知識があればScopedレジストリでない事を不思議に思うかもしれませんが、UPMでは@付きのパッケージ名が読み込めない為にこのような構成になっています

脚注
  1. .npmrcとして書き出すとgoogle-artifactregistry-auth実行時にnpmjs.comを見に行かなくなり解決できずパッケージダウンロードに失敗しました ↩︎

  2. UPMの認証方式はアクセストークンを利用するしかなく、有効期限付きでは一々作業中に更新する必要が出てしまいます。しかしユーザー権限の無期限のアクセストークンはセキュリティ上好ましくない為です ↩︎

  3. 実は最初に出てきたbase64コードの正体はJSON鍵を2回base64でエンコードしたものです ↩︎

カバー株式会社

Discussion