MEAN StackをDocker Composeで動かす
前回はMEAN StackをHeroku上で動かしてみました。
hi1280.hatenablog.com
今回はMEAN Stackアプリに手を加えて、Dockerに対応させます。
Dockerにすれば、他の環境への移行も楽になるのではと思います。
Docker Composeを使って、nginx+Node.js+MongoDBの環境でMEAN Stackアプリを動かします。
プログラム一式はこちら
github.com
Docker Composeを使って、以下の3つのコンテナで構成します。
- nginxでAngularを動かす(フロントエンドアプリ)
- Node.jsでExpressを動かす(バックエンドアプリ)
- MongoDBを動かす(DB)
Angularビルド環境用のDockerfile
AngularビルドのためにAngular CLI環境のDockerfileを作ります。
Dockerfile
FROM node:8.11.3-alpine LABEL authors="hi1280" RUN npm install -g @angular/cli@6.0.8 RUN npm cache clean --force
Node.jsの環境にAngular CLIをインストールしているだけというシンプルなモノです。
Angularアプリ実行用のDockerfile
Angularをビルドして、それをそのままDockerコンテナに含めると容量がかなり大きくなってしまいます。
そのため、Angularビルドとnginx上でのAngularアプリの実行を分けます。
これはDockerのマルチステージビルドの機能を使えば、実現できます。
Use multi-stage builds | Docker Documentation
マルチステージビルドを用いたDockerfileを作ります。
Dockerfile
# Angular Build FROM hi1280/angular-cli:latest as build-stage WORKDIR /usr/src/app COPY ["package.json", "package-lock.json*", "./"] RUN npm install --production --silent COPY . . RUN npm run build # nginx FROM nginx:alpine RUN rm -rf /usr/share/nginx/html/* COPY --from=build-stage /usr/src/app/dist/mean-example /usr/share/nginx/html COPY ./nginx /etc/nginx/conf.d CMD ["nginx", "-g", "daemon off;"]
COPY --from=build-stage
でビルド後の成果物のみをコピーしています。
これにより、最小限のファイルサイズになります。
AngularでビルドしたHTMLリソースをnginxで動かすDockerコンテナになります。
Express実行用のDockerfile
Expressを動かすDockerfileを作ります。
Dockerfile
FROM node:8.11.3-alpine WORKDIR /usr/src/app COPY ["server.js", "/src/server/package.json", "/src/server/package-lock.json", "./"] COPY ["/src/server", "./src/server"] RUN npm install --production --silent EXPOSE 3000 ENV NODE_ENV production CMD [ "node", "server.js" ]
Node.jsの環境を公式のイメージから取得して、Expressを動かすだけのDockerコンテナになります。
Docker Composeで各コンテナを連携
これまでに用意した各Dockerコンテナを連携します。
docker-compose.yml
version: '2.1' services: frontend: build: context: . dockerfile: Dockerfile-frontend ports: - 80:80 environment: - APP_HOST=backend - APP_PORT=3000 command: /bin/sh -c "envsubst '$$APP_HOST$$APP_PORT' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'" depends_on: - backend backend: build: context: . dockerfile: Dockerfile-backend ports: - 3000:3000 depends_on: - db environment: - MONGODB_URI=mongodb://db:27017/my-heroes db: image: mongo:3.4.16-jessie restart: always volumes: - /data/db:/data/db
URLにサービス名を指定することで、各サービスにアクセスすることができます。
mongodb://db:27017/my-heroes
といった形です。
depends_on
を指定することで、サービスを立ち上げるために事前に起動が必要なサービスを指定できます。
これにより、サービスを起動する順番を制御することができます。
Docker Composeにおけるnginxの設定変更
環境変数を用いて動的にnginxの設定を変更しています。
nginxの公式Dockerイメージにそのやり方が記載されています。(Using environment variables in nginx configurationという箇所です)
https://hub.docker.com/_/nginx/
こちらも参考にしました。
Docker上のNginxのconfに環境変数(env)を渡すたったひとつの全く優れてない方法(修正:+優れている方法)
default.conf.template
server { listen 80; server_name localhost; location /api/ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://${APP_HOST}:${APP_PORT}/api/; } location / { root /usr/share/nginx/html; index index.html index.htm; } }
${APP_HOST}と${APP_PORT}が環境変数で定義した値に変わります。
Expressのサービス名にアクセスする設定になります。
まとめ
公式のDockerイメージを活用すれば、プログラムをコピーして、起動コマンドを実行するといった形で、Dockerコンテナ化できるので難しいことはあまりないかなと思います。
ハマったら、コンテナのシェルに入ってデバッグするといったことができると良いです。