Skip to content

Repository files navigation

addchan for Cloud Run

Discordの /addch name:<チャンネル名> コマンドでテキストチャンネルを作成する、Cloud Run向けのHTTP Interactionサーバーです。

動作

  • DiscordのEd25519署名とタイムスタンプを検証します。
  • MANAGE_CHANNELS または ADMINISTRATOR 権限を持つメンバーだけが実行できます。
  • Botトークンを使い、Discord API v10でテキストチャンネルを作成します。
  • DISCORD_CATEGORY_ID の設定時は、指定したカテゴリー配下にチャンネルを作成します。
  • 成功メッセージはチャンネルに公開し、エラーは実行者だけに表示します。
  • GET /health をヘルスチェックとして提供します。

必要なDiscord設定

Discord Developer PortalでApplicationとBotを作成し、次の値を控えます。

  • Application ID
  • General InformationにあるPublic Key
  • Bot Token

Botをサーバーへ追加するときは、次のscopeと権限を付けてください。

  • scope: bot, applications.commands
  • Bot permission: MANAGE_CHANNELS (16)

Message Content IntentやGateway Intentは不要です。

ローカルテスト

Go 1.26以降を使用します。

go test ./...
go vet ./...

ローカルサーバーを起動する場合は .env.sample を参考に環境変数を設定します。通常のブラウザーやcurlから送ったPOSTはDiscord署名がないため、401 Unauthorized になります。

export DISCORD_BOT_TOKEN='...'
export DISCORD_PUBLIC_KEY='...'
export DISCORD_CATEGORY_ID='作成先カテゴリーID'
go run .

Docker Composeを使う場合:

cp .env.sample .env
# .envを編集
docker compose up --build

/addch コマンドの登録

最初はテスト用サーバーのGuild IDを指定すると、コマンドが即時反映されます。

export DISCORD_BOT_TOKEN='...'
export DISCORD_APPLICATION_ID='...'
export DISCORD_GUILD_ID='テスト用Guild ID'
go run ./cmd/register

全サーバー向けのグローバルコマンドとして登録する場合は、DISCORD_GUILD_ID を設定せずに実行します。同名コマンドへのPOSTはDiscord側で更新として扱われます。

Cloud Runへのデプロイ

scripts/deploy.sh はCloud RunとArtifact Registryを東京リージョンに置いたまま、Cloud BuildのソースだけをCloud Storage無料枠対象のus-west1へ保存します。Cloud RunからDiscordの署名付きリクエストを受けるため、サービス自体は未認証アクセスを許可し、アプリケーション内で署名を検証します。

プロジェクトの初期設定後、.envを用意して次を実行します。

./scripts/deploy.sh

このスクリプトは次を実施します。

  • us-west1のソースバケットを作成し、1日経過したビルドソースを削除する
  • ソースバケットのSoft Deleteを無効にする
  • Cloud Buildでコンテナを作成し、既存の東京Artifact Registryへ保存する
  • Secretを新バージョンとして追加し、その番号をCloud Runへ固定してデプロイする
  • ヘルスチェック成功後に旧Secretバージョンを破棄する
  • Artifact Registryで最新1イメージだけを保持するcleanup policyを有効にする

Secretの旧バージョン破棄は取り消せません。また、旧コンテナの削除後は過去のCloud Runリビジョンへロールバックできないため、必要な場合は先に別途バックアップしてください。

以下は初期構築を手動で行う場合の例です。

export PROJECT_ID='Google CloudプロジェクトID'
export REGION='asia-northeast1'
export SERVICE_NAME='addchan'
export RUNTIME_SERVICE_ACCOUNT="addchan-run@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud config set project "$PROJECT_ID"
gcloud services enable \
  run.googleapis.com \
  cloudbuild.googleapis.com \
  artifactregistry.googleapis.com \
  secretmanager.googleapis.com

gcloud iam service-accounts create addchan-run \
  --display-name='addchan Cloud Run runtime'

gcloud secrets create addchan-discord-bot-token \
  --replication-policy=automatic
printf '%s' "$DISCORD_BOT_TOKEN" | \
  gcloud secrets versions add addchan-discord-bot-token --data-file=-

gcloud secrets add-iam-policy-binding addchan-discord-bot-token \
  --member="serviceAccount:${RUNTIME_SERVICE_ACCOUNT}" \
  --role='roles/secretmanager.secretAccessor'

gcloud builds submit . \
  --region="$REGION" \
  --gcs-source-staging-dir="gs://addchan-build-source-${PROJECT_ID}-us-west1/source" \
  --tag="${REGION}-docker.pkg.dev/${PROJECT_ID}/cloud-run-source-deploy/${SERVICE_NAME}:manual"

gcloud run deploy "$SERVICE_NAME" \
  --image="${REGION}-docker.pkg.dev/${PROJECT_ID}/cloud-run-source-deploy/${SERVICE_NAME}:manual" \
  --region="$REGION" \
  --allow-unauthenticated \
  --service-account="$RUNTIME_SERVICE_ACCOUNT" \
  --cpu=1 \
  --memory=512Mi \
  --concurrency=20 \
  --min-instances=0 \
  --max-instances=1 \
  --timeout=5s \
  --set-env-vars="DISCORD_PUBLIC_KEY=${DISCORD_PUBLIC_KEY},DISCORD_CATEGORY_ID=${DISCORD_CATEGORY_ID}" \
  --set-secrets='DISCORD_BOT_TOKEN=addchan-discord-bot-token:latest'

デプロイ後、URLを確認します。

SERVICE_URL="$(gcloud run services describe "$SERVICE_NAME" \
  --region="$REGION" \
  --format='value(status.url)')"
curl "${SERVICE_URL}/health"

Discord Developer PortalのGeneral InformationにあるInteractions Endpoint URLへ、次を設定します。

https://Cloud-RunのURL/interactions

Discordが署名付きPINGを送り、サーバーがPONGを返すとURLが保存されます。その後、上記の登録ツールで /addch を登録してください。

環境変数

名前 必須 説明
DISCORD_BOT_TOKEN はい Discord Bot Token。Cloud RunではSecret Managerから注入します。
DISCORD_PUBLIC_KEY はい Discord ApplicationのEd25519 Public Key(16進文字列)。
DISCORD_CATEGORY_ID いいえ チャンネル作成先のDiscordカテゴリーID。未設定ならGuild直下に作成します。
PORT いいえ HTTPポート。既定値は8080で、Cloud Runが自動設定します。
DISCORD_API_BASE_URL いいえ テスト用Discord API URL。通常は設定しません。

登録ツールでは追加で DISCORD_APPLICATION_ID が必要です。DISCORD_GUILD_ID を指定するとGuild command、省略するとGlobal commandになります。

運用上の注意

  • DiscordはInteractionへの初回応答を3秒以内に要求します。Discord API呼び出しには2秒のタイムアウトを設定しています。
  • min-instances=0 ではコールドスタートが発生します。通常は小さなGoバイナリで収まりますが、3秒以内の応答を保証したい場合はCloud Runの最小インスタンスを検討してください。
  • Cloud Runのサービスは公開URLになるため、Bot Tokenを通常の環境変数へ直接保存しないでください。
  • max-instances=1 は小規模利用向けのコスト保護設定です。利用が増えた場合は引き上げてください。

License

MIT License

About

Bot-provided command to add a new text channel

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

Used by

Contributors

Languages