# Project Livewire - Google Cloud Run Deployment Guide This guide provides step-by-step instructions for deploying the Project Livewire client and server components as containerized services on Google Cloud Run. This setup is recommended for a scalable and managed production-like environment. ## Prerequisites 1. **Google Cloud Project:** You need an active Google Cloud project. 2. **Google Cloud SDK (`gcloud`):** Installed and authenticated. * [Install Guide](https://cloud.google.com/sdk/docs/install) * Login: `gcloud auth login` * Set your project: `gcloud config set project YOUR_GOOGLE_CLOUD_PROJECT` (Replace `YOUR_GOOGLE_CLOUD_PROJECT`) 3. **Enabled APIs:** Ensure the following APIs are enabled in your project: * Cloud Build API (`cloudbuild.googleapis.com`) * Cloud Run API (`run.googleapis.com`) * Secret Manager API (`secretmanager.googleapis.com`) * IAM API (`iam.googleapis.com`) * Container Registry API (`containerregistry.googleapis.com`) or Artifact Registry API (`artifactregistry.googleapis.com`) * (Optional) Vertex AI API (`aiplatform.googleapis.com`) - If using the Vertex AI endpoint. * (Optional) Cloud Functions API (`cloudfunctions.googleapis.com`) - For deploying tools. * (Optional) Google Calendar API (`calendar-json.googleapis.com`) - For the calendar tool function. ```bash gcloud services enable run.googleapis.com cloudbuild.googleapis.com secretmanager.googleapis.com iam.googleapis.com containerregistry.googleapis.com aiplatform.googleapis.com cloudfunctions.googleapis.com calendar-json.googleapis.com ``` 4. **Deployed Cloud Functions:** The backend server relies on Cloud Functions for tool integration (weather, calendar). * Deploy these functions first by following the **[Cloud Functions Setup Guide](../cloud-functions/README.md)**. * You do *not* need the function URLs in an `.env` file for Cloud Run deployment if you configure them via Secret Manager or pass them during backend deployment (though storing them in secrets is common). 5. **Git Repository:** You should have the Project Livewire code cloned locally. ## Setup Steps ### 1. Create Backend Service Account The Cloud Run service for the backend needs an identity to securely access other Google Cloud services like Secret Manager. ```bash # Define service account name (optional, adjust if needed) export BACKEND_SA_NAME="livewire-backend" export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) # Create the service account gcloud iam service-accounts create ${BACKEND_SA_NAME} \ --description="Service account for Project Livewire backend Cloud Run service" \ --display-name="Livewire Backend SA" # Grant Secret Manager access to the service account gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:${BACKEND_SA_NAME}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role="roles/secretmanager.secretAccessor" # (Optional) Grant Vertex AI User role if using Vertex AI endpoint # gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ # --member="serviceAccount:${BACKEND_SA_NAME}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ # --role="roles/aiplatform.user" ``` ### 2. Store Secrets in Secret Manager Securely store API keys and potentially other sensitive configuration. The backend service account will access these. * **Google Gemini API Key:** ```bash # Replace YOUR_GEMINI_API_KEY with your actual key echo -n "YOUR_GEMINI_API_KEY" | \ gcloud secrets create GOOGLE_API_KEY --replication-policy="automatic" --data-file=- ``` * **OpenWeather API Key (for weather tool):** ```bash # Replace YOUR_OPENWEATHER_API_KEY with your actual key echo -n "YOUR_OPENWEATHER_API_KEY" | \ gcloud secrets create OPENWEATHER_API_KEY --replication-policy="automatic" --data-file=- ``` * **(Optional) Store Cloud Function URLs:** You can also store function URLs as secrets if preferred. ```bash # Example for Weather Function URL # echo -n "YOUR_WEATHER_FUNCTION_URL" | \ # gcloud secrets create WEATHER_FUNCTION_URL --replication-policy="automatic" --data-file=- ``` *(Note: The current `server/config/config.py` primarily expects URLs from environment variables, but could be adapted to read them from secrets if desired).* ### 3. Deploy the Backend Server to Cloud Run This uses Cloud Build (`server/cloudbuild.yaml`) to build the Docker image and deploy it to Cloud Run. ```bash # Navigate to the project root directory cd /path/to/project-livewire # Submit the build and deployment job # This uses the configuration in server/cloudbuild.yaml # It sets GOOGLE_CLOUD_PROJECT and the service account during deployment gcloud builds submit --config server/cloudbuild.yaml ``` * **What `server/cloudbuild.yaml` does:** * Builds a Docker image using `server/Dockerfile`. * Pushes the image to Google Container Registry (or Artifact Registry). * Deploys the image to Cloud Run as a service named `livewire-backend`. * Sets the region (default `us-central1` - modify YAML if needed). * Allows unauthenticated access (for easy client connection - **consider restricting access in production**). * Sets the container port to `8081`. * Sets environment variables (`GOOGLE_CLOUD_PROJECT`, `LOG_LEVEL`). You can add more here (like `GOOGLE_GENAI_USE_VERTEXAI=true`, `GOOGLE_CLOUD_LOCATION`, or Function URLs if not using secrets). * Assigns the `livewire-backend` service account created earlier. ### 4. Get the Backend Service URL After the deployment finishes, retrieve the URL of the backend service. ```bash # Replace us-central1 if you deployed to a different region export BACKEND_URL=$(gcloud run services describe livewire-backend --platform managed --region us-central1 --format 'value(status.url)') # Verify the URL (should start with https://...) echo "Backend URL: ${BACKEND_URL}" ``` **Important:** The client needs the **WebSocket** version of this URL (replace `https://` with `wss://`). ### 5. Deploy the Frontend Client to Cloud Run This uses Cloud Build (`client/cloudbuild.yaml`) to build the client's Docker image (which uses nginx to serve static files) and deploy it. We pass the backend's WebSocket URL to the build process. ```bash # Navigate to the project root directory (if not already there) cd /path/to/project-livewire # Construct the WebSocket URL for the backend export WSS_BACKEND_URL=$(echo ${BACKEND_URL} | sed 's|https://|wss://|') echo "WebSocket Backend URL: ${WSS_BACKEND_URL}" # Submit the build and deployment job for the frontend # Pass the WebSocket URL as a substitution variable gcloud builds submit --config client/cloudbuild.yaml \ --substitutions=_BACKEND_URL="${WSS_BACKEND_URL}" ``` * **What `client/cloudbuild.yaml` does:** * Builds a Docker image using `client/Dockerfile`. * Pushes the image to Google Container Registry (or Artifact Registry). * Deploys the image to Cloud Run as a service named `livewire-ui`. * Sets the region (default `us-central1` - modify YAML if needed). * Allows unauthenticated access. * Sets the container port to `8080`. * **Crucially:** It expects the `_BACKEND_URL` substitution. This URL is injected into the `nginx.conf` file *during the build process* so the client-side JavaScript can potentially fetch it or be configured accordingly. *(Self-correction: The current client JS hardcodes `ws://localhost:8081`. This needs adjustment for cloud deployment. A common pattern is to have the frontend fetch config from a `/config` endpoint served by nginx, which gets the URL via the build arg/env var, or embed it directly in the HTML/JS during build).* * *Modification needed:* The client code (`client/src/api/gemini-api.js`) needs to be updated to dynamically use the backend URL provided during deployment, rather than hardcoding `ws://localhost:8081`. This could involve fetching a config file or having the build process replace a placeholder. The `cloudbuild.yaml` substitution provides the URL, but the client needs to *use* it. A simple approach for this setup might be to modify `client/cloudbuild.yaml` to directly replace the placeholder in `gemini-api.js` using `sed` before building the image. ### 6. Get the Frontend Service URL Retrieve the URL for the deployed UI service. ```bash # Replace us-central1 if you deployed to a different region export FRONTEND_URL=$(gcloud run services describe livewire-ui --platform managed --region us-central1 --format 'value(status.url)') # Print the URL echo "Frontend URL: ${FRONTEND_URL}" ``` ### 7. Access the Application Open the `FRONTEND_URL` in your web browser to use the deployed Project Livewire application. ## Troubleshooting * **Cloud Build Failures:** * Check the Cloud Build logs in the Google Cloud Console for detailed error messages. * Ensure the Cloud Build service account has necessary permissions (e.g., to push to Container Registry, deploy to Cloud Run). * **Cloud Run Service Errors:** * Check the "Logs" tab for your `livewire-backend` and `livewire-ui` services in the Cloud Run section of the Google Cloud Console. * **Backend:** Look for errors related to Secret Manager access (check IAM roles), API key validity, connection issues to Gemini, or problems calling Cloud Functions. Ensure `GOOGLE_CLOUD_PROJECT` is correctly passed or available. * **Frontend:** Look for nginx errors or issues serving files. Ensure the backend URL was correctly passed during the build and is accessible. * **Connection Issues (Client <-> Server):** * Verify the WebSocket URL used by the client correctly points to the `wss://` version of the `livewire-backend` service URL. * Ensure both Cloud Run services allow ingress traffic (e.g., `--allow-unauthenticated` was used, or appropriate authentication is configured if restricted). Check firewall rules if applicable. * **Secret Manager Access Denied:** Double-check that the `livewire-backend` service account has the `roles/secretmanager.secretAccessor` role assigned in IAM. * **Quota Errors:** Monitor API usage (Gemini, Cloud Functions, etc.) in the Google Cloud Console. You might be hitting free tier limits or project quotas.