SPAアプリケーションのコンテナ化と設定値について

概要

コンパイルされたJavaScriptのSPAアプリケーションがある。
これはDockerコンテナ上で動いている。
このアプリはdev,stg,prdなどの環境ごとに異なるAPIエンドポイントを持つ。
この環境ごとに異なる設定値をどのように扱うか。

問題点

フロントエンドで実行されるJSファイルに設定値が含まれているので、コンテナ実行時に環境変数として渡すことができない。

結論

各方針のデメリットと現状の要件を照らし合わせ適切な方法を選択する。

方法一覧

案1

環境ごとにアプリケーションををビルドする。 実行時にどのバンドルを実行するか指定する。

デメリット

ビルドに時間がかかる。 イメージの容量が大きくなる。

下記にNext.jsの具体例を示す。

Dockerfile

FROM node:alpine as builder

WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci \
    && APP_ENV=development npm run build \
    && mv /usr/src/app/.next /usr/src/app/.next_development \
    && APP_ENV=staging npm run build \
    && mv /usr/src/app/.next /usr/src/app/.next_staging \
    && APP_ENV=production npm run build \
    && mv /usr/src/app/.next /usr/src/app/.next_production \
    && npm ci --production
COPY . /usr/src/app/

FROM node:alpine as runner
WORKDIR /usr/src/app
COPY --from=builder /usr/src/app/.next_development /usr/src/app/.next_development
COPY --from=builder /usr/src/app/.next_staging /usr/src/app/.next_staging
COPY --from=builder /usr/src/app/.next_production /usr/src/app/.next_production
COPY --from=builder /usr/src/app/node_modules /usr/src/app/node_modules
COPY package*.json ./
COPY start.sh ./

CMD ash -c "./start.sh -d && ./node_modules/.bin/next start"

start.sh

#!/bin/ash
ln -s /usr/src/app/.next_${APP_ENV}/ /usr/src/app/.next

案2

環境ごとの設定ファイルを作り、実行時にフロントエンドから取得する。
具体的なイメージは参考リンク参照。
参考:https://www.barrydobson.com/post/configure-spa-docker/

デメリット

ユーザが設定を取得するためのリクエストを送らなければならない。

案3

環境ごとにDockerイメージをビルドする。

これはアンチパターンなので採用しない。
理由

  • ある環境で保証されていたことが別の環境では保証されなくなる
  • 開発が進むに連れ環境ごとの差分が発生する

参考:https://codefresh.io/containers/docker-anti-patterns/

案4

コンテナ実行時にビルドする。

デメリット

  • Dockerのライフサイクルとアプリケーションのライフサイクルがことなる
  • コンテナ実行時にビルドが失敗してコンテナが起動できない可能性がある

ライフサイクルがことなることで他のアプリケーションとの違いを意識する必要がある。メトリクス計測に影響が出る。
ビルドに成功したDockerイメージのみをDockerレジストリに登録する。

案4.5

コンテナ実行時に再ビルドする

  • docker build時にnpm run build
  • docker run時にnpm build && npm start

デメリット

上記と同じくDockerのライフサイクルとアプリケーションのライフサイクルがことなる