Deploy µQuery on GCP Cloud Run
- A Google Cloud account with billing enabled
- gcloud CLI installed and authenticated
- A GCP project with the following APIs enabled: Cloud Run, Cloud Storage, IAM
This tutorial walks through deploying µQuery on Cloud Run to query files stored in Cloud Storage. Authentication is handled via the GCP credential chain — no API keys or HMAC secrets required.
1. Set variables
Define these once. All subsequent commands reference them.
export PROJECT_ID="your-project-id"
export REGION="europe-west1"
export BUCKET_NAME="uquery-data"
export SERVICE_ACCOUNT_NAME="uquery-sa"
export CLOUD_RUN_SERVICE="uquery"
# Derived
export SERVICE_ACCOUNT_EMAIL="${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud config set project $PROJECT_ID
2. Create a Cloud Storage bucket
gcloud storage buckets create gs://$BUCKET_NAME \
--location=$REGION \
--uniform-bucket-level-access
Upload sample data
Download a Yellow Taxi Parquet file and upload it:
wget https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2026-01.parquet
gcloud storage cp yellow_tripdata_2026-01.parquet gs://$BUCKET_NAME/
3. Create a service account
gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
--display-name="uQuery Service Account" \
--description="Service account for µQuery on Cloud Run"
Grant read access to the bucket
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_NAME \
--member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
--role="roles/storage.objectViewer"
If µQuery needs to write files (e.g. COPY TO), use roles/storage.objectUser instead.
4. Deploy to Cloud Run
µQuery uses the GCP credential chain (UQ_GCS_CREDENTIAL_CHAIN=true) to authenticate against Cloud Storage. When running on Cloud Run, the attached service account is automatically detected — no secrets or key files needed.
gcloud run deploy $CLOUD_RUN_SERVICE \
--image=docker.io/fb64/uquery:latest \
--region=$REGION \
--service-account=$SERVICE_ACCOUNT_EMAIL \
--set-env-vars="UQ_GCS_CREDENTIAL_CHAIN=true" \
--allow-unauthenticated \
--port=8080 \
--cpu=1 \
--memory=512Mi \
--min-instances=0 \
--max-instances=10
Once deployed, retrieve the service URL:
export UQUERY_URL=$(gcloud run services describe $CLOUD_RUN_SERVICE \
--region=$REGION \
--format="value(status.url)")
echo $UQUERY_URL
5. Query your data
Use the gcs:// prefix to reference Cloud Storage files directly in SQL.
Count rows
curl -X POST $UQUERY_URL \
-H "Content-Type: text/plain" \
-d "SELECT COUNT(*) FROM 'gcs://$BUCKET_NAME/yellow_tripdata_2026-01.parquet'"
Aggregate query
curl -X POST $UQUERY_URL \
-H "Content-Type: text/plain" \
-H "Accept: application/json" \
-d "
SELECT
payment_type,
COUNT(*) AS trips,
ROUND(AVG(fare_amount), 2) AS avg_fare
FROM 'gcs://$BUCKET_NAME/yellow_tripdata_2026-01.parquet'
GROUP BY payment_type
ORDER BY trips DESC
"
Stream as Arrow IPC
curl -X POST $UQUERY_URL \
-H "Content-Type: text/plain" \
-H "Accept: application/vnd.apache.arrow.stream" \
-d "SELECT * FROM 'gcs://$BUCKET_NAME/yellow_tripdata_2026-01.parquet' LIMIT 1000" \
--output result.arrow
Check service health
curl $UQUERY_URL/health
6. Restrict access (recommended for production)
By default the service is public (--allow-unauthenticated). To require a Google identity:
# Remove unauthenticated access
gcloud run services update $CLOUD_RUN_SERVICE \
--region=$REGION \
--no-allow-unauthenticated
# Call the service with an identity token
curl -X POST $UQUERY_URL \
-H "Authorization: Bearer $(gcloud auth print-identity-token)" \
-H "Content-Type: text/plain" \
-d "SELECT 1"
7. Clean up
gcloud run services delete $CLOUD_RUN_SERVICE --region=$REGION
gcloud storage rm --recursive gs://$BUCKET_NAME
gcloud iam service-accounts delete $SERVICE_ACCOUNT_EMAIL