谷歌应用引擎Golang连接到Cloud SQL Postgres时出现unix dial no such file or directory的错误

4
大家好,我在连接我的Golang应用程序到Cloud SQL Postgres实例时遇到了困难。我刚刚按照谷歌云平台的教程和示例代码进行操作,但似乎并没有起作用。我只有两个文件app.yaml和main.go来测试连接。

app.yaml

runtime: go api_version: go1 env: standard

env_variables:   CLOUDSQL_CONNECTION_NAME: bxustl2019proj:asia-east1:sqlstlbxu   CLOUDSQL_USER: ustldbbxu   CLOUDSQL_PASSWORD: bxuuserstldb   CLOUDSQL_DB: stlbxudbs

beta_settings:
      cloud_sql_instances: bxustl2019proj:asia-east1:sqlstlbxu

handlers:

- url: /(.*\.(gif|png|jpg))$   static_files: static/\1   upload: static/.*\.(gif|png|jpg)

- url: /.*   script: _go_app

main.go

package dptest

import (
    _"bytes"
    "database/sql"
    "fmt"
    "log"
    "net/http"
    "os"

     _ "github.com/lib/pq"
)

var db *sql.DB

func init() {
    db = DB()

    http.HandleFunc("/", indexHandler)
}

// DB gets a connection to the database.
// This can panic for malformed database connection strings, invalid credentials, or non-existance database instance.
func DB() *sql.DB {
    /*
    var (
        connectionName = mustGetenv("CLOUDSQL_CONNECTION_NAME")
        user           = mustGetenv("CLOUDSQL_USER")
        dbname           = mustGetenv("CLOUDSQL_DB")
        password       = os.Getenv("CLOUDSQL_PASSWORD") // NOTE: password may be empty
        socket         = os.Getenv("CLOUDSQL_SOCKET_PREFIX")
    )

    //cloudsql is used on App Engine.
    if socket == "" {
        socket = "/cloudsql"
    }
    */
    // PostgreSQL Connection, uncomment to use.
    // connection string format: user=USER password=PASSWORD host=/cloudsql/PROJECT_ID:REGION_ID:INSTANCE_ID/[ dbname=DB_NAME]
    //dbURI := fmt.Sprintf("user=%s password=%s host=/cloudsql/%s database=%s", user, password, connectionName, dbname)
    dbURI := fmt.Sprintf("user=ustldbbxu password=bxuuserstldb host=/cloudsql/bxustl2019proj:asia-east1:sqlstlbxu/stlbxudbs")

    conn, err := sql.Open("postgres", dbURI)
    log.Printf("CONNECTION: %v", conn)
    if err != nil {
        panic(fmt.Sprintf("DB: %v", err))
    }

    rows, err := conn.Query("SELECT * FROM GAMES")
    log.Printf("ROW: %v", rows)
    if err != nil {
        log.Printf("Could not query db: %v", err)
    }
    defer rows.Close()

    return conn
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        http.NotFound(w, r)
        return
    }

    w.Header().Set("Content-Type", "text/plain")

    log.Printf("CONNECTION: %v", db)
    rows, err := db.Query("SELECT * FROM GAMES")
    log.Printf("ROW: %v", rows)
    if err != nil {
        log.Printf("Could not query db: %v", err)
        http.Error(w, "Internal Error", 500)
        return
    }
    defer rows.Close()
}

func mustGetenv(k string) string {
    v := os.Getenv(k)
    if v == "" {
        log.Panicf("%s environment variable not set.", k)
    }
    return v
}

我尝试使用"go run ." 和 "goapp serve",还尝试添加了appengine导入包,但是似乎都没有起作用,并且一直给我报错:

无法查询数据库:dial unix /cloudsql/bxustl2019proj:asia-east1:sqlstlbxu/stlbxudbs/.s.PGSQL.5432:连接:没有这个文件或目录

Cloud SQL管理已启用。我只是注释掉了环境变量以便更轻松地运行,但不管是硬编码查询路径还是从yaml中导入,错误看起来都是相同的。

希望有人能够帮助我。谢谢。


这和什么有关吗?https://stackoverflow.com/questions/55201556/failed-to-connect-to-database-setting-up-gcp-app-engine - dina
谢谢您的回复,这个错误确实与代码有关。我已经尝试按照标准环境的文档进行操作,但仍然无法解决。我已经被这个错误困扰了好几天了。 - Elijah Garcia
2个回答

0

看起来你正在连接App Engine(但你没有指定标准或弹性环境)。

如果你在标准环境中,Unix套接字会自动出现在/cloudsql/<INSTANCE_CONNECTION_NAME>

如果你在弹性环境中,你需要在app.yaml中指定要连接的实例,这将需要在/cloudsql/<INSTANCE_CONNECTION_NAME>创建Unix套接字。

这些Unix套接字仅在运行时本身中提供。如果你在本地运行并想要连接,你需要使用Cloud SQL代理/cloudsql/<INSTANCE_CONNECTION_NAME>创建Unix套接字(或更新你的连接字符串以使用公共IP并通过不同的方式进行身份验证)。


谢谢您的回复,我已经在app.yaml中指定了标准环境。上面的代码在云shell代码编辑器中运行,但是现在我可以使用代理在本地访问数据库。然而,如果我将该代码复制到编辑器中,即使我更改了连接字符串,仍会出现相同的错误。 - Elijah Garcia
云Shell是与本地运行不同的环境。您需要在云Shell中运行代理才能访问。值得注意的是,云Shell不会持续存在于会话之外 - 一旦您断开连接(或超时),代理将停止并且您的/cloudsql文件夹将被删除。当我提到您没有指定标准版还是弹性版时,我是指您的原始帖子。 - kurtisvg
我确实同意云 shell 与本地运行有所不同。我曾经以为在云 shell 中不再需要运行代理,因为文档中说同一项目中的应用程序已经被授权访问云 SQL 实例。如果使用 Go 和 Cloud SQL Postgres 部署应用程序,请问您对连接字符串有什么建议吗?我尝试了很多连接字符串,但似乎都不起作用,并出现服务器错误。谢谢。 - Elijah Garcia
Cloud Shell是云中预配的虚拟机,这意味着它是一台不同的机器。即使您在本地计算机上启动代理,也必须在云Shell中重新启动它才能从那里连接。对于连接字符串,您当前的示例缺少dbname。示例中包含的内容确实有效。 - kurtisvg
非常感谢您的帮助,它确实对我有很大帮助。现在,我的应用程序正在灵活的环境中运行。我重新开始了整个过程,然后按照网站上特别是灵活环境的教程的每一步进行操作,结果成功了。非常感谢@kurtisvg。 - Elijah Garcia
1
不要忘记给你觉得有用的答案点赞或接受,因为这有助于其他用户更快地确定信息是否有用。 - kurtisvg

0

任何使用此设置的人。

  • 使用Docker的GCR。
  • Golang版本1.15
  • ORM sqlboiler
  • golang dbapi
  • CloudSQL使用带有公共IP的postgresql,您只能使用cloudsql代理访问它,但是GCR -> CloudSQL之间的连接被拒绝,出现以下错误: models: unable to insert into user: dial tcp cloudsql-ip:5432: connect: connection timed out

第一步

当您部署实例时

gcloud run deploy foo --add-cloudsql-instances the-literal-instance-connection-name --update-env-vars INSTANCE_CONNECTION_NAME="the-literal-instance-connection-name" --image your-image-name --region $REGION --project your-project-id --service-account=the-service-account-you-run-your-things --platform managed --no-allow-unauthenticated

运行该容器的服务帐户具有 IAM 角色 Cloud SQL 客户端

sqlboiler 的 Toml 格式

  • host = "/cloudsql/实例连接名称/"

Golang lib/pq + golang db API 使用命名 Unix sock 进行连接

  • host=/cloudsql/实例连接名称/

什么是“实例连接名称”?

转到您的 CloudSQL 实例,查看“实例连接名称”列,并将其用作值。

来源

Google Cloud 文档中的 Python 示例

query_string = dict({"unix_sock": "/cloudsql/{}/.s.PGSQL.5432".format(connection_name)})

如果你在Golang中使用类似的格式,它是行不通的,经过多次尝试和错误,我终于得到了正确的版本。
例如,在两个连接中添加.s.PGSQL.5432,最终会出现以下错误。
 unable to insert into user: dial unix /cloudsql/the-literal-instance-connection-name/.s.PGSQL.5432/.s.PGSQL.5432: connect: not a directory

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接