0% 0% 0% 0%

Deploy to Cloud Run

Index
  1. 01. Concepts
  2. 02. Architecture
  3. 03. State & Storage
  4. 04. Tools
  5. 05. BigQuery
  6. 06. Cloud Storage
  7. 07. Compute & Containers
  8. 08. Cloud Run
  9. 09. Pub/Sub
  10. 10. Databases
  11. 11. Observability
  12. 12. Access & Billing
  13. 13. Secret Manager
  14. 14. Networking
  15. 15. Scheduling & Tasks
  16. 16. Build & Artifacts
  17. 17. Guardrails
  18. 18. Setup
  19. 19. Deploy to Cloud Run

Deploy to Cloud Run

For anything past a laptop, enoki runs as a Cloud Run service in your own GCP project. Inference uses that project’s Vertex AI as the service account; every data call still runs as the connecting Slack user’s own Google identity. Shared state lives in Firestore so the service can scale to several instances. Nothing is stored outside your project.

Slack ──HTTPS──▶ Cloud Run (gunicorn ▸ app_oauth:flask_app, N instances)
                    ├─ inference     ▶ Vertex AI     (runtime service account)
                    ├─ GCP tools     ▶ Google APIs   (each user's OAuth identity)
                    ├─ shared state  ▶ Firestore     (conversations, pending, idem, audit)
                    └─ per-user files▶ /app/data      (gcsfuse ▸ gs://…-enoki-data)

What you need first

  • A GCP project with billing enabled and gcloud authenticated.
  • A Slack app (from manifest.json) — Client ID, Client Secret, Signing Secret, Bot Token.
  • A Google OAuth 2.0 client (type Web application) in the same project.
  • A Fernet key for encrypting stored refresh tokens.

One command

cp deploy/.env.deploy.example deploy/.env.deploy   # fill in secrets (gitignored)
bash deploy/deploy.sh

The script is idempotent and runs in two phases — the public URL isn’t known until the service exists, so it deploys, reads the URL, sets the OAuth redirect URIs, and redeploys. It will:

  • enable the required APIs (Run, Cloud Build, Artifact Registry, Secret Manager, Vertex AI, Storage, Firestore);
  • create the Firestore (Native mode) database and the state bucket gs://<project>-enoki-data;
  • create a dedicated runtime service account and grant it only aiplatform.user, datastore.user, secretmanager.secretAccessor (per-secret), and storage.objectAdmin on that one bucket;
  • push secrets to Secret Manager and deploy Cloud Run gen2 with the bucket mounted at /app/data, --max-instances=5 (override with MAX_INSTANCES), --min-instances=1.

After the first deploy

The script prints the service URL. Finish wiring both providers:

ProviderSettingValue
SlackOAuth Redirect URL<URL>/slack/oauth_redirect
SlackEvent Subscriptions request URL<URL>/slack/events
GoogleAuthorized redirect URI<URL>/google/oauth/callback

Then install to your workspace at <URL>/slack/install.

Why it scales

Because conversations, pending approvals, idempotency, and the audit log are all Firestore-backed, any instance can handle any request — including an Approve/Deny click that lands on a different instance than the one that paused the run. That’s what lets --max-instances be greater than one. See State & Storage for the full model. The runtime service account has no GCP data-plane access — broad reads and writes are always the user’s own OAuth identity.

Back to Setup, or start at Concepts.