phx.gen.releaseを試して爆速でfly.ioにデプロイしてみよう
この記事はelixir Advent Calendar 2021の11日目です🎄
10日目は@Gsannさんの【Elixir】ElixirでGoogleAPIを実行してYoutubeの動画情報を取得する でした。
今回のテーマ
fukuoka.ex Elixir/Phoenixアドベントカレンダー 初日の記事のラストで phx.gen.docker
なるコマンドが生えそうと書いていたのですが、それがすでにmergeされ、Phoenixのv1.6.3でリリースされているようでした。
また、それを使ったデモ動画もtweetされています。
今回はそんなホットな phx.gen.release
を使ってみて、プロジェクトの作成からfly.ioまでのデプロイをやってみたいと思います。
前提
今回の記事ではflyのCLIのインストールやサインアップは済んでいる前提で記述します。
CLIのインストールやサインアップに関してはガイドを参考にしてみてください。
余談
ドキュメントを見てると fly
と flyctl
というコマンドが混在している様ですが、
-
flyctl
: 実行ファイル -
fly
:flyctl
へのシンボリックリンク
となっており、どちらを叩いても同じなようです。ゆくゆくは fly
だけになっていきそうな気がしています。
動作環境
$ fly version
fly v0.0.269 darwin/amd64 Commit: 1b5490b BuildDate: 2021-12-10T19:02:43Z
$ mix phx.new --version
Phoenix installer v1.6.4
実践
構成を簡単にするため、今回は --no-ecto
で試してみます
$ mix phx.new fly_deploy_demo --no-ecto
* creating fly_deploy_demo/config/config.exs
* creating fly_deploy_demo/config/dev.exs
* creating fly_deploy_demo/config/prod.exs
...中略
* creating fly_deploy_demo/priv/static/robots.txt
* creating fly_deploy_demo/priv/static/images/phoenix.png
* creating fly_deploy_demo/priv/static/favicon.ico
Fetch and install dependencies? [Yn] y
* running mix deps.get
* running mix deps.compile
We are almost there! The following steps are missing:
$ cd fly_deploy_demo
Start your Phoenix app with:
$ mix phx.server
You can also run your app inside IEx (Interactive Elixir) as:
$ iex -S mix phx.server
言われた通り、プロジェクト作成後はディレクトリを移動しましょう。
$ cd fly_deploy_demo
ここで本命の phx.gen.release
コマンドを --docker
オプション付きで実行します。
$ mix phx.gen.release --docker
* creating rel/overlays/bin/server
* creating rel/overlays/bin/server.bat
* creating Dockerfile
* creating .dockerignore
Your application is ready to be deployed in a release!
See https://hexdocs.pm/mix/Mix.Tasks.Release.html for more information about Elixir releases.
Using the generated Dockerfile, your release will be bundled into
a Docker image, ready for deployment on platforms that support Docker.
For more information about deploying with Docker see
https://hexdocs.pm/phoenix/releases.html#containers
Here are some useful release commands you can run in any release environment:
# To build a release
mix release
# To start your system with the Phoenix server running
_build/dev/rel/fly_deploy_demo/bin/server
Once the release is running you can connect to it remotely:
_build/dev/rel/fly_deploy_demo/bin/fly_deploy_demo remote
To list all commands:
_build/dev/rel/fly_deploy_demo/bin/fly_deploy_demo
リリースに使用するDockerfileを含む、以下のファイルが生成されました。
- .dockerignore
- Dockerfile
- rel/overlays/bin/server
- rel/overlays/bin/server.bat
diffはこんな感じ
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..a03cecf
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,18 @@
+.dockerignore
+# there are valid reasons to keep the .git, namely so that you can get the
+# current commit hash
+#.git
+.log
+tmp
+
+# Mix artifacts
+_build
+deps
+*.ez
+releases
+
+# Generate on crash by the VM
+erl_crash.dump
+
+# Static artifacts
+node_modules
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..5812ccc
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,89 @@
+# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian instead of
+# Alpine to avoid DNS resolution issues in production.
+#
+# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu
+# https://hub.docker.com/_/ubuntu?tab=tags
+#
+#
+# This file is based on these images:
+#
+# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image
+# - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20210902-slim - for the release image
+# - https://pkgs.org/ - resource for finding needed packages
+# - Ex: hexpm/elixir:1.13.0-erlang-24.0.1-debian-bullseye-20210902-slim
+#
+ARG BUILDER_IMAGE="hexpm/elixir:1.13.0-erlang-24.0.1-debian-bullseye-20210902-slim"
+ARG RUNNER_IMAGE="debian:bullseye-20210902-slim"
+
+FROM ${BUILDER_IMAGE} as builder
+
+# install build dependencies
+RUN apt-get update -y && apt-get install -y build-essential git \
+ && apt-get clean && rm -f /var/lib/apt/lists/*_*
+
+# prepare build dir
+WORKDIR /app
+
+# install hex + rebar
+RUN mix local.hex --force && \
+ mix local.rebar --force
+
+# set build ENV
+ENV MIX_ENV="prod"
+
+# install mix dependencies
+COPY mix.exs mix.lock ./
+RUN mix deps.get --only $MIX_ENV
+RUN mkdir config
+
+# copy compile-time config files before we compile dependencies
+# to ensure any relevant config change will trigger the dependencies
+# to be re-compiled.
+COPY config/config.exs config/${MIX_ENV}.exs config/
+RUN mix deps.compile
+
+COPY priv priv
+
+# note: if your project uses a tool like https://purgecss.com/,
+# which customizes asset compilation based on what it finds in
+# your Elixir templates, you will need to move the asset compilation
+# step down so that `lib` is available.
+COPY assets assets
+
+# compile assets
+RUN mix assets.deploy
+
+# Compile the release
+COPY lib lib
+
+RUN mix compile
+
+# Changes to config/runtime.exs don't require recompiling the code
+COPY config/runtime.exs config/
+
+COPY rel rel
+RUN mix release
+
+# start a new build stage so that the final image will only contain
+# the compiled release and other runtime necessities
+FROM ${RUNNER_IMAGE}
+
+RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \
+ && apt-get clean && rm -f /var/lib/apt/lists/*_*
+
+# Set the locale
+RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
+
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+
+WORKDIR "/app"
+RUN chown nobody /app
+
+# Only copy the final release from the build stage
+COPY --from=builder --chown=nobody:root /app/_build/prod/rel/fly_deploy_demo ./
+
+USER nobody
+
+CMD /app/bin/server
\ No newline at end of file
diff --git a/rel/overlays/bin/server b/rel/overlays/bin/server
new file mode 100755
index 0000000..e58a784
--- /dev/null
+++ b/rel/overlays/bin/server
@@ -0,0 +1,3 @@
+#!/bin/sh
+cd -P -- "$(dirname -- "$0")"
+PHX_SERVER=true exec ./fly_deploy_demo start
diff --git a/rel/overlays/bin/server.bat b/rel/overlays/bin/server.bat
new file mode 100755
index 0000000..6a07875
--- /dev/null
+++ b/rel/overlays/bin/server.bat
@@ -0,0 +1,2 @@
+set PHX_SERVER=true
+call "%~dp0\fly_deploy_demo" start
\ No newline at end of file
flyのセットアップ
flyの設定を進めます。 fly launch
を実行して設定ファイルを生成します。
App Nameを空でEnterを押して進めるとランダムな値が生成されます。 ? Would you like to deploy now?
と聞かれますが、このタイミングでは N
を押してskipしましょう。
$ fly launch
Creating app in /Users/koga/ghq/github.com/koga1020/fly_deploy_demo
Scanning source code
Detected a Dockerfile app
? App Name (leave blank to use an auto-generated name):
Automatically selected personal organization: Koga Shozo
? Select region: nrt (Tokyo, Japan)
Created app frosty-feather-5742 in organization personal
Wrote config file fly.toml
? Would you like to deploy now? No
Your app is ready. Deploy with `flyctl deploy`
続いて、ガイドと同じように fly.toml
を修正します。今回は --no-ecto
で実行しているため、 [deploy]
の設定は省略しています。
# fly.toml file generated for frosty-feather-5742 on 2021-12-11T19:27:06+09:00
# ここは各自設定したApp Nameで読み替えてください
app = "frosty-feather-5742"
kill_signal = "SIGTERM"
kill_timeout = 5
[env]
[[services]]
internal_port = 4000
protocol = "tcp"
[services.concurrency]
hard_limit = 25
soft_limit = 20
[[services.ports]]
handlers = ["http"]
port = 80
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[[services.tcp_checks]]
grace_period = "30s" # allow some time for startup
interval = "15s"
restart_limit = 6
timeout = "2s"
環境変数の設定
fly secrets
コマンドを利用して
PHX_HOST
SECRET_KEY_BASE
の環境変数を設定します。
# <APP NAME>.fly.dev で読み替えてください
$ fly secrets set PHX_HOST=frosty-feather-5742.fly.dev
Secrets are staged for the first deployment
$ fly secrets set SECRET_KEY_BASE=`mix phx.gen.secret`
Secrets are staged for the first deployment
デプロイの実行
やることはこれだけで、あとはdeployするだけです! fly deploy
でコンテナイメージのbuild, pushを行います。
$ fly deploy
1,2分そこら待って、fly status
でヘルスチェックを通ったのを確認しましょう。
$ fly status
App
Name = frosty-feather-5742
Owner = personal
Version = 0
Status = running
Hostname = frosty-feather-5742.fly.dev
Deployment Status
ID = e621ce72-ba5d-305b-bb79-e9b4d5686503
Version = v0
Status = successful
Description = Deployment completed successfully
Instances = 1 desired, 1 placed, 1 healthy, 0 unhealthy
Instances
ID PROCESS VERSION REGION DESIRED STATUS HEALTH CHECKS RESTARTS CREATED
e8f35aca app 0 nrt run running 1 total, 1 passing 0 1m53s ago
ヘルスチェックが通ったら、 fly open
でアプリを開きます。
$ fly open
いつもの画面が見れたらOKです!お疲れ様でした🍵
まとめ
phx.gen.release
で生成されたDockerfileを利用してfly.ioへのデプロイまで行なってみました。まっさらなプロジェクトを作成してから、修正したのはtomlファイルのみというのが驚きです!このスピード感は楽しいですね!
生成されたDockerfileをベースに、localeを変更するなり必要に応じてカスタマイズすれば十分使える気がします。
明日は @the_haigo さんの記事です!お楽しみに!
Discussion
ヤバすぎますね!