Skip to content

Deploying data formulator App #186

@JohnTan38

Description

@JohnTan38

Dear Community
We'd like to deploy this excellent App to a cloud service (example Google Cloud Run for backend, Vercel for frontend). Guidance and instructions are welcome. Thank you.

[vercel.json](https://github.com/user-attachments/files/22358026/vercel.json)

Dockerfile

Stage 1: build frontend

FROM node:18 AS frontend-build
WORKDIR /app/frontend

copy frontend package and source (project stores package.json inside Scripts/)

COPY Scripts/package.json Scripts/package-lock.json* ./
COPY src ./src
COPY Scripts/public ./public
COPY Scripts/vite.config.ts ./

RUN npm ci --silent
RUN npm run build

Stage 2: build backend image

FROM python:3.11-slim
WORKDIR /app

system deps needed for psycopg2 / building wheels

RUN apt-get update &&
apt-get install -y --no-install-recommends build-essential libpq-dev gcc &&
rm -rf /var/lib/apt/lists/*

install python deps

COPY Scripts/requirements.txt ./requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

copy backend source

COPY py-src/data_formulator ./data_formulator
COPY py-src/pyproject.toml ./pyproject.toml

copy built frontend into Flask static directory (adjust if Flask static path differs)

RUN mkdir -p /app/data_formulator/static
COPY --from=frontend-build /app/frontend/dist /app/data_formulator/static

ENV PORT=8080
EXPOSE 8080

run with gunicorn; adjust module path if your Flask app entry differs

CMD ["gunicorn", "--bind", "0.0.0.0:8080", "data_formulator.app:app", "--workers", "2", "--timeout", "120"]

param(
[string]$PROJECT_ID = "spheric-crow-424609-t1",
[string]$REGION = "asia-southeast1",
[string]$SERVICE_NAME = "data-formulator",
[string]$IMAGE = "",
[string]$INSTANCE_CONNECTION_NAME = "spheric-crow-424609-t1:asia-southeast1:data-formulator"
)

Check gcloud is available

if (-not (Get-Command gcloud -ErrorAction SilentlyContinue)) {
Write-Error "gcloud CLI not found. Install Google Cloud SDK and ensure 'gcloud' is on PATH. See https://cloud.google.com/sdk/docs/install"
exit 1
}

Check Docker is available

if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
Write-Error "Docker CLI not found. Install Docker and ensure 'docker' is on PATH. See https://docs.docker.com/get-docker/"
exit 1
}

prepare image variable

if (-not $IMAGE) { $IMAGE = "gcr.io/$PROJECT_ID/$SERVICE_NAME:latest" }

Write-Host "Project: $PROJECT_ID"
Write-Host "Region: $REGION"
Write-Host "Service: $SERVICE_NAME"
Write-Host "Image: $IMAGE"
Write-Host "Cloud SQL instance: $INSTANCE_CONNECTION_NAME"
Write-Host ""

deploy-cloud-run.ps1

1. ensure gcloud is configured

gcloud auth login --quiet
gcloud config set project $PROJECT_ID

2. enable required APIs

gcloud services enable run.googleapis.com cloudbuild.googleapis.com sqladmin.googleapis.com secretmanager.googleapis.com --project $PROJECT_ID

3. read DB password securely and store in Secret Manager

Write-Host "Enter the Postgres DB password (will be stored in Secret Manager 'data-formulator-db-password'):"
$secure = Read-Host -AsSecureString

convert SecureString to plain (used only to create secret; avoid storing plain in files)

$ptr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
$plain = [Runtime.InteropServices.Marshal]::PtrToStringAuto($ptr)
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr)

$tempFile = [System.IO.Path]::GetTempFileName()
Set-Content -Path $tempFile -Value $plain -NoNewline
Remove-Variable plain, ptr

create or add secret

$secretName = "data-formulator-db-password"
$exists = & gcloud secrets describe $secretName --project $PROJECT_ID 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Host "Creating secret $secretName in Secret Manager..."
gcloud secrets create $secretName --replication-policy="automatic" --data-file="$tempFile" --project $PROJECT_ID
} else {
Write-Host "Adding new version to secret $secretName..."
gcloud secrets versions add $secretName --data-file="$tempFile" --project $PROJECT_ID
}
Remove-Item $tempFile -Force

4. build and push container image using Cloud Build

Write-Host "Building container and submitting to Google Cloud Build..."
gcloud builds submit --tag $IMAGE --project $PROJECT_ID

5. deploy to Cloud Run, attach Cloud SQL, and mount secret as env var

Write-Host "Deploying to Cloud Run..."
gcloud run deploy $SERVICE_NAME --image $IMAGE
--region $REGION --platform managed
--allow-unauthenticated --add-cloudsql-instances $INSTANCE_CONNECTION_NAME
--set-env-vars "DB_HOST=/cloudsql/$INSTANCE_CONNECTION_NAME,DB_USER=postgres,DB_DATABASE=postgres,EXTERNAL_DB=true" --set-secrets "DB_PASSWORD=$secretName:latest"
--project $PROJECT_ID

6. grant service account access to Cloud SQL and Secret Manager

$serviceSa = gcloud run services describe $SERVICE_NAME --region $REGION --format="value(spec.template.spec.serviceAccountName)" --project $PROJECT_ID
if ($serviceSa) {
Write-Host "Granting roles/cloudsql.client and roles/secretmanager.secretAccessor to $serviceSa ..."
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$serviceSa" --role="roles/cloudsql.client" --project $PROJECT_ID
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:$serviceSa" --role="roles/secretmanager.secretAccessor" --project $PROJECT_ID
} else {
Write-Host "Could not determine Cloud Run service account. Please grant roles/cloudsql.client and roles/secretmanager.secretAccessor to the Cloud Run service account manually."
}

7. show service URL

$svcUrl = gcloud run services describe $SERVICE_NAME --region $REGION --format="value(status.url)" --project $PROJECT_ID
Write-Host ""
Write-Host "Deployment complete. Service URL: $svcUrl"
Write-Host "Note: Ensure py-src/data_formulator/db_manager.py treats DB_HOST starting with '/cloudsql/' as a unix socket path (e.g. pass host='/cloudsql/INSTANCE_CONNECTION_NAME' to psycopg2)."

...existing code...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions