Deploying to Cloud Run from a client-side web app

Deploying to Cloud Run from a client-side web app

Google Cloud Run makes it incredibly easy to deploy and scale containerized applications. Typically, you might use the gcloud command-line tool or the Google Cloud Console. But did you know it's possible to empower users to deploy applications directly from a web interface, using entirely client-side code? You can even try it yourself at deploy-cloud-run.steren.dev and find the full source code for the examples at github.com/steren/deploy-cloud-run-webapp.

Imagine a scenario where your users can vibe or write code in your web app and are looking for a serverless runtime to deploy it. You can allow them to deploy it to their own Google Cloud project with a button click. Another scenario would be if you offered a set of pre-defined templates (as containers). This is achievable by using Google Cloud APIs directly from client-side JavaScript and using the user’s credentials via a login with Google, no server required.

In this post, we'll explore how to build client-side web apps that can:

  1. Deploy a simple, pre-built container image to Cloud Run.
  2. Deploy an application from source code provided by the user, utilizing Cloud Build and Artifact Registry behind the scenes.

No dependency

We will do all that from scratch, no Google Cloud client libraries required, simply using JavaScript's fetch function to make calls to Google Cloud’s REST APIs, including the user's access token in the Authorization header. Many of these API calls (like creating a service or starting a build) initiate operations that take time. The initial API response often returns an operation ID. We need to poll or use a dedicated wait endpoint to determine when the operation is complete.

Prerequisites: Authenticating the current user and getting a token

Before the web app can make calls to Google Cloud APIs on behalf of the user, it needs their permission. We achieve this using OAuth 2.0.

For purely client-side applications, I am just copy pasting a great pure JavaScript sample from the official OAuth 2.0 for Client-side Web Applications docs.

The flow is the following:

Scenario 1: Deploying a Pre-built Container

This is the simplest case. Assuming the user is authenticated (see Prerequisites), we just need their Project ID and the container image URL that you have pre-built for them and stored in DockerHub or a public Artifact Registry repository.

(Source code: GitHub)

Steps:

  1. Get project ID: The user provides their Google Cloud Project ID.
  2. Deploy: The app defines the service configuration (image: gcr.io/cloudrun/hello, scaling, etc.) and makes a POST request to the Cloud Run API (/services) with the user's access token and config to start deployment, receiving an operation name.
  3. Wait & Get URL: The app calls the operation's :wait endpoint. Once complete, it makes a GET request to the service endpoint to retrieve and display the public URL.

Scenario 2: Deploying from source code

This scenario builds the container image first. It assumes the user is authenticated and has provided their Project ID.

(Source code: GitHub)

Steps:

  1. Setup Prerequisites: Ensure required APIs (Cloud Run, Build, Artifact Registry, Storage) are enabled and that a Cloud Storage bucket and Artifact Registry repository exist, waiting for any creation Long Running Operation.
  2. Select Source Folder: Gather the user's source (for example by prompting them user to select a folder or just write code in an editor.
  3. Process & Upload Source: Validate a Dockerfile exists, zip the folder contents in memory, and upload the zip archive to the Cloud Storage bucket.
  4. Trigger Cloud Build: Define and submit a Cloud Build job (POST /builds) pointing to the source zip, configured to build/push the image to Artifact Registry. Get the build Long Running Operation name.
  5. Wait for Build: Poll the Cloud Build API (GET /v1/{build_operation_name}) until the build succeeds or fails. Retrieve the built image URI.
  6. Deploy to Cloud Run: Check if the target Cloud Run service exists (GET). Create (POST) or update (PATCH) the service using the built image URI. Get the Cloud Run Long Running Operation name.
  7. Wait for Deployment: Use the Cloud Run operation's :wait endpoint.
  8. Get Service URL: Retrieve the final service details (GET) and display its URL.

Conclusion

By leveraging Google Cloud APIs and client-side JavaScript, you can offer a "one click" deployment experience from your client side web app to the user's Google Cloud project. While the "deploy from source" workflow involves more steps (Storage, Build, Artifact Registry), they can all be abstracted away from the user to provide a seamless deployment experience.

Feel free to try out the live demo at deploy-cloud-run.steren.dev and check out the complete source code on GitHub at github.com/steren/deploy-cloud-run-webapp to see these concepts in action!