kentarokentaro

Artifact RegistryにNode.jsのライブラリを作成する【後編】

2025-12-15

はじめに

こんにちは。SRE チーム所属の kentaro です。

この記事は下記の記事の後編になっています。

この記事では上記記事の前編では扱っていなかった、下記2つのトピックを扱っていきます。

  • Next.js側で作成したライブラリをinstallして利用
  • 最後にNext.jsをDockerでビルドしてコンテナ化を行いDocker用のArtifact Registryのプライベートのリポジトリに登録

前編を読んでいない、または気になる方は下記の前編の記事も是非ご覧ください。

前提条件

前提条件としてこの記事では下記のような条件で、前回作成したライブラリの使用、またDocker用のArtifact Registryのプライベートのリポジトリに登録を行っていきます。

  • Google CloudのArtifact Registryを利用
  • CI/CDにはGitHub Actionsを利用
  • Next.jsで利用するパッケージマネージャにはnpmを利用

利用するNode.js、Next.jsとnpmのバージョンは下記の通りです。

  • Node.js version 22.13.0
  • npm version 10.9.2
  • Next.js version 15.5.6

主な流れ

流れとしては下記の流れで行います。

  • ローカル環境にNext.jsをインストール
  • npm用のArtifact Registryのプライベートのリポジトリから前回作成したライブラリをNext.jsにインストール
  • Docker用のArtifact Registryのプライベートのリポジトリを作成
  • Next.jsをDockerでコンテナにビルド
  • ビルドした成果物をDocker用のArtifact Registryのプライベートのリポジトリにアップロード

ローカル環境にNext.jsをインストール

まずはローカル環境にNext.jsをインストールします。

インストールは下記のコマンドでインストールしましょう。

npx create-next-app@15.5.6 ${NEXT_JS_APP_DIRECTORY} --yes
cd ${NEXT_JS_APP_DIRECTORY}

一応下記のコマンドで起動を確認します。

npm run dev

起動が確認できたら次のステップに進みましょう。

npm用のArtifact Registryのプライベートのリポジトリから前回作成したライブラリをNext.jsにインストール

まずは前回作成したArtifact Registryのプライベートのリポジトリに対して、読み込み権限があるかどうかを確認します。

もし読み込み権限がない場合は、下記のロールをArtifact Registry上の対象のプライベートのリポジトリに対して認証を行うアカウントに付与しておきましょう。

  • roles/artifactregistry.reader

.npmrcの作成

下記のように.npmrcをNext.jsのルートディレクトリに作成します。

${LIBRARY_NAME}:registry=https://${LOCATION}-npm.pkg.dev/${PROJECT_NAME}/${REPOSITORY_NAME}/

${LIBRARY_NAME}は前回の記事で作成したライブラリ名を指定します。

@hoge/test-libのような形にしている場合、${LIBRARY_NAME}には@hogeの箇所のみ記載します。

${REPOSITORY_NAME}は作成したライブラリをアップロードした、Artifact Registryのプライベートのリポジトリ名を指定しましょう。

google-artifactregistry-authの追加

.npmrcが作成できたら、次はNext.jsでライブラリをインストールする際に認証を行うために必要なコマンドをpackage.jsonに追加します。

下記のコマンドを追加しましょう。

"scripts": {
  "artifactregistry-login": "npx google-artifactregistry-auth"
}

上記のコマンドを追加したら、Next.jsのルート直下で上記で設定したコマンドを実行します。

npm run artifactregistry-login

上記で認証が通ったら、最後に前回の記事で作成したライブラリをインストールします。

npm install --save-exact ${LIBRARY_NAME}@${VERSION}

ライブラリのインストールができたら実際に利用して確認してみます。

試しにapp/page.tsxに下記のように追加してみましょう。

import Image from "next/image";
import {hello} from "@hoge/test-lib";

export default function Home() {
    hello()
    ...略
}

動かすとコンソール上にhello pnpmと表示されるはずです。

Docker用のArtifact Registry上にプライベートのリポジトリを作成

Next.jsに作成したライブラリをインストールして動かすことができたため、今度は作成したNext.jsをArtifact Registryのプライベートのリポジトリへ登録するための準備をしていきます。

まずはDocker用のArtifact Registryのプライベートのリポジトリを作成します。

下記のコマンドで作成しましょう。

// それぞれ適宜置き換えてください
gcloud artifacts repositories create ${REPOSITORY_NAME} \
    --repository-format=docker \
    --location=asia-northeast1 \
    --description="This is a test docker registry." \
    --project=${PROJECT_ID}

CI/CDで動作させるサービスアカウントの作成

Docker用のArtifact Registryのプライベートのリポジトリが作成できたら、今度はCI/CDで動かすためのサービスアカウントを作成します。

下記のコマンドでCI/CD用のサービスアカウントを作成します。

// それぞれ適宜置き換えてください
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
  --description="DESCRIPTION" \
  --display-name="DISPLAY_NAME"

作成するCI/CDワークフロー上で、作成したDocker用のArtifact Registryのプライベートのリポジトリへ登録するための書き込み権限を付与してあげます。

// それぞれ適宜置き換えてください
gcloud projects add-iam-policy-binding ${PROJECT} \
   --member=serviceAccount:${SERVICE_ACCOUNT_NAME}@example.domain.com \
   --role=roles/artifactregistry.writer

下記のような表示が出ますが、今回はテストなのでNoneを選択しましょう。

The policy contains bindings with conditions, so specifying a condition is required when adding a binding. Please specify a condition.:

前の記事である前編で作成したWorkload Identity Providerに対して認証が通るようにします。

下記の${SERVICE_ACCOUNT_NAME}と${PROJECT}の箇所を作成したものに置き換えて実行してください。

Workload Identity Provider周りの設定については、前回の記事で作成していますので、そちらを参照してください。

gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT_NAME}@${PROJECT}.iam.gserviceaccount.com" \
  --project="${PROJECT_ID}" \
  --role="roles/iam.workloadIdentityUser" \
  --member="principalSet://iam.googleapis.com/${WORKLOAD_IDENTITY_POOL_ID}/attribute.repository/${REPOSITORY_NAME}"

これでサービスアカウントの作成と設定は完了です。

Next.jsをDockerのコンテナにビルド

Artifact Registry上でのプライベートのリポジトリの作成とサービスアカウントの作成ができたら、Next.jsをDockerでビルドできるようにします。

まずは、Next.js単体でビルドできるか確認しましょう。

ビルドするには下記のコマンドを実行します。

npm run build

おそらく現状の状態でnpm run buildすると下記のようにエラーが表示されると思います。

implicitly has an 'any' type.

今回はあくまでデモのため、下記のように@ts-ignoreを使って回避してください。

import Image from "next/image";
// @ts-ignore
import {hello} from "@hoge/test-lib";

export default function Home() {
    hello()
    ...略
}

もう一度下記のコマンドを実行してビルドが通ることを確認してください。

npm run build

Dockerfileの追加

ビルドが通ることを確認したら、Next.jsのルート直下にDockerfileを追加します。

追加するDockerfileは、Next.jsの公式サイトで紹介されているDockerをベースにしていきます。

上記のページを開いたらタグからバージョンを今回利用しているバージョンに合わせてv15.5.6のものを利用します。

上記をベースにして下記のDockerfileを作成しましょう。

FROM node:22-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN --mount=type=secret,mode=0644,id=npmrc,target=/app/.npmrc npm ci


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1

RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000

# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

追加部分について

追加した下記の部分は、後述のGitHub Actions上で生成した認証情報を利用するための記載です。

RUN --mount=type=secret,mode=0644,id=npmrc,target=/app/.npmrc npm ci

今回はnpmを利用しているためnpmのものに書き換えましたが、もしnpm以外のものが必要な場合は適時置き換えてください。

RUNに追加しているフラグについて

今回はArtifact Registryへの認証を行うため、secretを読み込むために下記のフラグを追加しています。

--mount=type=secret,mode=0644,id=npmrc,target=/app/.npmrc

上記のようにしている理由は下記のDocker公式の記載にある通り、成果物であるイメージにシークレットを残さないようにするためです。

Build arguments and environment variables are inappropriate for passing secrets to your build,
because they persist in the final image.

Instead, you should use secret mounts or SSH mounts,
which expose secrets to your builds securely.

参考:https://docs.docker.com/build/building/secrets

後述のGitHub Actionsの下記の箇所に登場しますが、Actionsで下記のようにGoogle Cloudへ認証するための認証情報が入った.npmrcファイルをDockerのビルド時に参照できるように渡しています。

- name: Build and push
  uses: docker/build-push-action@v6
  with:
    platforms: linux/amd64
    load: false
    push: true
    tags: ${{ steps.set-container-image-name.outputs.registry_path }}${{ $IMAGE_NAME }}:latest
    context: *package_working_directory
    secret-files: |
      npmrc=$PATH_TO_APPLICATION_DIRECTORY/.npmrc

上記のnpmrcの部分がDocker build時の下記の箇所のidと対応しています。

--mount=type=secret,mode=0644,id=npmrc,target=/app/.npmrc

上記を利用することで、Google CloudのArtifact Registryの認証をDockerの公式が推奨している方法で行うことができます。

For secret mounts and SSH mounts, using build secrets is a two-step process.
First you need to pass the secret into the docker build command,
and then you need to consume the secret in your Dockerfile.

参考:

他の準備

実際にビルドやGitHub Actionsを動かす前に.dockerignoreに下記を追加します。

.npmrc

追加できたら今度は下記を.gitignore, .dockerignoreに追加します。

gha-creds-*.json

上記のgha-creds-*.jsonについては下記のgoogle-github-actionsのauth@v2のPrerequisitesの箇所に記載されています。

ビルドした成果物をDocker用のArtifact Registryのプライベートのリポジトリにアップロード

Dockerfileを作成したら、今度は作成したDockerfileをArtifact RegistryのプライベートのリポジトリへGitHub Actions経由でアップロードしていきます。

下記のようなGitHub Actionsを作成してArtifact Registryのプライベートのリポジトリに対してアップロードします。

また下記のアクションはトリガーされるイベントにpushイベントを利用していますが、必要に応じて適宜置き換えてください。

name: upload dockerfile to artifact registry
on:
  push:
    branches:
      - feature/**

permissions: {}

jobs:
  build:
    permissions:
      contents: read
      id-token: write
    runs-on: ubuntu-latest
    timeout-minutes: 60
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Authentication with Google Cloud
        id: google-auth
        uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: $WORKLOAD_IDENTITY_PROVIDER
          service_account: $SERVICE_ACCOUNT
          token_format: access_token

      - name: Generate npm registry path
        shell: bash
        id: npm-registry-path
        env:
          RP_PROJECT: &project_id $GOOGLE_CLOUD_PROJECT_ID
          RP_LOCATION: &location asia-northeast1
          RP_REPOSITORY_NAME: $NPM_ARTIFACT_REGISTRY_REPOSITORY_NAME
        run: |
          echo "registry_path=${{ env.RP_LOCATION }}-npm.pkg.dev/${{ env.RP_PROJECT }}/${{ env.RP_REPOSITORY_NAME }}/" >> $GITHUB_OUTPUT

      - name: Setup .npmrc
        working-directory: &package_working_directory $WORKING_DIRECTORY
        shell: bash
        env:
          REGISTRY_PATH: ${{ steps.npm-registry-path.outputs.registry_path }}
          AUTH_ACCESS_TOKEN: ${{ steps.google-auth.outputs.access_token }}
        run: |
          if [ -f ".npmrc" ]; then
            echo ".npmrc already exists. Appending registry..."
            echo "//${{ env.REGISTRY_PATH }}:_authToken=\"${{ env.AUTH_ACCESS_TOKEN }}\"" >> .npmrc
            echo "//${{ env.REGISTRY_PATH }}:always-auth=true" >> .npmrc
          else
            echo ".npmrc does not exist. Creating..."
            echo "//${{ env.REGISTRY_PATH }}:_authToken=\"${{ env.AUTH_ACCESS_TOKEN }}\"" >> .npmrc
            echo "//${{ env.REGISTRY_PATH }}:always-auth=true" >> .npmrc
          fi

      - name: Generate docker registry path
        shell: bash
        id: set-container-image-name
        env:
          RP_PROJECT: *project_id
          RP_LOCATION: *location asia-northeast1
          RP_NAME: $DOCKER_ARTIFACT_REGISTRY_REPOSITORY_NAME
          IMAGE_NAME: $CONTAINER_IMAGE_NAME
        run: |
          echo "registry_path=${{ env.RP_LOCATION }}-docker.pkg.dev/${{ env.RP_PROJECT }}/${{ env.RP_NAME }}/" >> $GITHUB_OUTPUT

      - name: Configure docker for artifact registry
        shell: bash
        run: gcloud auth configure-docker "asia-northeast1-docker.pkg.dev"

      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          platforms: linux/amd64
          load: false
          push: true
          tags: ${{ steps.set-container-image-name.outputs.registry_path }}${{ $IMAGE_NAME }}:latest
          context: *package_working_directory
          secret-files: |
            npmrc=$PATH_TO_APPLICATION_DIRECTORY/.npmrc

上記のGitHub Actionsについて解説します。

Setup .npmrcについて

下記のstepでは、Docker build時にGitHub Actions上からGoogle CloudのArtifact Registryへの認証に必要な認証情報を生成しています。

- name: Setup .npmrc
  working-directory: &package_working_directory $WORKING_DIRECTORY
  shell: bash
  env:
    REGISTRY_PATH: ${{ steps.npm-registry-path.outputs.registry_path }}
    AUTH_ACCESS_TOKEN: ${{ steps.google-auth.outputs.access_token }}
  run: |
    if [ -f ".npmrc" ]; then
      echo ".npmrc already exists. Appending registry..."
      echo "//${{ env.REGISTRY_PATH }}:_authToken=\"${{ env.AUTH_ACCESS_TOKEN }}\"" >> .npmrc
      echo "//${{ env.REGISTRY_PATH }}:always-auth=true" >> .npmrc
    else
      echo ".npmrc does not exist. Creating..."
      echo "//${{ env.REGISTRY_PATH }}:_authToken=\"${{ env.AUTH_ACCESS_TOKEN }}\"" >> .npmrc
      echo "//${{ env.REGISTRY_PATH }}:always-auth=true" >> .npmrc
    fi

if文で分岐している通り、.npmrcが存在していれば追加、なければ作成を行っています。

_authTokenはAuthentication with Google Cloud stepで出力したaccess tokenを設定します。

Dockerのbuild時はこのトークンを利用して、Google CloudのArtifact Registryへ認証を行います。

always-auth=trueはGet Requestなどでも常に認証を求める設定です。

それぞれ下記のリンクに参照を載せておきます。

Configure docker for artifact registryについて

下記のstepでは、gcloud auth configure-dockerを使用してDockerがasia-northeast1のArtifact Registryへの認証情報を構成できるようにしています。

- name: Configure docker for artifact registry
  shell: bash
  run: gcloud auth configure-docker "asia-northeast1-docker.pkg.dev"

まとめ

この記事ではNext.jsでGoogle CloudのArtifact Registryのプライベートのリポジトリ上に存在しているライブラリをインストールして利用、実際にライブラリをインストールしたNext.jsをArtifact Registryのプライベートのリポジトリへ登録するところまでを行いました。

私はこの対応を行うのに色々と調査したため、この記事が私と同じように悩む人の助けになれば幸いです。

また、弊社 Belong では一緒に働く仲間を募集しています。

興味がある方は エンジニアリングチーム紹介ページ をご覧ください。

No table of contents available for this content