はじめに
AWS Copilot で Phoenix Framework の本番環境を構築するシリーズです
実装したサンプルはこちらに格納しています
Elixir のリリース手順
以前の記事では mix phx.server
を実行し、 Elixir の開発環境でそのまま Phoenix を起動していました
しかし、本番環境にはソースコードも Elixir も不要です
セキュリティやコンテナ軽量化のため、不要なものは何もない状態が理想です
そこで、 mix release
を実行してビルドした実行可能ファイルのみを本番環境コンテナに配置します
Docker のマルチステージビルド
ビルド用コンテナでビルドして、リリース用コンテナにビルド結果をコピーするので、
Docker のマルチステージビルドを利用します
Dockerfile 内で複数回 FROM 句を書けばマルチステージビルドになります
実装例
###################### ここからビルド用コンテナ ######################
# ビルド用とリリース用は同じ OS でなければならない
# リリース用は軽くしたいので alpine にする
FROM elixir:1.13.4-alpine AS build
ARG SECRET_KEY_BASE
ENV MIX_ENV="prod"
ENV SECRET_KEY_BASE=${SECRET_KEY_BASE}
# ビルドに必要なパッケージをインストールする
RUN apk add --no-cache build-base git npm yarn python3
RUN mix local.hex --force && \
mix local.rebar --force
# ソースコードをコピーする
COPY ./react_chat /app
WORKDIR /app
# 依存パッケージの取得など
RUN mix deps.get --only prod
RUN cd assets && yarn install
RUN mix assets.deploy
RUN mix phx.gen.release
# リリース用にビルドする
RUN mix release
###################### ここまでビルド用コンテナ ######################
###################### ここからリリース用コンテナ #####################
FROM alpine:3.15.4 AS app
ENV MIX_ENV="prod"
ENV HOME=/app
ENV PHX_SERVER=true
# 運用等に必要なパッケージをインストールする(curl や jq はクラスタリングに使用)
RUN apk add --no-cache openssl ncurses-libs curl jq libstdc++
WORKDIR /app
RUN chown nobody:nobody /app
USER nobody:nobody
# ビルド用コンテナからビルド結果をコピーする
COPY --from=build --chown=nobody:nobody /app/_build/${MIX_ENV}/rel/react_chat ./
# mix release で作られた実行可能ファイルから Phoenix を起動する
CMD ["bin/react_chat", "start"]
###################### ここまでリリース用コンテナ #####################
マルチステージビルドのポイント
- ビルド用コンテナとリリース用コンテナの OS は同じにする
- リリース用を軽量にしたいので Alpine Linux を指定する
-
FROM elixir:1.13.4-alpine AS build
というように別名を付ける -
COPY --from=build
というようにビルド用コンテナの別名を指定してリリース用コンテナにコピーする
参考記事:
AWS Copilot の設定
リリース用の Dockerfile を Dockerfile_release とした場合、
AWS Copilot の manifest.yml
では以下のように指定します
name: lb-svc # サービス名
type: Load Balanced Web Service
http:
path: '/'
image:
build:
dockerfile: Dockerfile_release # Dockerfile の指定
context: .
args: # ビルド引数の指定
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
port: 4000
cpu: 256
memory: 512
count:
spot: 2
exec: true
# リリース用コンテナに渡す環境変数
variables:
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
manifest.yml
では ${環境変数}
でローカルの環境変数を渡すことができます
SECRET_KEY_BASE
に任意の値を設定してから copilot svc deploy
を実行してください
まとめ
かつては開発用EC2でビルドした結果を GitHub のリリースにアップロードして、
本番用EC2は GitHub のリリースからダウンロードする、
というややこしい手順を Ansible で実行していました
Docker のマルチステージビルドであれば、
ビルドからデプロイまで Dockerfile 内で定義でき、
非常に分かりやすいです