Google cloud run is a fully managed container execution environment. It is an environment specifically for request-driven workloads. It provides autoscaling, scaling down to zero, pretty fast deployments, automatic HTTPS support, global names and more. Google Cloud Run doesn’t have language runtime restrictions as soon as the language runtime is supported on gVisor. It only requires the deployments to expose an HTTP server on a port.
This guide assumes that you are familiar with cloud console and cloud shell environment.
In this guide, we will deploy a minimal helloworld HTTP server. The container runtime is expecting the server to listen on $PORT:
Related contents:
- How to use Terraform to create a vpc network and a GKE in GCP
- How to create and manage Secrets in GCP Secret Manager using Terraform
- How to Create a Service Account for Terraform in GCP
- How to use Terraform to create a Redis instance in GCP
- How to use Terraform to create a vpc network and a Cloud SQL in GCP
Google cloud Authentication and Enabling required APIs
Since we will deploy our code to google cloud, we will need to authenticate to it. In this guide we will use the command line to achieve most of what we want. Google provides a command line utility (gcloud) that allows you to perform most of the operations with the google cloud.
You will need to have gcloud
installed. If not, consult the gcloud installation page. Confirm that it is working as expected by checking the version installed:
➜ gcloud version
Google Cloud SDK 414.0.0
alpha 2023.01.13
beta 2023.01.13
bq 2.0.84
core 2023.01.13
gcloud-crc32c 1.0.0
gke-gcloud-auth-plugin 0.4.0
gsutil 5.18
Since we will be using cli to perform out operations, we need to authenticate to google cloud. Use this gcloud command:
gcloud auth login
Then do application login to generate credentials for client libraries:
gcloud auth application-default login
Once logged in, we need to enable the required APIs. In our case, we will use cloudbuild so enable it with this command:
export GCP_PROJECT_NAME=citizix-build-project
# We can use this to build and submit container image
gcloud services enable cloudbuild.googleapis.com --project $GCP_PROJECT_NAME
# We will use this to run our code
gcloud services enable run.googleapis.com --project $GCP_PROJECT_NAME
That is it with google authentication, we are now set to create out application and deploy to cloud build.
Creating a Golang Application
Before checking this section, ensure that you have golang installed and working as expected. Checkout the go downloads page if you need any assistance with that.
Once installed, confirm that it is working as expected by checking the version. This is the output on my machine:
➜ go version
go version go1.19.5 darwin/arm64
Now we can set up a directory and add out code. Create a new application directory and initialize it as a Go application using this command:
mkdir goapp
cd goapp
go mod init goapp
Inside the directory, we will create a file main.go
and add the following content
package main
import (
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", handleRoot)
log.Println("Starting server on 8080")
err := http.ListenAndServe(":8080", mux)
if errors.Is(err, http.ErrServerClosed) {
fmt.Printf("server closed\n")
} else if err != nil {
fmt.Printf("error starting server: %s\n", err)
os.Exit(1)
}
}
func handleRoot(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!\n")
}
The above code will spin up a web server listening on port 8080
that responds with Hello world on GET
request to /
. To test that it is working as expected, run it with the following command:
➜ go run main.go
2023/01/20 09:03:22 Starting server on 8080
On a separate terminal window, you can make request to our server using curl. You should see something similar to this:
➜ curl http://localhost:8080/
Hello world!
Dockerize the app
Cloud run expects a container. That means for out application to work it needs to be dockerized. As a prerequisite, you need to have docker installed and working in your machine. If not, checkout How to install and configure docker in Rocky Linux/Alma Linux 9.
Confirm that docker is working as expected by checking the version installed:
➜ docker version
Client:
Cloud integration: v1.0.29
Version: 20.10.21
API version: 1.41
Go version: go1.18.7
Git commit: baeda1f
Built: Tue Oct 25 18:01:18 2022
OS/Arch: darwin/arm64
Context: default
Experimental: true
Next we will dockerize the app. Create a file namedDockerfile
in the application directory and add the following content:
#Compile stage
FROM golang:1.19.5-alpine AS compiler
# Add required packages
ENV CGO_ENABLED 0 \
GOOS=linux
WORKDIR /app
ADD go.mod ./
RUN go mod download
ADD . .
RUN go build -o goapp
# Run stage
FROM alpine:3.16
WORKDIR /usr/src/app
COPY --from=compiler /app/goapp .
CMD ["/usr/src/app/goapp"]
To test that this will build as expected use this command:
docker build . -t goapp:latest
Pushing the image to Google Cloud Registry
Once we have our application container image built, we need to push it to GCR for cloud run to use.
If you want to use the docker commandline, authenticate to docker registry:
➜ gcloud auth configure-docker gcr.io
Adding credentials for: gcr.io
After update, the following will be written to your Docker config file located at
[/Users/eutychus/.docker/config.json]:
{
"credHelpers": {
"gcr.io": "gcloud"
}
}
Do you want to continue (Y/n)?
Docker configuration file updated.
Build and push the image to Google Container Registry using the following commands:
# Build the docker image
docker build -t gcr.io/$GCP_PROJECT_NAME/goapp:0.1.0 .
# Push the docker image to container registry
docker push gcr.io/$GCP_PROJECT_NAME/goapp:0.1.0
The other alternative is using gcloud builds submit specifying your image as shown in this command:
gcloud builds submit --project $GCP_PROJECT_NAME --tag gcr.io/$GCP_PROJECT_NAME/goapp:0.1.0
This command builds a container with your code and puts it in the Container Registry of your project. You can see the container if you click: Navigation menu > Container Registry. If you don’t see goapp
, click Refresh.
Deploying our application to cloud build:
We can use the earlier image to deploy our application on cloud build:
gcloud run deploy goapp --project $GCP_PROJECT_NAME \
--image=gcr.io/$GCP_PROJECT_NAME/goapp:0.1.0 \
--region=europe-west1 \
--allow-unauthenticated \
--max-instances=2
On success you will see output similat to this:
Deploying container to Cloud Run service [goapp] in project [citizix-run-project] region [europe-west1]
✓ Deploying... Done.
✓ Creating Revision...
✓ Routing traffic...
✓ Setting IAM Policy...
Done.
Service [myapp] revision [myapp-00002-yay] has been deployed and is serving 100 percent of traffic.
Service URL: https://myapp-[hash].a.run.app
To confirm that the application is working as expected, initiate a request to the given URL:
➜ curl https://myapp-[hash].a.run.app
Hello world!
The above shows that it is working as expected.
Inspecting Cloud run services
Now that the service is up and running, we can use these gcloud commands to manage them.
List cloud run services:
➜ gcloud run services list --project $GCP_PROJECT_NAME
SERVICE REGION URL LAST DEPLOYED BY LAST DEPLOYED AT
✔ goapp europe-west1 https://myapp-2kn7s444fa-ew.a.run.app [email protected] 2023-01-13T04:48:46.697844Z
Describe the service to get its details:
➜ gcloud run services describe myapp --project $GCP_PROJECT_NAME --region=europe-west1
✔ Service goapp in region europe-west1
URL: https://myapp-2kn7s444fa-ew.a.run.app
Ingress: all
Traffic:
100% LATEST (currently myapp-00002-yay)
Last updated on 2023-01-13T04:48:46.697844Z by [email protected]:
Revision myapp-00002-yay
Image: gcr.io/dev-fiddle/goapp:0.1.1
Port: 8080
Memory: 512Mi
CPU: 1000m
Service account: [email protected]
Concurrency: 80
Max Instances: 2
Timeout: 300s
If you no longer need the service you can delete using this command:
➜ gcloud run services delete goapp --region europe-west1 --project $GCP_PROJECT_NAME
Service [goapp] will be deleted.
Do you want to continue (Y/n)? y
Deleting [goapp]...done.
Deleted service [goapp].
Conclusion
Google Cloud Run is specifically optimized for request-driven HTTP/HTTPS workloads. The containers can be preempted and migrated, so it is not great if you are planning to use it for long running services. There is no support other than HTTP/HTTPS for now either.