JavaScript
angular

Docker にパックした SPA に環境変数を埋め込む

SPA を Docker でホストするときによく思うことが、Environment Variables をSPA に渡したい!と思うことだ。例えば、バックエンドサーバーの URL 等だ。実際にこれは出来ない。なぜかというと、動作するのはあくまでユーザのブラウザ上だからだ。通常は、CIでそれらをインジェクトしてデプロイする。

そのインジェクションを Docker build の時にやってしまいたいので、そういうコードを書いてみた。

環境変数のビルド時におけるインジェクション

インジェクト用のシェルファイル

例えば Angular だったら、src/environments/environment.ts 等を書きかえる。

environment.ts

export const environment = {
  production: false,
  backendUrl: "https://somethingfunctionapp.azurewebsites.net/api/SomeStatus"
};

これをFUNCTION_NAME という環境変数で上書きされるようにスクリプトを書いておく。ここでポイントは、正規表現の記述が / ではなく | を使っていること。これは、somethingfunctionapp/$FUNCTION_NAME だと、ディレクトリ名と区分けがつかなくなり、somethingfunctionapp//somename などに変換されるため。

inject.sh

#!/bin/sh

grep -l 'somethingfunctionapp' src/environments/*.ts | xargs sed -i.bak -e "s|somethingfunctionapp|$FUNCTION_NAME|g" 

Dockerfile

通常だと、実行しているシェルの環境変数は引き継がれない。ARG を用いる。

FROM node:8-alpine AS build
WORKDIR /usr/src/app
RUN npm i -g @angular/cli
COPY . .
ARG FUNCTION_NAME
RUN sh inject.sh
RUN npm install --silent
RUN npm run build

FROM nginx:1.13.12-alpine
WORKDIR /app
RUN rm -rf /usr/share/nginx/html
# COPY ./dist /usr/share/nginx/html # Useful for local builds
COPY --from=build /usr/src/app/dist /usr/share/nginx/html

こうしておくと実行時に次のようにして環境変数を渡すことができる。

docker build --build-arg FUNCTION_NAME="$FUNCTION_NAME" . -t abc

あとはこの docker build を実行すると無事に実行時すれば完了。

あとがき

ちなみに、これを作り終えてから気が付いたが、このファイル書き換えの方法をスタートアップスクリプトを作って、それが環境変数をインジェクトするようにすると、docker コンテナの環境変数でもインジェクトできることに気が付いた。こんかいのユースケースではそこまで不要なのでやってないが、そっちのほうがカッコいいかも。