🔐

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

6 min read

はじめに

こんにちは。

医療系スタートアップ Ubie株式会社の「Ubie Discovery」というチームで働く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

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}

${NPM_TOKEN} の部分は ~/.npmrc と異なり、実際のアクセストークンに置き換えません。このように書いておくと、npm cli が自動で環境変数 NPM_TOKENの値に置き換えてくれます。環境変数名は好きな名前で大丈夫です。この記事では 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 でビルドすることができるようになりました。

参考

Discussion

ログインするとコメントできます