🔐

プライベートなnpmパッケージをDockerfileでインストールしてGitHub Actionsでビルドする

2022/02/12に公開

はじめに

こんにちは。

医療系スタートアップUbie株式会社の「Ubie Discovery」というチームで働く@jimboです。Webフロントエンドが得意なソフトウェアエンジニアです。

社内限定のプライベートなnpmパッケージを開発し、npm registryやGitHub Packagesに登録して、さまざまなプロジェクトでnpm installして利用したいことがあります。
(UbieにもGitHub Packagesで管理するプライベートなnpmパッケージが存在しています。)

パブリックなパッケージと違い、プライベートなパッケージをnpm installするためには、npm registryあるいはGitHub Packagesへのアクセストークンが必要です。個人(ローカル)で利用する場合は、アクセストークンを記載した ~/.npmrc ファイルを用意すればOKです。

~/.npmrc
# npm registory を利用している場合
//registry.npmjs.org/:_authToken=YOUR_ACCESS_TOKEN
# GitHub Packages を利用している場合
//npm.pkg.github.com/:_authToken=YOUR_ACCESS_TOKEN

しかし、Dockerfile内でnpm installをしている場合は、 ~/.npmrc を参照できないためうまくいきません。別の方法でDockerにアクセストークンを参照させる必要があり、かつGitHub ActionsでDockerをビルドするには、いくつかの工夫が必要です。

今回はその方法について調べたので、まとめてみます。

Dockerfileでプライベートなパッケージをnpm installする

次のようなDockerfileでは、npm install時に認証エラーとなってしまいます。

Dockerfile
FROM node:alpine

COPY package*.json ./
RUN npm install

...
$ docker image build .
 => ...
 => [1/3] FROM docker.io/library/node:alpine@sha256:f372a9ffcec27159dc9623bad29997a1b61eafbb145dbf4f7a64568be2f59b99                                       0.0s
 => CACHED [2/3] COPY package*.json ./                                                                                                                     0.0s
 => ERROR [3/3] RUN npm install                                                                                                                            2.3s
------
 > [3/3] RUN npm install:
#6 2.211 npm ERR! code E401
#6 2.213 npm ERR! Incorrect or missing password.
#6 2.213 npm ERR! If you were trying to login, change your password, create an
#6 2.213 npm ERR! authentication token or enable two-factor authentication then
#6 2.213 npm ERR! that means you likely typed your password in incorrectly.
#6 2.213 npm ERR! Please try again, or recover your password at:
#6 2.213 npm ERR!     https://www.npmjs.com/forgot
#6 2.213 npm ERR!
#6 2.213 npm ERR! If you were doing some other operation then your saved credentials are
#6 2.213 npm ERR! probably out of date. To correct this please try logging in again with:
#6 2.214 npm ERR!     npm login
#6 2.222
#6 2.222 npm ERR! A complete log of this run can be found in:
#6 2.222 npm ERR!     /root/.npm/_logs/2021-06-10T12_58_35_383Z-debug.log

これはDockerでnpm installする際に、Dockerにアクセストークンが渡されていないのが原因です。

プロジェクト専用の.npmrcファイルを用意する

まず、~/.npmrc とは別に、プロジェクト専用の .npmrc ファイルをプロジェクトのルートディレクトリ(package.json と同じ場所)に用意します。

ファイルの中身は次のようにします。(GitHub Packagesを利用した例です)

.npmrc
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}

Dockerfileで.npmrcを参照できるようにする

次に、用意した .npmrc ファイルをDockerfile内でコピーして、 npm install時に参照されるようにします。

Dockerfile
FROM node:alpine

COPY .npmrc .npmrc
COPY package*.json ./
RUN npm install

ただし、まだ環境変数 NPM_TOKEN がDockerfile内で定義されていないため、このままではやはりエラーとなります。

環境変数をDockerfileに渡す

Docker内で環境変数を参照するにはどうすればよいでしょう。

次のようにDockerfile内で環境変数をセットするのは可能ですが、Dockerfileにアクセストークンを直接書くのは管理上避けるべきです。

Dockerfile
FROM node:alpine

ENV NPM_TOKEN xxxxxxxxxxxxxxx
COPY .npmrc .npmrc
COPY package*.json ./
RUN npm install

そこで利用できるのが、ARG パラメータ です。(Docker 1.9から利用可能です)
ARGパラメータを使うと、Dockerの外側からDocker内部に環境変数を渡すことができます。

次のようにDockerfileを変更します。

Dockerfile
FROM node:alpine

ARG NPM_TOKEN
COPY .npmrc .npmrc
COPY package*.json ./
RUN npm install

これで環境変数 NPM_TOKEN を受け取ることができます。

最後に、dockerビルド時に --build-arg オプションを使って環境変数を指定します。これでDockerの外側からDocker内部に環境変数を渡すことができるようになりました。

$ export NPM_TOKEN=xxxxxxxxx
$ docker build --build-arg NPM_TOKEN=${NPM_TOKEN} .

GitHub ActionsでDockerビルドする

ローカル環境であれば、上記のように環境変数 NPM_TOKEN にトークンをセットすればよいのですが、GitHub Actionsで docker build を実行する場合はどうすればよいでしょう。

次のように GitHub Actionsのワークフローファイル内で環境変数を設定することもできますが、YAMLファイルに直接トークンを書くのはやはり避けたいところです。

.github/workflows/build.yml
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      NPM_TOKEN: xxxxxxxxxx
    steps:
      - name: Build Image
        run: |
          docker image build --build-arg NPM_TOKEN=${{ env.NPM_TOKEN }} .

GitHubのシークレットを使うと、安全に管理されたアクセストークンを利用できます。

Organizationリポジトリ 単位でシークレットを作成できますが、社内でプライベートなnpmパッケージを用意している場合は、Organizationでシークレットを作成しておくと、さまざまなリポジトリで利用しやすくなります。

作成したシークレットは、GitHub Actionsのワークフローファイルでは ${{ secrets.xxxxxxx }} で参照できます。例えば、ACCESS_TOKEN_GITHUB_PACKAGE_REGISTRY という名前でシークレットを用意した場合は、次のようになります。

.github/workflows/build.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build Image
        run: |
          docker image build --build-arg NPM_TOKEN=${{ secrets.ACCESS_TOKEN_GITHUB_PACKAGE_REGISTRY }} .

これで、privateなnpmパッケージをDockerfileでインストールしてGitHub Actionsでビルドできるようになりました。

参考

Ubie テックブログ

Discussion