1. Overview
The Cloud SQL Go connector is the easiest way to securely connect your Go application to your Cloud SQL database. Cloud Run is a fully managed serverless platform that enables you to run stateless containers that are invocable via HTTP requests. This Codelab will demonstrate how to connect a Go application on Cloud Run to a Cloud SQL for PostgreSQL database securely with a service account using IAM Authentication.
What you will learn
In this lab, you will learn how to do the following:
- Create a Cloud SQL for PostgreSQL database
- Deploy a Go application to Cloud Run
- Connect your application to Cloud SQL using the Go Connector
Prerequisites
- This lab assumes familiarity with the Cloud Console and Cloud Shell environments.
2. Before you begin
Cloud Project setup
- Sign-in to the Google Cloud Console and create a new project or reuse an existing one. If you don't already have a Google account, you must create one.
- The Project name is the display name for this project's participants. It is a character string not used by Google APIs. You can update it at any time.
- The Project ID is unique across all Google Cloud projects and is immutable (cannot be changed after it has been set). The Cloud Console auto-generates a unique string; usually you don't care what it is. In most codelabs, you'll need to reference the Project ID (it is typically identified as
PROJECT_ID
). If you don't like the generated ID, you may generate another random one. Alternatively, you can try your own and see if it's available. It cannot be changed after this step and will remain for the duration of the project. - For your information, there is a third value, a Project Number which some APIs use. Learn more about all three of these values in the documentation.
- Next, you'll need to enable billing in the Cloud Console to use Cloud resources/APIs. Running through this codelab shouldn't cost much, if anything at all. To shut down resources so you don't incur billing beyond this tutorial, you can delete the resources you created or delete the whole project. New users of Google Cloud are eligible for the $300 USD Free Trial program.
Environment Setup
Activate Cloud Shell by clicking on the icon to the right of the search bar.
From Cloud Shell, enable the APIs:
gcloud services enable compute.googleapis.com sqladmin.googleapis.com \
run.googleapis.com artifactregistry.googleapis.com \
cloudbuild.googleapis.com servicenetworking.googleapis.com
If prompted to authorize, click "Authorize" to continue.
This command may take a few minutes to complete, but it should eventually produce a successful message similar to this one:
Operation "operations/acf.p2-327036483151-73d90d00-47ee-447a-b600-a6badf0eceae" finished successfully.
3. Set up a Service Account
Create and configure a Google Cloud service account to be used by Cloud Run so that it has the correct permissions to connect to Cloud SQL.
- Run the
gcloud iam service-accounts create
command as follows to create a new service account:gcloud iam service-accounts create quickstart-service-account \ --display-name="Quickstart Service Account"
- Run the gcloud projects add-iam-policy-binding command as follows to add the Cloud SQL Client role to the Google Cloud service account you just created. In Cloud Shell, the expression
${GOOGLE_CLOUD_PROJECT}
will be replaced by the name of your project. You can also do this replacement manually if you feel more comfortable with that.gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role="roles/cloudsql.client"
- Run the gcloud projects add-iam-policy-binding command as follows to add the Cloud SQL Instance User role to the Google Cloud service account you just created.
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role="roles/cloudsql.instanceUser"
- Run the gcloud projects add-iam-policy-binding command as follows to add the Log Writer role to the Google Cloud service account you just created.
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role="roles/logging.logWriter"
4. Set up Cloud SQL
Run the gcloud sql instances create
command to create a Cloud SQL instance.
- –database-version: The database engine type and version. If left unspecified, the API default is used. See the gcloud database versions documentation to see the current available versions.
- –cpu: The number of cores desired in the machine.
- –memory: Whole number value indicating how much memory is desired in the machine. A size unit should be provided (for example, 3072MB or 9GB). If no units are specified, GB is assumed.
- –region: Regional location of the instance (for example: us-central1, asia-east1, us-east1).
- –database-flags: Allows setting flags. In this case, we are turning on
cloudsql.iam_authentication
to enable Cloud Run to connect to Cloud SQL using the service account we created before.gcloud sql instances create quickstart-instance \ --database-version=POSTGRES_14 \ --cpu=1 \ --memory=4GB \ --region=us-central1 \ --database-flags=cloudsql.iam_authentication=on
This command may take a few minutes to complete.
Run the gcloud sql databases create
command to create a Cloud SQL database within the quickstart-instance
.
gcloud sql databases create quickstart_db \
--instance=quickstart-instance
Create a PostgreSQL database user for the service account you created earlier to access the database.
gcloud sql users create quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam \
--instance=quickstart-instance \
--type=cloud_iam_service_account
5. Prepare Application
Prepare a Go application that responds to HTTP requests.
- In Cloud Shell create a new directory named
helloworld
, then change into that directory:mkdir helloworld cd helloworld
- Run
go mod init
to initialize a new Go application.go mod init github.com/GoogleCloudPlatform/golang-samples/run/helloworld
- Install the Cloud SQL Go Connector dependency.
go get cloud.google.com/go/cloudsqlconn go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
- Create a
main.go
file with the application code. This code is able to:- Accept HTTP requests
- Connect to the database
- Store the time of the HTTP request in the database
- Return the times of the last five requests
cat > main.go << "EOF" package main import ( "database/sql" "encoding/json" "fmt" "log" "net/http" "os" "time" "cloud.google.com/go/cloudsqlconn" "cloud.google.com/go/cloudsqlconn/postgres/pgxv4" ) // visitData is used to pass data to the HTML template. type visitData struct { RecentVisits []visit } // visit contains a single row from the visits table in the database. // Each visit includes a timestamp. type visit struct { VisitTime time.Time } // getDB creates a connection to the database // based on environment variables. func getDB() (*sql.DB, func() error) { cleanup, err := pgxv4.RegisterDriver("cloudsql-postgres", cloudsqlconn.WithIAMAuthN()) if err != nil { log.Fatalf("Error on pgxv4.RegisterDriver: %v", err) } dsn := fmt.Sprintf("host=%s user=%s dbname=%s sslmode=disable", os.Getenv("INSTANCE_CONNECTION_NAME"), os.Getenv("DB_USER"), os.Getenv("DB_NAME")) db, err := sql.Open("cloudsql-postgres", dsn) if err != nil { log.Fatalf("Error on sql.Open: %v", err) } createVisits := `CREATE TABLE IF NOT EXISTS visits ( id SERIAL NOT NULL, created_at timestamp NOT NULL, PRIMARY KEY (id) );` _, err = db.Exec(createVisits) if err != nil { log.Fatalf("unable to create table: %s", err) } return db, cleanup } func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } log.Printf("Listening on port %s", port) db, cleanup := getDB() defer cleanup() http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { // Insert current visit _, err := db.Exec("INSERT INTO visits(created_at) VALUES(NOW())") if err != nil { log.Fatalf("unable to save visit: %v", err) } // Get the last 5 visits rows, err := db.Query("SELECT created_at FROM visits ORDER BY created_at DESC LIMIT 5") if err != nil { log.Fatalf("DB.Query: %v", err) } defer rows.Close() var visits []visit for rows.Next() { var visitTime time.Time err := rows.Scan(&visitTime) if err != nil { log.Fatalf("Rows.Scan: %v", err) } visits = append(visits, visit{VisitTime: visitTime}) } response, err := json.Marshal(visitData{RecentVisits: visits}) if err != nil { log.Fatalf("renderIndex: failed to parse totals with json.Marshal: %v", err) } w.Write(response) }) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatal(err) } } EOF
This code creates a basic web server that listens on the port defined by the PORT environment variable. The application is now ready to be deployed.
6. Deploy Cloud Run Application
Run the command below to deploy your application:
- –region: Regional location of the instance (for example: us-central1, asia-east1, us-east1).
- –source: The source code to be deployed. In this case,
.
refers to the source code in the current folderhelloworld
. - –set-env-vars: Sets environment variables used by the application to direct the application to the Cloud SQL database.
- –service-account: Ties the Cloud Run deployment to the service account with permissions to connect to the Cloud SQL database created at the beginning of this Codelab.
- –allow-unauthenticated: Allows unauthenticated requests so that the application is accessible from the internet.
gcloud run deploy helloworld \
--region=us-central1 \
--source=. \
--set-env-vars INSTANCE_CONNECTION_NAME="${GOOGLE_CLOUD_PROJECT}:us-central1:quickstart-instance" \
--set-env-vars DB_NAME="quickstart_db" \
--set-env-vars DB_USER="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam" \
--service-account="quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
--allow-unauthenticated
If prompted, press y
and Enter
to confirm that you would like to continue:
Do you want to continue (Y/n)? y
After a few minutes, the application should provide a URL for you to visit.
Navigate to the URL to see your application in action. Every time you visit the URL or refresh the page, you will see the five most recent visits returned as JSON.
7. Congratulations
You have deployed a Go application on Cloud Run that is able to connect to a PostgreSQL database running on Cloud SQL.
What we've covered:
- Creating a Cloud SQL for PostgreSQL database
- Deploying a Go application to Cloud Run
- Connecting your application to Cloud SQL using the Go Connector
Clean up
To avoid incurring charges to your Google Cloud account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources. If you would like to delete the entire project, you can run:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}