概要
コンパイルされた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のライフサイクルとアプリケーションのライフサイクルがことなる