DEV Community

Cover image for Google Cloud Run: A serverless platform for containerized applications
Daniel Puig Gerarde
Daniel Puig Gerarde

Posted on

Google Cloud Run: A serverless platform for containerized applications

Google has always been at the forefront of cloud innovation, and with its introduction of Cloud Run, it has once again demonstrated its commitment to providing top-tier cloud solutions for developers. In this blog post, we'll delve deep into the wonders of Google Cloud Run: what it is, its benefits, and how to get started.

Google Cloud Run is a fully managed compute platform that enables you to run containerized applications without provisioning or managing servers. Cloud Run scales your application automatically based on demand, so you can focus on building great applications without worrying about the infrastructure.

There are many benefits to using Cloud Run, including:

  • Serverless: Cloud Run takes care of all the infrastructure management for you, so you can focus on your code.
  • Scalability: Cloud Run scales your application automatically based on demand, so you can handle unexpected spikes in traffic without any downtime.
  • Portability: Cloud Run uses standard containers, so you can easily port your applications to and from Cloud Run.
  • Pay as You Go: With Cloud Run, you only pay for the compute time you use. If your application isn't running, you aren't charged. This not only makes it cost-effective but also ensures that you're not overspending on idle resources.
  • Developer Friendly: Cloud Run supports multiple programming languages, and with its integration with Cloud Build, developers can automatically build and deploy their applications directly from their source repositories.

Use cases for Cloud Run

Cloud Run is a good choice for a wide range of applications, including:

  • Web applications: Cloud Run is a great way to run web applications, such as blogs, e-commerce sites, and content management systems.
  • Microservices: Cloud Run is a good choice for running microservices architectures, where each service is independently scalable and deployable.
  • Event-driven applications: Cloud Run can be used to build event-driven applications, such as real-time data processing and notification systems.
  • Machine learning applications: Cloud Run can be used to run machine learning applications, such as image recognition and natural language processing models.

Click here for more information, how to install and other steps.

Example

Tools

Operating Systems: Kubuntu
IDE: VSCode Google Cloud Code
Programming Language: Go
Container Runtime: Docker

We will create a microservice with some endpoints called patient-svc, which will be part of a Hospital Management System

  • Register new patient
  • Update patient details
  • Retrieve patient details
  1. Ctrl + P then type > Cloud Run: New Application.
  2. Select the option Cloud Run application.
  3. In this case select Go: Cloud Run.
  4. Select the directory to save the project with the name patient-svc.
  5. In the Cloud Code status bar, click the active project name.Image description

main.go

package main

import (
    "encoding/json"
    "log"
    "net/http"
    "sync"
)

type Patient struct {
    ID      string `json:"id"`
    Name    string `json:"name"`
    Address string `json:"address"`
}

var patients = make(map[string]Patient)
var mu sync.Mutex

func RegisterPatient(w http.ResponseWriter, r *http.Request) {
    var p Patient
    if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    mu.Lock()
    patients[p.ID] = p
    mu.Unlock()

    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(p)
}

func UpdatePatientDetails(w http.ResponseWriter, r *http.Request) {
    var p Patient
    if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    mu.Lock()
    if _, exists := patients[p.ID]; exists {
        patients[p.ID] = p
    } else {
        http.Error(w, "Patient not found", http.StatusNotFound)
        mu.Unlock()
        return
    }
    mu.Unlock()

    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(p)
}

func RetrievePatientDetails(w http.ResponseWriter, r *http.Request) {
    id := r.URL.Query().Get("id")
    if id == "" {
        http.Error(w, "ID is required", http.StatusBadRequest)
        return
    }

    mu.Lock()
    p, exists := patients[id]
    mu.Unlock()
    if !exists {
        http.Error(w, "Patient not found", http.StatusNotFound)
        return
    }

    json.NewEncoder(w).Encode(p)
}

func main() {
    http.HandleFunc("/register", RegisterPatient)
    http.HandleFunc("/update", UpdatePatientDetails)
    http.HandleFunc("/retrieve", RetrievePatientDetails)

    port := "8080"
    log.Printf("Server started on :%s", port)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}
Enter fullscreen mode Exit fullscreen mode

main_test.go

func TestRegisterPatient(t *testing.T) {
    // Create a new request with a JSON payload
    reqBody := []byte(`{"id": "123", "name": "John Doe", "age": 35}`)
    req, err := http.NewRequest("POST", "/register", bytes.NewBuffer(reqBody))
    if err != nil {
        t.Fatal(err)
    }

    // Set the request header content type to JSON
    req.Header.Set("Content-Type", "application/json")

    // Create a response recorder to record the response
    rr := httptest.NewRecorder()

    // Call the RegisterPatient function with the response recorder and request
    handler := http.HandlerFunc(RegisterPatient)
    handler.ServeHTTP(rr, req)

    // Check the status code is 201 Created
    if status := rr.Code; status != http.StatusCreated {
        t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusCreated)
    }

    // Check the response body is what we expect
    expected := `{"id":"123","name":"John Doe","age":35}`
    if rr.Body.String() != expected {
        t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)
    }
}

func TestUpdatePatientDetails(t *testing.T) {
    // Create a new request with a JSON payload
    reqBody := []byte(`{"id": "123", "name": "John Doe", "age": 36}`)
    req, err := http.NewRequest("PUT", "/update", bytes.NewBuffer(reqBody))
    if err != nil {
        t.Fatal(err)
    }

    // Set the request header content type to JSON
    req.Header.Set("Content-Type", "application/json")

    // Create a response recorder to record the response
    rr := httptest.NewRecorder()

    // Call the UpdatePatientDetails function with the response recorder and request
    handler := http.HandlerFunc(UpdatePatientDetails)
    handler.ServeHTTP(rr, req)

    // Check the status code is 200 OK
    if status := rr.Code; status != http.StatusOK {
        t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
    }

    // Check the response body is what we expect
    expected := `{"id":"123","name":"John Doe","age":36}`
    if rr.Body.String() != expected {
        t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)
    }
}
Enter fullscreen mode Exit fullscreen mode

Debug

  1. In the Cloud Code status bar, click the active project name.Image description
  2. Select Debug on Cloud Run Emulator. If it is the first time a form will appear. This is how I have it configured. screenshot01
  3. Debug View from the VSCode Code Editor

vscode debug

  1. Test the endpoints
$ curl -X POST -H "Content-Type: application/json" -d '{"id": "123", "name": "John Doe", "age": 35}' http://localhost:8080/register
{"id":"123","name":"John Doe","address":""}
Enter fullscreen mode Exit fullscreen mode
$ curl -X PUT -H "Content-Type: application/json" -d '{"id": "123", "name": "John Doe", "age": 36}' http://localhost:8080/update
{"id":"123","name":"John Doe","address":""}
Enter fullscreen mode Exit fullscreen mode
$ curl -X GET http://localhost:8080/retrieve?id=123
{"id":"123","name":"John Doe","address":""}
Enter fullscreen mode Exit fullscreen mode

Deploy

Refer to this guide for specific details https://cloud.google.com/run/docs/deploying

I present some screenshots of the details of my deployment using the Google Cloud Console.

Create a Service

Logs

https://patient-svc-3v56nzrvtq-uc.a.run.app

curl -X POST -H "Content-Type: application/json" -d '{"id": "123", "name": "John Doe", "age": 35}' https://patient-svc-3v56nzrvtq-uc.a.run.app/register 
{"id":"123","name":"John Doe","address":""}
Enter fullscreen mode Exit fullscreen mode

Google Cloud Run provides developers with a robust, scalable, and cost-effective platform to deploy containerized applications without the hassle of server management. As organizations continue to look for solutions that allow them to move fast and adapt to changing needs, platforms like Cloud Run will only become more pivotal. So, whether you're a startup or a well-established business, it might just be the right time to explore what Google Cloud Run can offer you!

Top comments (0)