本文へ移動

自分のリポジトリから自動でデプロイする ​

このリポジトリでは、GitHub Actionsが、Cloudflare版のWorkerとVercel版のプロジェクトを自動でデプロイできます。このページは、このリポジトリをフォークして、自分で運用する人向けです。Deployボタンで置いた人は、CloudflareかVercelが自動でデプロイし直すので、この設定は要りません。

しくみ ​

  1. mainにpushされると、Releaseのワークフローが、CIのジョブ(各アプリのlint、型検査、テストと、文書のビルド)を流します。
  2. それが通ると、リリースを作ります。リリースが出るのは、前のリリースからfeatかfixのコミットが入ったときです。
  3. リリースが出たら、Deployのワークフローが、そのタグの中身を、デプロイ先のGitHub Environmentごとにデプロイします。Cloudflare版はwrangler deployで、Vercel版はVercelのCLIでビルドして送ります。
  4. 同じEnvironmentへのデプロイは、1つずつ順に行います。

リリースが出ないpush(文書、CI、依存の更新だけのもの)では、デプロイしません。いくつかまとめて入れても、デプロイは次のリリースのときの1回で済みます。

リリースを作るには、リポジトリのSecretRELEASE_TOKENが要ります。RELEASE_TOKENが無いリポジトリ(ふつうのフォーク)では、リリースを作らずに、pushのたびにmainに入った中身をデプロイします。

デプロイ先を書かなければ、Deployは何もしません。フォークしただけのリポジトリで、勝手にデプロイが走ることはありません。

Cloudflare版を設定する ​

1. GitHub Environmentを作る ​

リポジトリの「Settings → Environments」で、デプロイ先ごとにEnvironmentを作ります。名前は自由です(例:身内用のcloudflare-productionと公開用のcloudflare-public)。

それぞれのEnvironmentで、「Deployment branches and tags」をSelected branchesにし、mainだけを許可します。こうすると、main以外のブランチのワークフローからは、このEnvironmentのSecretを読めません。

2. Secretを入れる ​

Environmentごとに、次のSecretを入れます。

名前中身
WORKER_NAMEWorkerの名前。Environmentごとに変える。R2のバケットは「<この名前>-assets」になる
ACCESS_CONTROL_ALLOW_ORIGINそのWorkerで受けるAxeのOrigin。カンマ区切りで複数書ける
CLOUDFLARE_API_TOKENデプロイに使うCloudflareのAPIトークン(下の「APIトークン」を参照)
CLOUDFLARE_ACCOUNT_IDCloudflareのアカウントID。全部のEnvironmentで同じなら、リポジトリのSecretに置いてもよい
DISCORD_CLIENT_IDログインに使うDiscordのアプリのClient ID(ログインと部屋を使うとき)
DISCORD_CLIENT_SECRET同じアプリのClient Secret
SESSION_SECRETトークンに署名する鍵。32文字以上の乱数。Environmentごとに別のものにする
SKYWAY_APP_IDSkyWayのアプリケーションID(SkyWay版のトークンを発行するとき)
SKYWAY_SECRET同じアプリのシークレットキー
ADMIN_DISCORD_IDS管理画面に入れる運営する人のDiscordのユーザーID。カンマ区切り(管理画面を使うとき)
ADMIN_WEBHOOK_URL運営する人への知らせを送るDiscordのWebhookのURL(知らせを受けるとき)
ADMIN_CONTACT_URL断った人に見せる問い合わせ先。https://のページかmailto:(出すとき)
ROOM_STORAGE_LIMIT_MB1つの部屋に置ける画像と音声の合計(MB)(上限を置くとき)
ADMIN_STORAGE_ALERT_GB置き場所の合計がこの量(GB)を超えたら知らせる(数えるとき)

ログインの3つは、そろえて入れるか、どれも入れないかのどちらかにします。一部だけだと、デプロイのジョブが止まります。SkyWayの2つも同じです。ログインの3つだけを入れたEnvironmentは部屋のサーバーに、SkyWayの2つだけを入れたEnvironmentはSkyWay版のトークン発行サーバー(→ Cloudflareに置く(SkyWay版))になり、両方を入れると両方を受け持ちます。Discordのアプリの作りかたはDiscordのアプリを作るにあります。

運営する人の設定(ADMIN_で始まる4つとROOM_STORAGE_LIMIT_MB)は、どれも入れなくてもかまいません(→ 管理画面とBAN、設定項目)。入れたものは、デプロイの前に形を確かめ、合わなければジョブを止めます。形の合わない設定があると、Workerはすべてのリクエストに500 config-invalidを返すためです。デプロイは、Workerにあるシークレットへ足すだけです。Environmentから消しても、Workerには残ります。外すときは、Cloudflareのダッシュボードかwrangler secret deleteで消します。ADMIN_PASSKEY_RESETは、パスキーをすべて失くしたときだけ入れて外すものなので、ここには入れず、ダッシュボードで扱います(→ 端末を失くしたとき)。

ACCESS_CONTROL_ALLOW_ORIGIN、ログインの3つ、SkyWayの2つ、入れた運営する人の設定は、デプロイのたびにWorkerのシークレットとして入れ直します。wrangler.jsoncに書いた手元用の値(http://localhost:4200)は、このシークレットで置き換わります。

ghコマンドを使うと、次のように入れられます。

sh
R=<owner>/<repo>
E=cloudflare-production
gh secret set WORKER_NAME --env $E --repo $R --body udonarium-axe-production
gh secret set ACCESS_CONTROL_ALLOW_ORIGIN --env $E --repo $R --body https://axe.example.com
gh secret set CLOUDFLARE_API_TOKEN --env $E --repo $R      # 実行すると値を尋ねられる
gh secret set CLOUDFLARE_ACCOUNT_ID --repo $R --body <アカウントID>
gh secret set DISCORD_CLIENT_ID --env $E --repo $R --body <Client ID>
gh secret set DISCORD_CLIENT_SECRET --env $E --repo $R  # 値を尋ねられる
openssl rand -base64 48 | gh secret set SESSION_SECRET --env $E --repo $R

3. デプロイ先を書く ​

リポジトリの「Settings → Secrets and variables → Actions → Variables」で、Variable CLOUDFLARE_DEPLOY_ENVIRONMENTSに、Environmentの名前をJSONの配列で書きます。

json
["cloudflare-production", "cloudflare-public"]
sh
gh variable set CLOUDFLARE_DEPLOY_ENVIRONMENTS --repo $R --body '["cloudflare-production","cloudflare-public"]'

次にリリースが出たときから、デプロイが走ります(リリースを作らないフォークでは、次にmainへpushしたときから)。すぐに出すときは、値を変えたときと同じく、Deployのワークフローを手で起動します。

APIトークン ​

APIトークンは、Cloudflareのダッシュボードの「My Profile → API Tokens」(またはアカウントの「API Tokens」)で作ります。権限は、必要な最小限に絞ってください。

時期権限範囲
Workerを初めてデプロイするWorkers AdminすべてのWorker(新しく作るため)
Workers R2 Storage Write・Readアカウント(バケットを作るため)
2回目からWorkers EditorデプロイするWorkerだけ
  • 「Account Resources」は、そのアカウントだけを選びます。
  • ゾーンの権限は要りません。カスタムドメインはダッシュボードで付けるので、デプロイではゾーンに触りません。
  • すべてのEnvironmentで初回のデプロイが済んだら、トークンを「Workers Editor(デプロイするWorkerだけ)」に絞ってください。2回目からは、デプロイ済みのWorkerからバケットの割り当てを引き継ぐので、R2の権限は要りません。
  • 「選んだWorkerだけ」の範囲は、そのWorkerができてからでないと選べません。そのため、初回だけは広い権限が要ります。
  • 部屋のサーバーのDurable Objectsは、Workerと一緒にデプロイされます。別の権限は要りません。すでに置いてあるWorkerに、部屋のサーバーの入った版を初めて出すときAuthentication errorになったら、その1回だけ初回と同じ権限でデプロイし直してください。

Vercel版を設定する ​

Vercel版は、VercelのGitの連携を使わずに、ActionsからVercelのCLIで送ります。Gitの連携があると、mainへのpushのたびに本番が変わり、リリースした版とずれるためです。

1. プロジェクトを作る ​

手元で、このリポジトリのapps/vercelから、Vercelのプロジェクトを作ります。

sh
cd apps/vercel
npm ci
npx vercel login
npx vercel link
  • vercel linkで、新しいプロジェクトを作るほうを選び、名前を入れます。コードの場所を尋ねられたら./のままにします。プロジェクトのRoot Directoryは空のままにします。ActionsはCLIをapps/vercelで動かすためです。
  • できると、apps/vercel/.vercel/project.jsonにorgIdとprojectIdが書かれます。手順3で使うので控えます。このファイルはGitに入りません。
  • プロジェクトのSettingsのGitで、Gitのリポジトリがつながっていないかを確かめます。つながっていたら外します。

2. プロジェクトの設定を入れる ​

部屋のサーバーの値は、GitHubではなく、Vercelのプロジェクトに置きます。入れかたはVercelに置く(サーバー版)と同じです。

  • 環境変数のACCESS_CONTROL_ALLOW_ORIGIN、DISCORD_CLIENT_ID、DISCORD_CLIENT_SECRET、SESSION_SECRET(→ 手順3)。プロジェクトのSettingsのEnvironment Variablesで入れます。
  • Redis(→ 手順5)と、Blobのストア(→ 手順6)
  • 掃除の鍵のCRON_SECRET(任意。→ 掃除の鍵を入れる)

ビルドのときに、Actionsがこの値をプロジェクトから読みます。

3. GitHub EnvironmentとSecretを入れる ​

Cloudflare版の手順1と同じく、Environmentを作り(例:vercel-production)、mainだけを許可します。そこに次のSecretを入れます。

名前中身
VERCEL_TOKENデプロイに使うVercelのトークン。アカウントのトークンの画面(https://vercel.com/account/tokens)で作る
VERCEL_ORG_ID手順1のproject.jsonのorgId
VERCEL_PROJECT_ID手順1のproject.jsonのprojectId
sh
R=<owner>/<repo>
E=vercel-production
gh secret set VERCEL_TOKEN --env $E --repo $R      # 値を尋ねられる
gh secret set VERCEL_ORG_ID --env $E --repo $R --body <orgId>
gh secret set VERCEL_PROJECT_ID --env $E --repo $R --body <projectId>

4. デプロイ先を書く ​

Variable VERCEL_DEPLOY_ENVIRONMENTSに、Environmentの名前をJSONの配列で書きます。

sh
gh variable set VERCEL_DEPLOY_ENVIRONMENTS --repo $R --body '["vercel-production"]'

初めてのデプロイは、値を変えたときと同じく、Deployのワークフローを手で起動します。終わったら、プロジェクトの本番のURLを控えて、Discordに戻り先を登録します(→ 手順8)。

値を変えたとき ​

GitHubのSecretやVariable、Vercelのプロジェクトの環境変数を変えても、すぐには反映されません。手でデプロイし直します。

  1. GitHubの「Actions」で、左の一覧からDeployを開き、Run workflowを押します。
  2. ブランチはmainのままにします。Environmentはmainからしか使えないためです。
  3. refに、いま出ている版のタグ(リリースの一覧のいちばん新しいもの。例:v1.1.0)を入れます。リリースを作らないフォークではmainを入れます。
  4. appで、デプロイし直すアプリを選びます。片方の値だけを変えたときは、そのアプリ(cloudflareかvercel)にします。Cloudflare版をデプロイし直すと、部屋のサーバーが入れ替わり、遊んでいる人の接続がいったん切れるためです(Axeはつなぎ直します)。
  5. Run workflowを押すと、新しい値でデプロイし直します。

うまくいかないとき ​

ジョブのログ原因と直しかた
WORKER_NAME is not configured for the … environmentそのEnvironmentにWORKER_NAMEが無い
ACCESS_CONTROL_ALLOW_ORIGIN is not configured for the …そのEnvironmentにACCESS_CONTROL_ALLOW_ORIGINが無い
Please enable R2 through the Cloudflare DashboardアカウントでR2を使い始めていない(→ Cloudflareに置く)
You need to enable Analytics Engine(10089)アカウントでAnalytics Engineを使い始めていない(→ Cloudflareに置く)
同じ名前のR2のバケットがあって作れない初めてのデプロイが途中で止まり、バケットだけが残っている。空なのを確かめて消してから、やり直す(→ Cloudflareに置く)
Authentication error(10000など)APIトークンの権限が足りない。初回は上の表の広い権限が要る
VERCEL_TOKEN is not configured for the … environmentそのEnvironmentにVERCEL_TOKENが無い。VERCEL_ORG_IDとVERCEL_PROJECT_IDも同じ
Vercel版のデプロイで、部屋のサーバーがconfig-invalidを返すプロジェクトの環境変数か、RedisかBlobのストアが足りない(→ Vercel版の手順2)。足したら、手でデプロイし直す
Deployのジョブが「skipped」になるリリースが出なかった(featかfixのコミットが無かった)、その前のCIのジョブが落ちた、またはCLOUDFLARE_DEPLOY_ENVIRONMENTSかVERCEL_DEPLOY_ENVIRONMENTSが空

MITライセンスで公開しています