1. 概览
Cloud SQL Go 连接器是将 Go 应用安全地连接到 Cloud SQL 数据库的最简单方法。Cloud Run 是一个全代管式无服务器平台,供您运行可通过 HTTP 请求调用的无状态容器。此 Codelab 将演示如何使用 IAM 身份验证通过服务账号将 Cloud Run 上的 Go 应用安全地连接到 Cloud SQL for PostgreSQL 数据库。
学习内容
在本实验中,您将学习如何完成以下操作:
- 创建 Cloud SQL for PostgreSQL 数据库
- 将 Go 应用部署到 Cloud Run
- 使用 Go 连接器将应用连接到 Cloud SQL
前提条件
- 本实验假定您熟悉 Cloud 控制台和 Cloud Shell 环境。
2. 准备工作
Cloud 项目设置
- 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Google 账号,则必须创建一个。
- 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
- 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常您不在乎这是什么在大多数 Codelab 中,您都需要引用项目 ID(它通常标识为
PROJECT_ID
)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且该 ID 在项目期间会一直保留。 - 此外,还有第三个值,即某些 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档。
- 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。如需关停资源,以免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除整个项目。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。
环境设置
点击搜索栏右侧的图标,激活 Cloud Shell。
在 Cloud Shell 中,启用 API:
gcloud services enable compute.googleapis.com sqladmin.googleapis.com \
run.googleapis.com artifactregistry.googleapis.com \
cloudbuild.googleapis.com servicenetworking.googleapis.com
如果系统提示您授权,请点击“授权”以继续。
此命令可能需要几分钟才能完成,但最终应生成类似于以下内容的成功消息:
Operation "operations/acf.p2-327036483151-73d90d00-47ee-447a-b600-a6badf0eceae" finished successfully.
3. 设置服务账号
创建并配置 Google Cloud 服务账号以供 Cloud Run 使用,使其具有连接到 Cloud SQL 的正确权限。
- 按如下方式运行
gcloud iam service-accounts create
命令以创建新的服务账号:gcloud iam service-accounts create quickstart-service-account \ --display-name="Quickstart Service Account"
- 如下所示运行 gcloud projects add-iam-policy-binding 命令,将 Cloud SQL Client 角色添加到您刚创建的 Google Cloud 服务账号。在 Cloud Shell 中,表达式
${GOOGLE_CLOUD_PROJECT}
将替换为您的项目名称。如果您觉得更合适,也可以手动进行替换。gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role="roles/cloudsql.client"
- 如下所示运行 gcloud projects add-iam-policy-binding 命令,将 Cloud SQL Instance User 角色添加到您刚创建的 Google Cloud 服务账号。
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role="roles/cloudsql.instanceUser"
- 如下所示运行 gcloud projects add-iam-policy-binding 命令,将 Log Writer 角色添加到您刚刚创建的 Google Cloud 服务账号。
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. 设置 Cloud SQL
运行 gcloud sql instances create
命令以创建 Cloud SQL 实例。
- -database-version:数据库引擎类型和版本。如果未指定,系统会使用 API 默认值。如需了解当前可用的版本,请参阅 gcloud 数据库版本文档。
- -cpu:机器中所需的核心数。
- –memory:整数值,表示计算机需要多少内存。应提供大小单位(例如 3072MB 或 9GB)。如果未指定单位,则假定为 GB。
- -region:实例的区域位置(例如:us-central1、asia-east1、us-east1)。
- –database-flags:允许设置标志。在本例中,我们将开启
cloudsql.iam_authentication
,以便 Cloud Run 使用我们之前创建的服务账号连接到 Cloud SQL。gcloud sql instances create quickstart-instance \ --database-version=POSTGRES_14 \ --cpu=1 \ --memory=4GB \ --region=us-central1 \ --database-flags=cloudsql.iam_authentication=on
此命令可能需要几分钟才能完成。
运行 gcloud sql databases create
命令以在 quickstart-instance
中创建 Cloud SQL 数据库。
gcloud sql databases create quickstart_db \
--instance=quickstart-instance
为您之前创建的服务账号创建一个用于访问数据库的 PostgreSQL 数据库用户。
gcloud sql users create quickstart-service-account@${GOOGLE_CLOUD_PROJECT}.iam \
--instance=quickstart-instance \
--type=cloud_iam_service_account
5. 准备应用
准备响应 HTTP 请求的 Go 应用。
- 在 Cloud Shell 中,新建一个名为
helloworld
的目录,然后切换到该目录:mkdir helloworld cd helloworld
- 运行
go mod init
以初始化新的 Go 应用。go mod init github.com/GoogleCloudPlatform/golang-samples/run/helloworld
- 安装 Cloud SQL Go 连接器依赖项。
go get cloud.google.com/go/cloudsqlconn go get cloud.google.com/go/cloudsqlconn/postgres/pgxv4
- 创建一个包含应用代码的
main.go
文件。此代码能够:- 接受 HTTP 请求
- 连接到数据库
- 在数据库中存储 HTTP 请求的时间
- 返回最近五个请求的时间
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
此代码会创建一个基本 Web 服务器,监听由 PORT 环境变量定义的端口。应用现已准备就绪,可以进行部署了。
6. 部署 Cloud Run 应用
运行以下命令以部署您的应用:
- -region:实例的区域位置(例如:us-central1、asia-east1、us-east1)。
- -source:要部署的源代码。在本例中,
.
是指当前文件夹helloworld
中的源代码。 - –set-env-vars:设置应用用于将应用定向到 Cloud SQL 数据库的环境变量。
- –service-account:将 Cloud Run 部署关联到有权连接到在此 Codelab 开头创建的 Cloud SQL 数据库的服务账号。
- –allow-unauthenticated:允许未经身份验证的请求,以便通过互联网访问应用。
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
如果出现提示,请按 y
和 Enter
以确认您要继续:
Do you want to continue (Y/n)? y
几分钟后,应用应该会提供一个网址供您访问。
导航到该网址以查看应用的运行情况。您每次访问该网址或刷新页面时,您都会看到以 JSON 格式返回的最近五次访问。
7. 恭喜
您已在 Cloud Run 上部署了一个 Go 应用,该应用能够连接到在 Cloud SQL 上运行的 PostgreSQL 数据库。
所学内容:
- 创建 Cloud SQL for PostgreSQL 数据库
- 将 Go 应用部署到 Cloud Run
- 使用 Go 连接器将应用连接到 Cloud SQL
清理
为避免系统因本教程中使用的资源向您的 Google Cloud 账号收取费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。如果要删除整个项目,您可以运行以下命令:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}