TT Lab
はじめる
学ぶ 学習パス コース

閉域網のミラーとプライベート CA

レジストリをもう一つ立てる理由

TT Labで続きを見る

一言でいうと

npmのエアギャップ環境への対応は、レジストリをもう1つ立てることです。接続されている間に、上位(npmjs)を引いて埋めておき、切断したあとは、埋めておいたものだけを出します。プロジェクトは、.npmrcのregistry1行で、そのレジストリを見ます。ロックファイルに埋め込まれたアドレスは、npmが自動で置き換えてくれますが、そのデフォルトを知らないと事故が起きます。

なぜ必要なのか

フロントエンドのリポジトリ1つのnode_modulesは、パッケージが数百個です。エアギャップ環境でnpm ciを実行すると、最初のパッケージで止まります。よくある一時しのぎは、接続されたPCでnode_modulesを丸ごと圧縮して持ち込むことですが、OSやnodeのバージョンが違えば、ネイティブモジュールが壊れ、何が入ったかの一覧も残りません。必要なのは、パッケージ単位で取得しておき、ロックファイルのとおりに再インストールできるリポジトリです。

どう動くのか

レジストリを指し示す: npmは、設定を、コマンドライン → 環境変数 → npmrcファイル → デフォルト値の順に従い、npmrcは、プロジェクト(.npmrc)→ ユーザー(~/.npmrc)→ グローバル($PREFIX/etc/npmrc)→ 組み込みの順に優先されます。registryのデフォルト値はhttps://registry.npmjs.org/です。プロジェクトの.npmrcにregistry=を書けば、そのリポジトリを開く誰もが、同じレジストリを見ます。

verdaccioの3つの設定: uplinksは上位レジストリの一覧で、packagesは、名前のパターンごとにaccess・publish・proxyを決めます。ドキュメントによると、パターンの順序が重要で、**を最後の受け皿として置きます。proxyにuplink名を書いたパターンは、ローカルにないものを上位から引いてstorageに残し、proxyがないパターンは、ローカルのストレージにあるものだけを返します。これが「切断する」の正体です。デフォルトのポートは4873です。

NexusやArtifactoryの用語に置き換えると、次のようになります。Nexusのドキュメントは、リポジトリを3種類に分けています。リモートをキャッシュするproxy、自分たちがアップロードする元のhosted、複数を1つのアドレスにまとめるgroupです。verdaccioのproxy: npmjsが付いたパターンがproxyリポジトリ、社内パッケージをpublishするパターンがhosted、2つを1つのアドレスで出すものがgroupの役割です。Nexus 3は、公式の要求仕様が、ホストメモリ8GB、デフォルトのヒープ2703MBなので、このラボのPod(2Gi)には入りません。原理を軽いもので身につけて、現場の機器のメニューに対応させれば済みます。

ロックファイルとアドレス: package-lock.jsonのresolvedには、tarballの完全なアドレスが書かれます。外部で作ったロックファイルには、https://registry.npmjs.org/...が埋め込まれています。npmのreplace-registry-host設定が、この問題を扱います。デフォルト値のnpmjsは、デフォルトのレジストリを指すアドレスだけを、設定したレジストリに置き換えて取得します。neverは書かれたアドレスのまま行き、alwaysは、どのホストでも置き換えます。社内レジストリのアドレスが埋め込まれたロックファイルを、別の社内レジストリに移すときは、デフォルト値が助けてくれないという意味でもあります。

インストールコマンド: npm ciは、ロックファイルが必ず必要で、package.jsonとずれると、ロックを直す代わりにエラーで止まり、node_modulesを削除して新しくインストールします。持ち込みの再現には、こちらが適しています。--offlineは、ネットワークリクエストをまったくせずに、キャッシュだけを使い、--prefer-offlineは、キャッシュを先に見て、なければ取得しに行きます。npmのドキュメントは、キャッシュを「信頼できる永続ストレージとして頼るな」と書いています。キャッシュを持ち込みの手段にするのではなく、レジストリを立てる理由です。

現場での姿

このラボのPodで測ってみました(npm 10.9.0、verdaccio 6.1.6)。registry.npmjs.orgのアドレスが埋め込まれたロックファイルで、外部をふさいだままnpm ci --registry http://127.0.0.1:4873/を実行すると、デフォルトでは、6個のパッケージが社内レジストリからインストールされ、--replace-registry-host=neverを指定すると、プロキシの接続エラーで止まりました。同じロックファイル、同じレジストリ設定なのに、1行のデフォルト値が結果を分けます。また、uplinkを切断したverdaccioに、ストレージになかったパッケージをリクエストすると、404になります。「レジストリが故障した」のではなく、「持ち込み一覧になかった」という意味なので、404は、持ち込み申請書を書き直せという合図です。

verdaccio自体もnpmパッケージなので、持ち込み物です。このラボでインストールすると、依存関係が270個あまりついてきて、ディスクを59MB使いました。バージョンを固定してインストールして、そのロックファイルも一緒に保管しておかないと、エアギャップ環境の中で、同じverdaccioを立て直せません。

次のラボですること

verdaccio 6.1.6をインストールして、npmjsを上位に置いたレジストリとして、npm.airgap.internal:4873で起動し、プロジェクトの.npmrcで指し示して、chalk 4.1.2を引いて埋めます。uplinkを切断して、外部がふさがれた状態で、新しいキャッシュでnpm ciができるかを、採点がもう一度実行して確認します。最後に、外部で作ったロックファイルで、replace-registry-hostのデフォルトとneverを、直接比較して記録します。

参考ドキュメント: npmrc・npm config(registry, replace-registry-host, offline)・npm ci・verdaccio Configuration・verdaccio Packages・Nexus Repository Types・Nexus System Requirements