はじめに
PaaSはアプリケーションコードを書くだけでほとんどインフラを意識せずに爆速デプロイできるサービスであり、個人開発する際に主にとても重宝しています。PaaSで有名なものにHerokuがありますが、無料プランの廃止や以前のHerokuのセキュリティインシデントなどを受けて、別のPaaSを探している方も多いようです。
つい最近、また個人開発を進める機会があり、私自身も別のPaaSに興味を持ち、今回はその中でも(主観的な調査のもと)特に知名度や評判の良いと判断した、fly.ioを使ってみることにしました。個人開発を進めるにあたって、ただシンプルなWebアプリケーションが公開できるだけでなく、定期的にデータベースにレコードを追加する処理要件がありました。
そこで本記事では、fly.ioを活用し、Webアプリケーションと定期処理プロセス(Cron)を爆速でデプロイする方法について紹介します。Webアプリケーションのデプロイは正直、超簡単でインターネット上に情報も豊富にありましたが、定期処理プロセス(Cron)のデプロイ方法まで含めてまとまっているところがあまり見つけられませんでした。fly.ioの公式ドキュメントにもいくつか記載はあるのですが、通しで書いてあるわけではなく、少しだけ手間取ったためここにまとめます。念のため書いておくと、fly.ioの公式ドキュメントはかなり分かりやすく便利です。
目的
fly.ioで、データベースと接続できるWebアプリケーションと定期処理プロセス(Cron)をとにかく爆速で動かすことを目的として記事を書きます。また、GitHub Actionsで自動的にデプロイする手順についてもおまけとして書きます。
「他にどんなPaaSがあるんですか?」や「fly.ioの具体的な料金プランはどうなんですか?」などの疑問についてはほとんど触れません。別の記事やドキュメントなどを参照してください。
手順完了後の状態
これから説明される手順通りに進めていった結果どうなるの?がすぐわかるようにあらかじめ共有します。
手順
早速、fly.ioでデータベースとWebアプリケーション、定期処理プロセス(Cron)を爆速で動かすための手順を解説していきます。本記事では、サンプルとしてRuby on Railsを利用します。Railsアプリケーションを構築できる環境と、Homebrewが使える状態を前提として進めていきます。
事前準備
fly.ioのアカウントをお持ちでない方は、 https://fly.io/ からアカウントを作成してください。また、クレジットカードの登録もしておく必要があるかもしれません。
次に、flyctl
コマンドを使える状態にする必要があります。以下のコマンドを打ってください。
brew install flyctl # インストール
flyctl auth login # CLI上でのログイン
次に、WebアプリケーションとしてRailsを初期化します。
rails new fly-io-tutorial --api -d postgresql
これで事前準備は完了です。
データベースとWebアプリケーションのデプロイ
初期化したRailsのディレクトリに入って、以下のコマンドを打ちます。これによって、fly.ioへのデプロイに必要な設定ファイルが自動生成されます。いくつか質問されます。
cd fly-io-tutorial
fly launch
# fly.io上での好きなアプリケーション名を指定してください。自動生成されるURLにも利用されます。
# アプリケーション名は後から変更できないようです。 参考: https://community.fly.io/t/how-to-rename-my-apps/3098
? Choose an app name (leave blank to generate one): fly-io-tutorial
? Choose a region for deployment: Tokyo, Japan (nrt)
? Would you like to set up a Postgresql database now? Yes
? Select configuration: Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk
# 必要あれば、後からこの設定は変更できます
# https://community.fly.io/t/how-to-turn-off-postgres-scaling-to-zero-after-1-hour/12522
? Scale single node pg to zero after one hour? No
# 雑に個人開発する時にRedisまで使うことがあまりないので、今回はNoとしましたが、必要なら追加してください
# 本記事ではRedisについては一切触れません
? Would you like to set up an Upstash Redis database now? No
さて、これでデータベースはデプロイが完了しました!また、アプリケーションの設定が作成されています。もちろん、この時点ではまだアプリケーションはデプロイされていません。
また、Railsのディレクトリを改めてみると、いくつかのファイルが自動生成されています。
- Dockerfile
- .dockerignore
- fly.toml
お察しの通り、Dockerfile
を利用して作成されたDockerイメージを利用してデプロイが行われます。fly.toml
はfly.ioへデプロイする際の設定などをまとめたファイルです。後で触れますが、一旦ここではスルーします。
これでWebアプリケーションのデプロイの準備が完了しました!ただ、デプロイできたことが確認しやすいように、routes.rb
を以下のように修正します。 差分
Rails.application.routes.draw do
root to: "rails/welcome#index"
end
完璧です。デプロイを進めていきましょう。
fly deploy
Webアプリケーションのデプロイ確認
無事に完了したら、デプロイコマンドで最後に出てきたURLにアクセスして、Railsアプリケーションがちゃんとデプロイされていることを確認しましょう。私の場合は、URLは https://fly-io-tutorial.fly.dev/ でした。
補足1: 以下のコマンドを用いて、何台のインスタンスが立ち上がっているか確認できます。私の場合は、冗長性を確保するためか、自動的に2台が立ち上がっていました。
fly scale show
補足2: fly.ioのダッシュボードから対象のWebアプリケーションのSecretsを見てみると、DATABASE_URL
やRAILS_MASTER_KEY
などが自動で設定されています。さすが便利ですね。他に秘匿の環境変数を追加したくなった場合は、CLI経由で追加できます。
データベースの接続確認
雑にマイグレーションファイルおよびモデルファイルを作ります。 差分
rails g model Hello
もう一度fly.ioのデプロイをしましょう。
fly deploy
これでマイグレーションが行われているか確認します。以下のようなコマンドを打ち、データベースと接続することができます。
fly postgres connect -a fly-io-tutorial-db # デプロイされたデータベース名を指定
postgres=# \c fly_io_tutorial --データベース名を指定
You are now connected to database "fly_io_tutorial" as user "postgres".
fly_io_tutorial=# \d
List of relations
Schema | Name | Type | Owner
--------+----------------------+----------+-----------------
public | ar_internal_metadata | table | fly_io_tutorial
public | hellos | table | fly_io_tutorial
public | hellos_id_seq | sequence | fly_io_tutorial
public | schema_migrations | table | fly_io_tutorial
(4 rows)
hellos
テーブルがちゃんと作成されていますね!
定期処理プロセス(Cron)の設定
本記事で重要な、Cronの設定もしていきます。ここからの説明は https://fly.io/docs/app-guides/supercronic/ をベースとしています。
はじめに、定期的に実行したいRakeタスクを定義してみます。lib/tasks/create_hellos.rake
を新規作成し、以下のような内容にします。 差分
task "create_hellos": :environment do
Hello.create!
end
次に、定期処理の設定を記載する場所であるcrontab
ファイルを以下の内容で作成します。サンプルとして、5分に1回、hellos
テーブルのレコードを1つ増やすようにしています。 差分
*/5 * * * * bundle exec rake /rails/lib/tasks/create_hellos.rake create_hellos
次に、Dockerfileを修正して、定期的に処理が実行できる状態を作ります。以下の記述を最終ステージに追加します。また、最後のCMD ["./bin/rails", "server"]
の記載を削除してしまいます。のちに、同等の処理をfly.toml
に記載するからです。 差分
# この`apt-get update -qq`以降の記載は元からありますが、ここでcurlもインストールするように修正します
# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y postgresql-client curl && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# # Latest releases available at https://github.com/aptible/supercronic/releases
ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.24/supercronic-linux-amd64 \
SUPERCRONIC=supercronic-linux-amd64 \
SUPERCRONIC_SHA1SUM=6817299e04457e5d6ec4809c72ee13a43e95ba41
RUN curl -fsSLO "$SUPERCRONIC_URL" \
&& echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \
&& chmod +x "$SUPERCRONIC" \
&& mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \
&& ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic
# You might need to change this depending on where your crontab is located
COPY crontab crontab
# 最後の`CMD ["./bin/rails", "server"]`の記載を削除します
ここで、改めて自動生成されたfly.toml
を見ると、以下のような内容になっています。概ね、設定されている情報は雰囲気で読み取れるでしょう。気になる方は公式ドキュメントを見てください。
# fly.toml app configuration file generated for fly-io-tutorial on 2023-05-06T21:01:45+09:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
app = "fly-io-tutorial"
primary_region = "nrt"
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = true
auto_start_machines = true
[[statics]]
guest_path = "/rails/public"
url_prefix = "/"
これに対して、以下のように修正します。 差分
app = "fly-io-tutorial"
primary_region = "nrt"
[processes]
web = "bin/rails server"
cron = "supercronic /rails/crontab"
[http_service]
processes = ["web"]
internal_port = 3000
force_https = true
auto_stop_machines = true
auto_start_machines = true
[[statics]]
guest_path = "/rails/public"
url_prefix = "/"
さて、processesというものを加えました。これによってWebアプリケーションのプロセスとは別に、Cron専用のプロセスを立ち上げることができます。Dockerイメージは共通のものが使われますが、それぞれ指定したコマンドが最後に実行され動くことになります。また、http_serviceにprocesses = ["web"]
を指定しています。processesの記載がない場合には、プロセスが確実に1つのため暗黙的に指定されるのですが、processesの記載を増やした場合には、明示的にどのプロセスをhttp_serviceで利用するのか指定する必要があるためです。
準備完了です!お馴染みのコマンドでデプロイしましょう。
fly deploy
これでCronのプロセスが立ち上がります。以下のコマンドを打って、インスタンスの数を確認します。
fly scale show
すると、私の場合、Cronのプロセスまで冗長性をもって2台が起動してしまっていました。定期的に1台で実行されれば十分な場合がほとんどのはずです。そこで、1台にスケールインさせます。
fly scale count cron=1 --process-group fly-io-tutorial # アプリケーション名を指定
補足: 最初から1台だけ起動するようにできないのかなあ、と思ったものの、公式ドキュメントでこのような方法が紹介されていたので、多分ないのかなあと思います。 https://fly.io/docs/app-guides/supercronic/
少し待ってみて、Cronの実行が行われたら、hellos
テーブルにレコードが追加されているか確認しましょう!
fly postgres connect -a fly-io-tutorial-db # デプロイされたデータベース名を指定
postgres=# \c fly_io_tutorial --データベース名を指定
You are now connected to database "fly_io_tutorial" as user "postgres".
fly_io_tutorial=# select * from hellos;
id | created_at | updated_at
----+----------------------------+----------------------------
1 | 2023-05-06 13:30:01.523303 | 2023-05-06 13:30:01.523303
(1 rows)
見事に追加されていました。これで、本記事の目的は達成しました!
おまけ: GitHub Actionsで自動デプロイ
本セクションは https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ をベースとしています。
以下のコマンドを使って、デプロイに利用できるトークンを発行します。
flyctl tokens create deploy -x 999999h
その後、お手元のGitHubのリポジトリのSecretsでFLY_API_TOKEN
を追加します。値はもちろん、上記で発行されたトークンをそのまま貼り付けます。
そして、.github/workflows/fly.yml
を新規作成し、以下の内容を記載し、コミット&プッシュすれば完了です。
name: Fly Deploy
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
最後に
本記事では、fly.ioを活用して、Webアプリケーションと定期処理プロセス(Cron)を爆速デプロイする方法を紹介しました。かなり爆速で環境構築ができて良かったです。
雑プロダクトの個人開発を前提にして環境構築や調査を進めたため、もしかしたら曖昧な表現や誤っている部分があるかもしれません。その際はぜひご指摘ください。
久々に軽い気持ちで記事を書き始めましたが、ちゃんとまとめようとすると大変ですね😇 どなたかのお助けになれば幸いです。最後までお読みいただきありがとうございました。