PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

プライベートNPMレジストリ Verdaccio について

ソリューション技術部の斎藤です。
弊社では、社内でNPMパッケージを管理するライブラリとしてVerdaccioを利用しています。

verdaccio.org

Verdaccioは、無料でプライベートなNPMレジストリを作成できるNPMパッケージです。
ローカルのNPMレジストリ参照先を、公式のNPMレジストリからVerdaccioで作成したプライベートレジストリに変更することで既存のNPMコマンドを利用できます。
プライベートレジストリに存在しないNPMパッケージをインストールしようとした場合にも、自動で公式のNPMレジストリに問い合わせを行います。
また、publishしたNPMパッケージをWeb画面上で確認することができ、画面上でダウンロードなども行えます。
リポジトリ管理されているパッケージの歴代バージョンも確認できます。

弊社では数年前からVerdaccioにお世話になっていましたが、時間経過とともにNPMパッケージが増え、徐々にEC2のディスクが圧迫されるようになってきました。
調べたところ、現在のVerdaccioバージョンではストレージ先をローカルからS3に変更できるとのことだったので、
ストレージ変更をおこなうとともに、Verdaccioのバージョンアップも行いましたのでその手順についてまとめました。

作業の流れ

今回の作業は、AWSで別サーバを用意して行います。

  • 現行サーバのEC2ローカルからS3へのNPMパッケージ移行
  • 新規サーバへのVerdaccioインストール
  • Verdaccioの設定ファイル更新
  • 新旧サーバ切替(Route 53)

NPMパッケージの移行

まずは、EC2のローカル上にあるNPMパッケージをS3に移行します。
バージョンアップ時に利用できるmigrationツールをVerdaccio公式が用意していましたが、
今回はストレージがS3への変更になるので、こちらは使わず、下記スクリプトを流してデータ移行しました。

S3に移行先となるバケットを作成して、作成したバケット名を下記スクリプトに指定します。
dirpathは、現行サーバのVerdaccioのローカルストレージディレクトリの場所です。
下記は、ec2-userのホームディレクトリにVerdaccioディレクトリが置かれている場合の例です。

#!/bin/sh

dirpath="/home/ec2-user/verdaccio/storage/*"
for package in $dirpath;
do
  if [[ ! $filepath =~ ^@.* ]] && [ -d $filepath ] ; then
    package_name=$(basename ${package})
    echo $package_name
    aws s3 cp /home/ec2-user/verdaccio/storage/"$package_name" s3://【S3バケット名】/"$package_name" --recursive
  fi
done

新サーバへのインストール

NPMパッケージをS3にコピーしている間に、Verdaccioの設定ファイルを更新します。
サーバ設定の反映については、ansibleを使用します。

www.redhat.com

※今回の記事では、EC2構築手順については省略します。

nodejsのバージョン

今回はnode v16系にします。

# roles/nodejs/tasks/main.yml

- name: node source
  shell: curl --silent --location https://rpm.nodesource.com/setup_16.x | bash -

- name: install nodejs
  yum:
    name: nodejs

Verdaccio最新バージョンを入れる → バージョン固定に

Verdaccioのバージョンはlatestを指定して作業していましたが、頻繁にアップデートされているプロジェクトのようで
作業時の最新バージョンではバグがあったようで起動しなくなってしまいましたのでバージョンは固定することにしました。
また、pm2で起動しますので最新バージョンを入れておきます。

# roles/nodejs/tasks/main.yml

- name: install global npm packages
  npm: name={{ item.name }} version={{ item.version }} global=yes
  with_items:
    - { name: verdaccio, version: 'v5.19.1' }
    - { name: verdaccio-aws-s3-storage, version: latest }
    - { name: pm2, version: latest }

設定ファイルを置く場所を指定します。
下記は、ec2-userで起動、ec2-userのホームディレクトリにVerdaccioディレクトリが置かれる場合の例です。

# roles/nodejs/tasks/main.yml

- name: VERDACCIO | Put config.yaml
  copy:
    src: roles/nodejs/files/config.yaml
    dest: /home/ec2-user/verdaccio/config.yaml
    owner: ec2-user
    group: ec2-user

- name: Put ecosystem.config.js
  copy:
    src: roles/nodejs/files/ecosystem.config.js
    dest: /home/ec2-user/verdaccio/ecosystem.config.js
    owner: ec2-user
    group: ec2-user

ここまでできたら一度ansible-playbookコマンドで新サーバへ反映して、インストールを確認します。

Verdaccio設定ファイルの更新

こちらもansible-playbookで反映します。
先程までの作業で、サーバ上にVerdaccioがインストールされていればconfig.ymlが指定ディレクトリに置かれていると思いますので
インストールされたYAMLファイルを更新していきます。

verdaccio.org

Verdaccioのストレージ変更

verdaccio S3 pluginを利用します。

verdaccio S3 plugin github.com

設定ファイルのstorageをコメントアウトして、store以下を記載して設定します。

# roles/nodejs/files/config.yaml

# path to a directory with all packages
# storage: ./storage
store:
  aws-s3-storage:
    bucket: 【S3バケット名】
    region: 【リージョン】
    accessKeyId: 【アクセスキーID】
    secretAccessKey: 【シークレット】

ついでに日本語化

日本語化されていませんでしたので、localeを設定します。

# roles/nodejs/files/config.yaml

i18n:
  web: ja-JP

pm2の設定

# roles/nodejs/tasks/main.yml

- name: create pm2 startup script
  shell: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ec2-user --hp /home/ec2-user

- name: pm2 startup script save
  shell: pm2 save

- name: start app
  shell: pm2 startOrRestart /home/ec2-user/verdaccio/ecosystem.config.js
  become: false

その他設定は状況に応じて適宜変更して(ログファイルやローテートの設定など)、再度ansible-playbookコマンドを実行します。

コマンド実行が成功すると、pm2がVerdaccioを起動して、ブラウザでVerdaccioが見れるようになる!…はずだったのですが

VerdaccioのjsのhostがローカルIPになってしまう

ブラウザで確認しようとしたところ、真っ白な画面が…。
Webコンソールで確認したところ、どうやら、Verdaccioのjsファイルのhost名にローカルIPが指定されているようです。

下記を参考に、環境変数でVERDACCIO_PUBLIC_URLを設定することにします。
この設定はVerdaccioのconfigファイルでは設定できないようなので、こちらもansible-playbookに追記します。
この時点ではまだ現行サーバで利用しているドメインに切り替えていませんので、一旦ALBのURLを指定します。

verdaccio.org

# roles/nodejs/files/environment

VERDACCIO_PUBLIC_URL='【ALBのURL】'

環境変数を記載したenvironmentファイルを設置する設定も追記します。

# roles/nodejs/tasks/main.yml

- name: VERDACCIO | Put /etc/environment
  copy:
    src: roles/nodejs/files/environment
    dest: /etc/environment

これをansible-playbookコマンドで再反映すると、ブラウザで画面が見れるようになりました。

NPMパッケージの一覧画面ですNPMパッケージの詳細画面です。パッケージダウンロードもここから

最初に実行していたS3へのパッケージ移行スクリプトが完了していたら、npmコマンドをいくつか実行して動作確認してみます。
npm publish/unpublish実行時には、S3バケット内も確認します。

$ npm config set registry 【ALBのURL】
$ npm adduser
$ npm login
$ npm publish
$ npm unpublish [package name@xx.xx.xx]

サーバ切り替え

一通りの動作が確認できましたら、Route 53でドメインを切り替えます。
ansible-playbookでALBのURLが設定されている箇所を切り替え後のドメインを設定し直し、再度ansible-playbookコマンドを実行します。
作業後、切り替え後のドメインで先程のVerdaccioの画面が見れること、npmコマンドが実行できることを確認できたら完了です。

※旧サーバのEC2インスタンスを停止させるのを忘れずに…

サーバ切り替え後に問題が…

これで作業は完了したと思っていたのですが、サーバ移行後しばらくしてからブラウザからVerdaccioにアクセスすると、
NPMパッケージが空っぽの状態(Verdaccio初期設定ページが表示されている)になっていました。
これは私がうっかりしていたのですが、セッションマネージャーからサーバに入った際にも、pm2を起動してしまっていたようで
ssm-userec2-userの両方でpm2が二重起動されている状態でした。
ssm-userのpm2ではALBのURLが参照されていたため、なにかのタイミングでこちらのpm2が参照されたとき、
クロスドメインによるエラーでNPMパッケージ一覧が取得できなくなっていました。
ssm-userのpm2をkillして解決。

Verdaccio自体は200が返りますのでヘルスチェックも通ってしまっていたので、ブラウザにアクセスするまで気付けませんでした。
NPMパッケージが1件も取れなくなった場合にはアラートを飛ばすようにしたほうがいいかもしれません。(今後の課題)

まとめ

細々ハマった箇所はありましたが、設定自体はとてもシンプルで分かりやすい構造になっていると思います。
プライベートNPMレジストリを気軽に構築したい方は、ぜひお試しください。