Google App Engine Golang 连接到 Cloud SQL Postgres unix dial no such file or directory

Posted

技术标签:

【中文标题】Google App Engine Golang 连接到 Cloud SQL Postgres unix dial no such file or directory【英文标题】:Google App Engine Golang connect to Cloud SQL Postgres unix dial no such file or directory 【发布时间】:2019-08-07 17:54:18 【问题描述】:

大家好,我无法将我的 golang 应用程序连接到云 sql postgres 实例。我刚刚完成了他们在 Google Cloud Platform 中的教程和示例代码,但它似乎不起作用。我只有两个文件 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 服务。我也尝试过添加 appengine 导入,但似乎没有任何工作,它一直给我错误:

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

Cloud SQL Admin 也已启用。我只是注释掉了 env 以便于运行,无论硬编码查询路径还是从 yaml 导入,错误似乎都是一样的。

我希望有人可以帮助我。谢谢。

【问题讨论】:

这有关系吗? ***.com/questions/55201556/… 感谢您的回复,该错误确实相关..我已尝试使用标准环境执行文档,但仍然无济于事..已陷入此错误好几天了.. 【参考方案1】:

您似乎正在与 App Engine 连接(但您没有指定标准或灵活环境)。

如果您使用的是标准版,则 unix 套接字会自动在 /cloudsql/<INSTANCE_CONNECTION_NAME> 上可用。

如果您使用的是 Flexible,则需要在 app.yaml 中指定要连接的实例,这需要在 /cloudsql/<INSTANCE_CONNECTION_NAME> 创建 unix 套接字。

这些 un​​ix 套接字仅在运行时本身提供。如果您在本地运行并想要连接,则需要使用Cloud SQL proxy 在/cloudsql/<INSTANCE_CONNECTION_NAME> 创建 unix 套接字(或更新您的连接字符串以使用公共 IP 并以不同的方式进行身份验证)。

【讨论】:

感谢您的回复,我已经在 app.yaml 中指定了标准环境。上面的代码在云外壳代码编辑器中运行,但我现在可以使用代理在本地访问数据库。但是,如果我将该代码复制到编辑器,即使我更改了连接字符串也会出现同样的错误.. 云 shell 是与本地运行不同的环境。您需要在云 shell 中运行代理才能访问。值得注意的是,云外壳不会在会话之后持续存在 - 一旦您断开连接(或超时),代理将停止并且您的 /cloudsql 文件夹将被删除。当我提到您没有指定 Standard 或 Flex 时,我的意思是在您原来的帖子中。 我同意云 shell 不同于在本地运行。我真的认为我不再需要在云 shell 中运行代理了,因为我已经阅读了文档说同一个项目中的应用程序已经被授权访问云 sql 实例。如果使用 go 和 cloud sql postgres 部署应用程序,您对连接字符串有什么建议吗?我已经尝试了很多,但似乎没有一个工作,它给了我服务器错误。谢谢 Cloud Shell 是在云中配置的 VM,这意味着它是不同的机器。即使您在本地计算机上启动代理,您也必须在云 shell 中再次启动它才能从那里连接。对于连接字符串,您当前的示例缺少 dbname。示例中包含的内容确实有效。 不要忘记点赞或接受您认为有用的答案,因为它可以帮助其他用户更快地确定信息是否有用。【参考方案2】:

使用此设置的任何人。 我有类似的布局。

GCR 使用 Docker。 Golang 1.15 版 ORM sqlboiler golang dbapi CloudSQL 使用带有公共 IP 的 postgresql,您只能使用 cloudsql 代理访问该 IP,但 GCR -> CloudSQL 之间的连接被拒绝 型号:无法插入用户:拨号 tcp cloudsql-ip:5432:连接:连接超时

第一步

部署实例时

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/the-literal-instance-connection-name/"

使用命名 unix sock 的 Golang lib/pq + golang db API 连接

host=/cloudsql/the-literal-instance-connection-name/

什么是-literal-instance-connection-name?

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

来源

https://cloud.google.com/sql/docs/postgres/tutorial-connect-run#prepare_the_code

谷歌云文档中的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

【讨论】:

以上是关于Google App Engine Golang 连接到 Cloud SQL Postgres unix dial no such file or directory的主要内容,如果未能解决你的问题,请参考以下文章