皆さん、こんにちは。 デザイアグランプリの虜、おっくんです。
今回は、「Deno で掲示板サイトを作ろう! with upstash & supabase」企画の 4 回目として、upstash redis の導入と自動デプロイに取り組みます。
前回記事はこちら
upstash redis の導入
クラウドにこれまで作成した掲示板アプリをデプロイするにあたり、これまで開発環境ではコンテナで用意していた Redis の代替になるものが必要です。 ここで、今回は upstash redis を導入します。
upstash redis とは?
upstash redis は、Upstash, Inc が運用している Redis サービスです。 公式サイトで紹介されている特徴としては、データの永続化が有効になっていることや、低レイテンシが挙げられています。
Redis を「サーバーレスで」、「お安く」「上限有り(MAX 160$)の従量課金且つ」で使えるのが魅力です。
意図せず不適切な設定で費用が嵩むことは、従量課金型のクラウドサービスを利用する上での懸念することの一つかと思います。
この点においては、かなり安心して使えるのではないでしょうか?
以降のupstashの画面表示では課金の表示が出ていますが、無料利用枠もあるサービスです。
また、各機能それぞれ Deno 向けのモジュールも公式が公開しているので導入しやすいのが利点です。
upstash では、Redis 以外に Kafka や、サーバーレスおよびエッジランタイム向けのメッセージング/スケジューリングソリューションの QStash も展開されています。 そのうち QStash は取り上げる予定です。
実装方針
upstash Redis を使いたいのは、クラウドにデプロイされたアプリケーションだけです。 ローカルの開発環境では、引き続きコンテナで用意した Redis をそのまま使いたいです。
この要求を満たすための準備として、既に前回までの実装で Redis のクライアントを関数で1枚ラップしています。 環境変数に基づいて、ラップした関数から返却するRedisクライアントを切り替えます。
データベース作成
upstash Redis を使うには、最初にデータベースの作成が必要になります。 次の手順で用意します。
- 任意の方法で、upstash にサインインしてください。
メールアドレスでの登録以外に Amazon、GitHub、Google アカウントでの登録ができるようになっています。 - 「Create DataBase」を押下
- 任意の設定でデータベースを作成します。
- UPSTASH_REDIS_REST_URLと、UPSTASH_REDIS_REST_TOKEN を控える
クリックすると、クリップボードにコピーされます
以上で用意ができていますので実装に入ります。
実装
以前までに Redis クライアントを返す関数は、次の通り実装されています。
[util/redis.ts]
import { connect } from "redis/mod.ts"; export const redisConnect = (() => { return connect({ hostname: "redis", port: 6379, }); })();
こちらを改修します。 書き換えたものは、次の通りとなります。
[util/redis.ts(変更)]
import { envConfig } from "./config.ts"; import { connect } from "redis/mod.ts"; import { Redis } from "upstash_redis/mod.ts"; export const redisConnect = (() => { if (envConfig.DENO_ENV === "development") { return connect({ hostname: "redis", port: 6379, }); } return new Redis({ url: envConfig.UPSTASH_REDIS_REST_URL, token: envConfig.UPSTASH_REDIS_REST_TOKEN, automaticDeserialization: false, //デフォルト設定では自動でJSONのパースをしてしまうので機能をOFFに }); })();
見ての通りですが、環境変数 DENO_ENV を参照し、
"development" ではない場合に、UPSTASH_REDIS_REST_URL と UPSTASH_REDIS_REST_TOKEN を使って upstash_redis モジュールのクライアントを作成し、返却します。
これができるのは、upstash_redis のクライアントのメソッドが標準のRedisと互換性があるメソッドになっているからです。
参照する環境変数が増えていますので、util/config.ts を修正して参照する環境変数を追加します。
[util/config.ts(変更)]
import "https://deno.land/std@0.150.0/dotenv/load.ts"; const envConfig = { SUPABASE_EDGE_FUNCTION_END_POINT: Deno.env.get( "SUPABASE_EDGE_FUNCTION_END_POINT", )!, SUPABASE_ANON_KEY: Deno.env.get("SUPABASE_ANON_KEY")!, SESSION_SECONDS: Deno.env.get("SESSION_SECONDS")!, SECRET: Deno.env.get("SECRET")!, SALT: Deno.env.get("SALT")!, // 以下3件を追記 DENO_ENV: Deno.env.get("DENO_ENV")!, UPSTASH_REDIS_REST_URL: Deno.env.get("UPSTASH_REDIS_REST_URL")!, UPSTASH_REDIS_REST_TOKEN: Deno.env.get("UPSTASH_REDIS_REST_TOKEN")! }; export { envConfig };
また、upstash_redis モジュールを導入しているので、import_map.json も修正が必要です。
[import_map.json(変更)]
{ "imports": { /* 省略*/ "upstash_redis/": "https://deno.land/x/upstash_redis/" // <= 追記します。 } }
併せてそれぞれ環境変数の設定を行ってください。
試しに、環境変数 DENO_ENV を develop 以外に設定してみましょう。
qstash redis 向きに通信が飛び、保存されているはずです。
upstash のコンソールから Data Browser を開くと保存内容が確認できます。
自動デプロイ導入
upstash redis の用意ができたので、クラウド環境へのデプロイの足がかりが掴めました。 引き続き、自動デプロイの用意を進めます。
デプロイ先は、supabase と、Deno Deploy の2つになります。 それぞれの用意から始めます。
supabase の設定
任意の方法で、supabase にサインインしてください。
メールアドレスでの登録以外に GitHub アカウントなどでの登録ができるようになっています。
- オーガナイゼーションを作成(もともとあれば、それを使っても大きな問題にはならないと思います。)
- プロジェクトを任意の名称で作成してください。
- Settings -> API の項目に後々使用するキーが記載されていますので、控えておくか都度都度この画面で確認します。
Deno Deploy の設定 1
Deno Deploy は、GitHub アカウントでの登録のみが可能です。 任意のアカウントを使用し、サインインしてください。
- New Project を選択します。
- リポジトリ、ブランチを順に選択し、 「Github Action」を選択します。
Automatic を選択することも可能ではありますが、前提となるデータベースのマイグレーションなども自動化する場合こちらがオススメです。
- name 部分が長い場合は適宜編集してから、Link を押します。(画像では、「anonymous-board」としています。)
- 遷移先に、GitHub Actions 用の yaml が掲載されているのでこちらを参考にしていきます。
GitHub Actions を設定
GitHub Actions を使用するには、先に共有したようにyaml ファイルの用意が必要です。
今回使用した yaml ファイルは次の様にしました。 作り方は様々有るかと思いますが、特に今回意識しているのは「ローカルで使用する方法の踏襲」です。 supabase cli を使用したマイグレーションも可能ではありますが、ローカルで使っていないので、ここでも使用せず進めます。
[.github/workflows/deploy.yml(新規)]
name: anonymous-board deploy on: [push] jobs: deploy: name: anonymous-board deploy runs-on: ubuntu-latest timeout-minutes: 600 permissions: id-token: write # Needed for auth with Deno Deploy contents: read # Needed to clone the repository steps: - uses: actions/checkout@v3 # 以下 supabase データベース のマイグレーション # Denoコンテナ準備 - name: Do `container preparation` run: | docker-compose build docker-compose up -d - name: Do suppabase db migrate env: SUPABASE_POSTGRES_HOST: ${{secrets.SUPABASE_POSTGRES_HOST}} SUPABASE_POSTGRES_DB: ${{secrets.SUPABASE_POSTGRES_DB}} SUPABASE_POSTGRES_USER: ${{secrets.SUPABASE_POSTGRES_USER}} SUPABASE_POSTGRES_PASSWORD: ${{secrets.SUPABASE_POSTGRES_PASSWORD}} SUPABASE_POSTGRES_PORT: ${{secrets.SUPABASE_POSTGRES_PORT}} run: | echo SUPABASE_POSTGRES_HOST=$SUPABASE_POSTGRES_HOST >> ./anonymous-board/.env echo SUPABASE_POSTGRES_USER=$SUPABASE_POSTGRES_USER >> ./anonymous-board/.env echo SUPABASE_POSTGRES_PASSWORD=$SUPABASE_POSTGRES_PASSWORD >> ./anonymous-board/.env echo SUPABASE_POSTGRES_DB=$SUPABASE_POSTGRES_DB >> ./anonymous-board/.env echo SUPABASE_POSTGRES_PORT=$SUPABASE_POSTGRES_PORT >> ./anonymous-board/.env docker-compose exec -T app bash -c 'cd anonymous-board && deno task db:migrate' # 以下 supabase Edge functions へのデプロイ - uses: supabase/setup-cli@v1 with: version: latest - name: supabase edge functions deploy env: SUPABASE_ACCESS_TOKEN: ${{secrets.SUPABASE_ACCESS_TOKEN}} SUPABASE_PROJECT_ID: ${{secrets.SUPABASE_PROJECT_ID}} run: | supabase link --project-ref $SUPABASE_PROJECT_ID supabase functions deploy board_api --project-ref $SUPABASE_PROJECT_ID # 以下 Deno Deploy へのデプロイ - name: Upload to Deno Deploy uses: denoland/deployctl@v1 with: project: "anonymous-board" entrypoint: "./anonymous-board/main.ts"
大きくステップは3つに分かれています。
- supabase のデータベースへのマイグレーション
- supabase Edge functions へのデプロイ
Deno Deploy へのデプロイ
はローカルでデータベースにマイグレーションをするのと同じ方法を踏襲するために、コンテナの起動とコンテナに入らずにマイグレーションコマンドを実行しています。
- には、提供されているアクションが有るので、そちらを使わせていただきます。
見ての通り、いずれの方法もシークレットを参照しています。 必要なシークレットは GitHub のリポジトリにて、設定ください。
必要なシークレットは以下の7件種類です。
SUPABASE_POSTGRES_HOST SUPABASE_POSTGRES_DB SUPABASE_POSTGRES_USER SUPABASE_POSTGRES_PASSWORD SUPABASE_POSTGRES_PORT SUPABASE_ACCESS_TOKEN SUPABASE_PROJECT_ID
設定できたら、GitHub にプッシュしてください。 GitHub Actions が開始されるはずです。
※注意
- supabase で指定されている Postgres のバージョンが古い
セットアップ時、次のエラーが GitHub actions の実行ログに現れエラーになることが考えられます。
Remote database Postgres version 15 is incompatible with db.major_version 14. If you are setting up a fresh Supabase CLI project, try changing db.major_version in supabase/config.toml to 15.
この場合、supabase cli のバージョンを上げて、supabase/config.toml の major_version = 14
の記載を major_version = 15
に書き換えてください。
Deno Deploy の設定 2
先に実施したデプロイにより、Deno Deploy にアプリケーションが展開されています。
おそらく、プロジェクトの詳細右上の 「View」ボタンが有効になっています。
押すと、展開されたアプリケーションのパスに遷移しますが、次のようなエラーページが表示されるはずです。
これは環境変数の設定がされていないからです。
Deno Deploy も環境変数の設定を行いましょう。
プロジェクトの詳細ページ中ほどに「Environment Variables」があるので、ここで登録します。
設定する環境変数は、次の8件です。
SUPABASE_EDGE_FUNCTION_END_POINT SUPABASE_ANON_KEY SESSION_SECONDS SECRET SALT DENO_ENV UPSTASH_REDIS_REST_URL UPSTASH_REDIS_REST_TOKEN
「SUPABASE_EDGE_FUNCTION_END_POINT」 は、supabase Edge Functions にデプロイしたAPIの詳細を開くと、「Endpoint URL」に記載されています。
「SUPABASE_ANON_KEY」は、supabase の Project Setttings 画面の API の項目を開くと、「Project API keys」に記載があります。
環境変数を書き換えると、Deno Deploy にはすぐに反映されます。
先ほどはエラーになっていたページにアクセスすると、開発時に表示されていたページと同じものが表示されるはずです。
適当に入力して、supabase の Table Editor を 見ると、入力内容が登録されているのが確認できるはずです。
簡易ではありますが、動作確認まで出来ました。
今回は、GitHub Actions を使用して Deno Deploy と supabase/supabase Edge Functions のデプロイを行い、アプリケーションの動作確認まで進めました。 本記事ではストレートに進めていますが、特にGitHub Actions の設定については試行錯誤をしています。 動作してくれると、なかなかうれしいものです。
次回は、Twitter 連携か、upstash Qstash を使用したスケジュール実行について触れていく予定です。
今回進めた内容は、以下のリポジトリに上げていますので全体感を確認したい場合はこちらをご参考ください。
https://github.com/Octo8080X/anonymous-board/tree/4th_2023_01
P.S.
採用
虎の穴では一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧下さい。
yumenosora.co.jp