インフラとデプロイ
このセクションは、本番環境がどう組み立てられているか、変更がどう本番に届くかを把握するためのものです。ローカル開発の起動方法は はじめに / dev-loop を、環境ごとの違いは次ページの 環境の種類 を参照してください。
本番の Terraform state・Cloud SQL・顧客データには触れません。インフラ変更は PR → CI 経由が唯一の適用経路です(下記「Terraform — IaC」参照)。
本番トポロジーの全体像
Astar Management のプロダクション環境は GCP + Cloudflare のハイブリッド構成です。「バックエンドは Cloud Run」という直感は誤りで、コスト最適化のため 2026-03-17 に GCE VM へ移行済みです(infrastructure/terraform/cloud-run-backend.tf は removed ブロックのみが残る記録用ファイル)。
| コンポーネント | 実体 | 経路 |
|---|---|---|
フロントエンド (app.astarworks.com) | Cloudflare Pages(astar-frontend プロジェクト、Nuxt を静的+Worker としてビルド) | Cloudflare が直接配信 |
バックエンド API (api.astarworks.com) | GCE VM(Ubuntu 24.04、Docker Compose: backend + cloud-sql-proxy + cloudflared + autoheal) | Cloudflare Tunnel 経由(外部 IP なし、ボディ上限 100MB) |
Office 編集 (collabora.astarworks.com) | 専用 GCE VM(Collabora Online / WOPI client) | Cloudflare Tunnel 経由(backend VM とは別 VM。backend VM の OOM 履歴を踏まえ分離) |
| DB | Cloud SQL for PostgreSQL | GCE VM から Cloud SQL Auth Proxy 経由 |
| 補助サービス(下記) | Cloud Run(3 サービス、すべて private) | backend VM のサービスアカウントのみ invoke 可能 |
| バイナリ配布・ドキュメントストレージ | Cloudflare R2(astar-downloads / astar-documents) | — |
| サンドボックス実行系 | Cloudflare Workers(downloads-redirect / usercontent / coderun) | — |
Cloud Run 上の補助サービス
バックエンド本体は GCE VM ですが、重い/バースト的な処理は Cloud Run の個別サービスに切り出されています(いずれも backend_vm サービスアカウントのみが invoke できる private サービス)。
astar-doc-export— Playwright(headless Chromium) による HTML → PDF/PNG レンダリング。UI 側のブラウザ export が主経路で、サーバーサイドレンダリングが必要な場合のフォールバック。min_instance_count = 0(scale-to-zero)。astar-doc-converter— LibreOffice による旧 Office 形式 (.doc/.xls) の変換・プレビュー生成。レイテンシに敏感なユーザー向けパスのためmin_instance_count = 1(常時ウォーム)。astar-kreuzberg— ドキュメント OCR / Markdown 抽出サイドカー。2026-07-06 の障害(backend VM の 8GB がメモリ超過しcloudflared/sshdが OOM kill → トンネル断)を受けて VM から分離。
理由と構成の詳細はそれぞれの infrastructure/terraform/cloud-run-*.tf の冒頭コメントに書かれています。
Terraform — IaC
infrastructure/terraform/ が GCP + Cloudflare のインフラを 形状(メモリ・CPU・スケーリング・ネットワーク・IAM・シークレットの入れ物)としてコード管理します。
terraform apply を CLI から手動実行しない。 適用は .github/workflows/iac.yml が CI 駆動で行います(infrastructure/terraform/** か infrastructure/workers/** に変更が入った PR で terraform plan → PR コメント、main へのマージで terraform apply -auto-approve)。ローカルでは terraform plan で差分確認までに留めます。
- Terraform が管理するもの: インフラの形状、シークレットのシェル(名前・レプリケーション・アクセス権のみ)、GCP API 有効化、Workload Identity Federation
- Terraform が管理しない/できないもの: Cloud Run のイメージとシークレットの値(
release.ymlが担当)、Auth0 / SendGrid / Sentry など外部 SaaS - 同じ
iac.ymlがmainマージ時に Cloudflare Workers 3 本(downloads-redirect/usercontent/coderun)もwrangler deployする
infrastructure/terraform/README.md はディレクトリ構成の索引として書かれていますが、個別ファイルの現状(例: どのサービスが Cloud Run か GCE か)は README.md の記述より実際の .tf ファイルの方が新しい場合があります。疑わしいときは .tf の冒頭コメントを直接読んでください。
リリースパイプライン
リリースは git tag (vX.Y.Z) の push で始まります。手動で gcloud や docker push を叩く経路はありません。
/releaseskill がローカルの最新vX.Y.Zタグから次バージョンを計算し、隔離 worktree で frontend build+typecheck・Tauri desktop build・Go agent cross-compile・backend Flyway migration をすべて検証- 全ゲート PASS で
vX.Y.Zタグを作成 → 明示確認の上で push - push が
.github/workflows/release.ymlを起動:validate-and-sync-secrets— 1Password から必要なシークレットを解決し GCP Secret Manager へ同期(下記参照)。ここが fail-fast ゲート- 各種ビルド(Tauri desktop / Go agent binary / CLI binary / agent Docker image / doc-export / doc-converter / backend / frontend)
build-and-deploy-frontend— Nuxt を Cloudflare Pages 向けにビルドしwrangler pages deploydeploy— Cloud SQL Auth Proxy 経由で Flyway migration を CI 上で実行 → GCE VM に SSH でデプロイスクリプトを転送・実行create-release— GitHub Release 作成
リリースの基点は 直前の vX.Y.Z タグの系列であり、origin/main ブランチの最新コミットではありません。ローカル main が origin より進んでいても push 前の判断は別問題として扱われます。
シークレットの SSoT
Astar の全バックエンドシークレットは infrastructure/secrets/secrets.json の 1 ファイルで宣言されています(値そのものは含まれません — 1Password への op://… ポインタのみ)。
1Password (Astar Prod) → resolve (release.yml の validate-and-sync-secrets job)
→ job-scoped $GITHUB_ENV
→ GCP Secret Manager(シェルは Terraform が事前作成)
→ deploy.sh が fetch → backend 環境変数
以前は Terraform / release.yml / deploy.sh の 3 ファイルを手で同期する必要があり、1 つでも漏れると NOT_FOUND でリリースが途中で壊れていました。今は secrets.json を編集するだけで済み、infrastructure/scripts/check-secret-wiring.sh が配線漏れを事前検知します。詳細は infrastructure/secrets/README.md。
シークレットの値を画面出力させたり、secrets.json に直接書き込んだりしない。値の実体は常に 1Password 側のみ。