Cloud Run 和 Cloud SQL 代理似乎无法协同工作

问题描述 投票:0回答:1

云运行使用的服务帐号权限绰绰有余。 Cloud SQL Admin、Cloud Run Admin 以及许多其他此处不相关的内容,我可以为其授予完整的项目所有者权限,但它不会工作。

我们还知道,使用 Cloud SQL 代理在 Cloud Run 外部连接到数据库是 100% 有效的,例如在部署中使用 sidecar 或在通过此帐户进行身份验证时在本地使用它。

不可能存在任何防火墙问题,因为这是本地主机并连接到我们的 VPC 内部的 GCP 后端。

我们在任何地方都找不到显示 Cloud SQL 代理尝试连接到数据库的日志,也没有任何关于它是否成功以及原因的提示或线索。我们需要日志。没有足够的日志。那么问题来了,除了容器日志之外,还有哪些日志呢?

这是错误:

2023-09-28 20:30:41 调试 rasa.core.tracker_store - 尝试通过“postgresql://user1:***@localhost/rasa-oss-001”连接到数据库。

上面的帐户有所有者,可以在数据库中构建表,但这不应该相关。

2023-09-28 20:30:41 错误 rasa.core.tracker_store - 无法创建表:(psycopg2.OperationalError)连接到“localhost”(127.0.0.1)的服务器,端口 5432 失败:连接被拒绝

在日志资源管理器中打开

{
insertId: "6515e27100075a076642487a"
labels: {1}
logName: "projects/bdt-eng-play/logs/run.googleapis.com%2Fstderr"
receiveTimestamp: "2023-09-28T20:30:41.492307554Z"
resource: {2}
textPayload: "2023-09-28 20:30:41 ERROR    rasa.core.tracker_store  - Could not create tables: (psycopg2.OperationalError) connection to server at "localhost" (127.0.0.1), port 5432 failed: Connection refused"
timestamp: "2023-09-28T20:30:41.481799Z"
}

对我来说,上述错误显然意味着 Cloud SQL 代理部分不起作用。它要么没有将该本地端口重定向到实例,要么没有成功连接到实例。这对任何应用程序都不起作用,因此上述日志可以适用于任何东西。

google-cloud-sql google-cloud-run cloud-sql-proxy
1个回答
1
投票

当您通过命令行通过

--add-cloudsql-instances
标志或通过 UI 部署具有“Cloud SQL 连接”的 Cloud Run 服务时,如下所示:

它的作用是通过 Unix 套接字在后台为您部署 Cloud SQL 代理,Cloud SQL 代理的 Unix 套接字部署仅适用于公共 IP Cloud SQL 连接。有一篇很好的博客文章概述了这个限制。

对于私有 IP Cloud SQL 连接(例如您的),有两个选项:

第一个选项有一个示例,展示了使用新的多容器功能将 Cloud SQL 代理与 Cloud Run 应用程序一起部署。 (该示例适用于 Ruby,但 YAML 是相同的)。

第二个选项是删除 Cloud SQL 代理并直接使用 TCP 连接到您的 Cloud SQL 实例。由于自动 mTLS 连接的优势,我们主要建议将 Cloud SQL 代理用于公共 IP Cloud SQL 连接。代理生成客户端证书并使用它建立安全的 SSL 连接。但是,客户端证书并不是安全连接所必需的。如果您使用私有 IP,那么您的连接是通过私有 VPC 网络进行的,在这种情况下,对客户端证书的要求并不那么突出,并且设置

ssl="require"
仍将建立安全的 SSL 连接(这可能足以满足您的使用案例)

import sqlalchemy
from sqlalchemy import event

engine = sqlalchemy.create_engine(
    # Equivalent URL:
    # postgresql+psycopg2://<user>:<password>@<host>:5432/<db_name>
    sqlalchemy.engine.url.URL.create(
        drivername="postgresql+psycopg2",
        username="my-user",
        password="my-password",
        host=ip_address,  # Cloud SQL instance IP address (or localhost for local SQL)
        port=5432,
        database=db_name,  # "my-database-name"
    ),
    connect_args={"sslmode": "require"},
)

# use connection from connection pool to query Cloud SQL database
with engine.connect() as conn:
    time = conn.execute(sqlalchemy.text("SELECT NOW()")).fetchone()
    conn.commit()
    print("Current time is ", time[0])

如果您使用自动 IAM 身份验证,您甚至可以在不使用代理的情况下进行连接:

import sqlalchemy
from sqlalchemy import event

import google.auth
from google.auth.credentials import Credentials
from google.auth.transport.requests import Request

# initialize Google Auth creds
creds, _ = google.auth.default(
    scopes=["https://www.googleapis.com/auth/sqlservice.admin"]
)

def get_authentication_token(credentials: Credentials) -> str:
    """Get OAuth2 access token to be used for IAM database authentication"""
    # refresh credentials if expired
    if not credentials.valid:
        request = Request()
        credentials.refresh(request)
    return credentials.token

engine = sqlalchemy.create_engine(
    # Equivalent URL:
    # postgresql+psycopg2://<user>:empty@<host>:5432/<db_name>
    sqlalchemy.engine.url.URL.create(
        drivername="postgresql+psycopg2",
        username=user,  # IAM db user, e.g. [email protected]
        password="",  # placeholder to be replaced with OAuth2 token
        host=ip_address,  # Cloud SQL instance IP address
        port=5432,
        database=db_name,  # "my-database-name"
    ),
    connect_args={"sslmode": "require"},
)

# set 'do_connect' event listener to replace password with OAuth2 token
@event.listens_for(engine, "do_connect")
def auto_iam_authentication(dialect, conn_rec, cargs, cparams) -> None:
    cparams["password"] = get_authentication_token(creds)

需要注意的一件事是,零信任环境不喜欢依赖客户做正确的事情。例如,Cloud SQL 有一个配置选项“仅允许 SSL 连接”,该选项强制连接使用客户端证书进行 mTLS 连接才能成功。虽然

ssl=require
强制加密连接,但如果您需要 mTLS 连接,则可能还需要下载和管理客户端证书。在这种情况下,使用代理的第一个选项可能是更好的选择。

© www.soinside.com 2019 - 2024. All rights reserved.