はじめに
前回の記事で Petal Pro をローカル実行しました
今回はこのアプリを Fly.io にデプロイしてみます
ただし、以下の点については開発用のままデプロイします
- Faker で生成した出鱈目な文字列
- メール送信機能
Fly.io とは
Fly.io の公式ドキュメントに説明があります
Fly.io: A New Public Cloud
Fly.io はパブリッククラウドサービスで、 Web アプリケーションをデプロイすることでインターネット上に公開、つまり本番運用することが可能です
大きな特長は以下のものが挙げられます
- Docker コンテナで簡単にアプリケーション、環境を定義できる
- Web アプリケーションを最大3つまで無料で運用できる
- PostgreSQL をクラウド上で簡単に安く使える
- CLI で簡単に操作できる
今の所、私の不満は以下の点です
- GPU が使えない(有償でも)
GPU が使えるようになりました
Docker コンテナによるアプリケーション定義
AWS を使う場合、様々なサービスを組み合わせてコストパフォーマンス最適なシステム構成を設計、運用します
そのため、システム構築には AWS 自体への深い理解が必要になります
VPC の設定や、 RDS Proxy を通した DB 接続や、 IAM の詳細な権限設定など、知らないといけないことが大量にあります
AWS Copilot などを使うことでかなり簡単にはなります
Fly.io では、 fly launch
コマンドを実行するだけで Dockerfile を自動生成してくれる上に、 DB との接続などなどもよしなにやってくれます
fly deploy
コマンドだけでデプロイでき、コンテナのビルドもリモートで実行するため開発者のマシンに Docker がなくても問題ありません
開発者は AWS Lambda 以上にインフラを意識しないでシステム構築可能です
無償利用枠
Fly.io には無償利用枠があり、これを使うことで無料で運用可能です
- 3つまでの shared-cpu-1x 256MB VM (アプリケーションと PostgreSQL などのマシン合わせて)
- 合計 3 GB までの永続ストレージ
- 160 GB までのアウトバウンド(インターネットへの)データ転送(インバウンドは完全無料)
データベースが不要のアプリケーション(単純な Web サイトなど)であれば3つ運用できます
データベースを使うアプリケーションの場合、アプリケーション1つ、PostgreSQL1つで運用可能です
PostgreSQL
これが AWS と比べて非常に魅力的です
データベース不要のアプリケーションであれば、 AWS でも S3 + API Gateway + Lambda などで実質無料運用可能です
データベースが必要な場合も Amazon DynamoDB を使えばかなり低コストで運用できますが、 NoSQL なので要件の適合性や特有の知識、設計が必要になります
RDB = リレーショナルデータベースを安く使いたいとなると Aurora Serverless が選択肢に入ってきますが、それでもそれなりに費用が発生します
Fly.io であれば、 PostgreSQL が簡単に使える上、前述したように1つだけなら無料です
技術検証や開発期間中ならかなりの低コスト(実質無料)で運用できるわけです
CLI による操作
flyctl を使うことで、かなり簡単に操作できます
詳細は後述します
アカウント作成からデプロイまで
公式ドキュメントに Speedrun! Deploying to Fly.io! があります
これが一番速いと思います
以降の操作は Petal Pro のプロジェクトディレクトリー直下で実行します
flyctl のインストール
macOS であれば Homebrew でインストール可能です
brew install flyctl
Linux の場合
curl -L https://fly.io/install.sh | sh
Windows の場合
powershell -Command "iwr https://fly.io/install.ps1 -useb | iex"
アカウント作成、ログイン
以下のコマンドを実行します
fly auth login
ブラウザで以下のような画面が開くので、 GitHub でサインインするか Need an Account? のリンクからアカウントを作ってください
ログインまでに時間がかかりすぎるとエラーになるので、その場合は再実行してください
アプリケーションの作成
以下のコマンドを実行します
fly launch
すると、しばらくして、このプロジェクトが Phoenix フレームワークであることを察してくれます
...
All dependencies are up to date
Detected a Phoenix app
? Choose an app name (leave blank to generate one):
今回は適当に決めてもらうので、そのまま ENTER を押します
続いて地域を聞かれます
? Choose a region for deployment: [Use arrows to move, type to filter]
Ashburn, Virginia (US) (iad)
Johannesburg, South Africa (jnb)
Los Angeles, California (US) (lax)
London, United Kingdom (lhr)
Chennai (Madras), India (maa)
Madrid, Spain (mad)
Miami, Florida (US) (mia)
> Tokyo, Japan (nrt)
Chicago, Illinois (US) (ord)
Bucharest, Romania (otp)
Querétaro, Mexico (qro)
Santiago, Chile (scl)
Seattle, Washington (US) (sea)
Singapore, Singapore (sin)
San Jose, California (US) (sjc)
Tokyo, Japan (nrt) を選択して ENTER を押します
適当な名前でアプリケーションが作られ、データベースを作るか聞かれます
Created app snowy-pine-3701 in organization personal
Admin URL: https://fly.io/apps/hoge-hoge-1234
Hostname: hoge-hoge-1234.fly.dev
Set secrets on hoge-hoge-1234: SECRET_KEY_BASE
? Would you like to set up a Postgresql database now? (y/N)
使うので y を入れてから ENTER を押します
次はコンテナを動かす VM の性能を選択します
? Select configuration: [Use arrows to move, type to filter]
> Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk
Production - Highly available, 2x shared CPUs, 4GB RAM, 40GB disk
Production - Highly available, 4x shared CPUs, 8GB RAM, 80GB disk
Specify custom configuration
お試しなので Development を選択して ENTER を押します
PostgreSQL のマシンが作成されます
続いて Upstash Redis を作るか聞いてきますが、これは不要なのでそのまま ENTER を押します
? Would you like to set up an Upstash Redis database now? (y/N)
最後にそのままデプロイするか聞いてきます
? Would you like to deploy now? (y/N)
少し準備が必要なので、ここではそのまま ENTER を押します
この時点で Dockerfile が自動的に生成されています
# 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-20230109-slim - for the release image
# - https://pkgs.org/ - resource for finding needed packages
# - Ex: hexpm/elixir:1.14.3-erlang-25.2.2-debian-bullseye-20230109-slim
#
ARG ELIXIR_VERSION=1.14.3
ARG OTP_VERSION=25.2.2
ARG DEBIAN_VERSION=bullseye-20230109-slim
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
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
COPY lib lib
COPY assets assets
# compile assets
RUN mix assets.deploy
# Compile the release
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
# set runner ENV
ENV MIX_ENV="prod"
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/my_app ./
USER nobody
CMD ["/app/bin/server"]
# Appended by flyctl
ENV ECTO_IPV6 true
ENV ERL_AFLAGS "-proto_dist inet6_tcp"
Dockerfile 内で mix release
などが動くようになっています
Dockerfile すら自分で考えなくて良いとは恐れ入りました
コードの修正
開発環境用のままデプロイしたいので、少し修正を加えます
Faker のインストール
今回は Faker の出鱈目文字をそのままにしておくので、本番環境でも Faker をインストールするようにします
mix.exs
- {:faker, "~> 0.17", only: [:test, :dev]},
+ {:faker, "~> 0.17"},
メールボックスのルーティング設定
ダミーのメールボックスを使うため、ルーティング設定を変更します
/Users/oec/dev/petal_pro/lib/my_app_web/routes/dev_routes.ex
- if Mix.env() in [:dev, :test] do
- scope "/" do
- forward "/dev/mailbox", Plug.Swoosh.MailboxPreview
- end
-
+ scope "/" do
+ forward "/dev/mailbox", Plug.Swoosh.MailboxPreview
+ end
+
+ if Mix.env() in [:dev, :test] do
SES の無効化
本番環境では Amazon SES でメール送信するようになっていますが、今回は無効化します
config/runtime.exs
-
- config :my_app, MyApp.Mailer,
- adapter: Swoosh.Adapters.AmazonSES,
- region: System.get_env("AWS_REGION"),
- access_key: System.get_env("AWS_ACCESS_KEY"),
- secret: System.get_env("AWS_SECRET")
開発環境用表示
メールボックスへのリンクを表示するようにします
lib/my_app_web/live/auth/user_confirmation_instructions_live.ex
- <%= if MyApp.config(:env) == :dev do %>
<div class="fixed mt-10 left-10 bottom-10">
<.alert color="warning">
DEV ONLY:
<.link href="/dev/mailbox" class="underline">Go to mailbox</.link>
</.alert>
</div>
- <% end %>
</.auth_layout>
データベースユーザーの権限変更
2023/03/02
マイグレーションが動かない問題は解消されていたので、この操作は不要になりました
おそらくこれはどこかのバグだと思いますが、そのままデプロイするとマイグレーション(データベースの初期化)で権限不足によるエラーが発生します
そこで、データベースユーザーの権限を変更してエラーを回避します
以下のコマンドで PostgreSQL に接続します
fly postgres connect -a hoge-hoge-1234-db
接続されたら \du+
でユーザー一覧を確認します
postgres=# \du+
List of roles
Role name | Attributes | Member of | Description
-----------------+------------------------------------------------------------+--------------------------------------+-------------
flypgadmin | Superuser | {} |
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} |
repmgr | Superuser | {} |
hoge_hoge_1234 | | {pg_read_all_data,pg_write_all_data} |
hoge_hoge_1234(例) がシステムで使うユーザーです
これを Superuser に変更してしまいます(実際の運用ではこの辺りを適切に変更してください)
postgres=# ALTER USER hoge_hoge_1234 WITH SUPERUSER;
ALTER ROLE
PostgreSQL から切断します
postgres=# exit
デプロイ
以下のコマンドでデプロイします
fly deploy
しばらくして、以下のような文言が表示されればデプロイ成功です
1 desired, 1 placed, 1 healthy, 0 unhealthy [health checks: 1 total, 1 passing]
--> v0 deployed successfully
アプリケーションの表示
以下のコマンドを実行すると、ブラウザでアプリケーションを開きます
fly open
ローカル実行で動いていたのと同じ画面が表示され、ユーザー登録やログインができるはずです
アプリケーションのログ監視
以下のコマンドでアプリケーションのログを表示可能です
fly logs
独自ドメインの利用
独自ドメインを使うのも簡単にできます
独自ドメインを使う場合、以下の Petal Pro 公式ドキュメントを参考にドメイン関係の設定を変更してください
まとめ
開発環境用のままデプロイするため色々修正しましたが、それを除けばかなり簡単でした
以前、 AWS に Phoenix アプリケーションをデプロイしようとして色々苦労していましたが、 Fly.io だとほとんど何も考えずにできました
上記の記事は認証に Auth0 を使ったりしたのもありますが、 CloudFront で WebSocket 通信するための設定など、結構考えなければならないことがありました
Petal Pro + Fly.io であれば、このような基盤部分にかける時間もお金もかなり節約できます
SES によるメール送信や Route53 による DNS 、あるいは SageMaker による AI 推論など、まさにマイクロサービスとして必要な機能だけを AWS に任せて、基盤は Fly.io を使う、という構成はかなり有用な気がします
少なくとも、 Phoenix を使うのであれば Fly.io は最適な選択肢の一つと言えます
ただし、 Petal Pro 自体がまだまだ成長中なので、いくつか上げてきたような問題(GitHub認証など)がまだ発生している、という点だけは注意が必要です