【问题标题】:psycopg2.OperationalError: could not connect to server when called from Google Cloud Runpsycopg2.OperationalError:从 Google Cloud Run 调用时无法连接到服务器
【发布时间】:2021-10-21 00:03:20
【问题描述】:

我有一个 (Linux) Docker 映像,当我在本地计算机上将它作为容器运行时,它成功连接到 Google 的 Cloud SQL。当我将该映像移动到 Google 的容器注册表并将其放入 Google Cloud Run API 时,我收到以下错误:

psycopg2.OperationalError: could not connect to server: Connection timed out Is the server running on host "xxx.xxx.xxx.xxx" and accepting TCP/IP connections on port 5432?
    at connect (/env/local/lib/python3.7/site-packages/psycopg2/__init__.py:130)
    ...

我假设这是因为我将 Cloud SQL 实例配置为具有“授权网络”列表的“公共 IP”。见文档here

问题在于,根据我部署 Cloud Run API 的方式/时间,IP 地址可能会随着时间而改变。如何授权从属于我的项目(而非其他项目)的其他 Google Cloud 服务(特别是 Google Cloud Run)访问 Cloud SQL 实例?

更新

根据 John Hanley 的评论(请参阅此 URL),我可以通过将以下内容添加到我的 gcloud beta run deploy 命令来更新我的部署命令:

--add-cloudsql-instances=[CLOUD_SQL_CONNECTION_NAME] --service-account=service-account@my-project.iam.gserviceaccount.com

SQL 连接仍然无法正常工作。我想我已经完成了这个网页上我能想到的所有事情,除了重写我的 SQL 连接 python 代码。是否需要以本页所示的 unix-socket 格式编写连接?

我已经编写了使用 SSL 客户端证书的代码。这是我用于连接的类中的 2 种方法:

def get_db_connection(self):
    file_map = {os.path.abspath(f'{TEMP_PATH}/sslrootcert.pem'): self.sslrootcert,
                os.path.abspath(f'{TEMP_PATH}/sslcert.pem'): self.sslcert,
                os.path.abspath(f'{TEMP_PATH}/sslkey.pem'): self.sslkey}
    rev_map = {v: k for k, v in file_map.items()}
    db = None
    try:
        for path, obj in file_map.items():
            with open(path, 'w') as f:
                if isinstance(obj, bytes):
                    f.write(obj.decode('utf-8'))
                else:
                    f.write(str(obj))
            os.chmod(path, stat.S_IRWXU)

        db = psycopg2.connect(database=self.database, user=self.user, password=self.password, host=self.host,
                              port=self.port, sslmode=self.sslmode, sslrootcert=rev_map.get(self.sslrootcert),
                              sslcert=rev_map.get(self.sslcert), sslkey=rev_map.get(self.sslkey))
    finally:
        for path in file_map.keys():
            if os.path.isfile(path):
                os.remove(path)
    return db

@contextlib.contextmanager
def db_connect(self):
    db = self.get_db_connection()
    cur = db.cursor()
    try:
        yield (db, cur)
    finally:
        db.close()

更新 2

我仍在努力尝试所有建议的方法,但我意识到我的 Cloud SQL 数据库设置为“仅允许 SSL 连接”:

这可能是连接在 Cloud Run 中运行时失败但在我的本地计算机上成功(在 Docker 容器中或在 Docker 容器中)的原因吗?如果是这样,应如何更改 Cloud Run 设置以解决此问题?

最终更新

使用基于 Unix Socket 的连接(来自here)允许连接开始工作。为什么从 Google Cloud Run 到 Google Cloud SQL 的连接需要 Unix Socket 连接?有没有办法让它与我上面的 SSL 证书方法/代码一起使用?

【问题讨论】:

  • Google Cloud Run 提供 Cloud SQL Auth Proxy 支持。这在带有示例的文档中进行了介绍。 cloud.google.com/sql/docs/mysql/connect-run
  • John Hanley,感谢您将我指向此文档。我在谷歌搜索这个问题时没有找到这个。它帮助我解决了我在上述问题中更新的 2 个问题。

标签: ssl psycopg2 google-cloud-sql google-cloud-run unix-socket


【解决方案1】:

我使用了这个Google documentation,这也是 John Hanley 建议的,其中提到了使用 unix 套接字将 Cloud run 连接到 SQL 的分步过程。卡住的时候也参考了这个youtube video,虽然视频是用php的,但我觉得可能对你还是有用的。我使用文档中提供的代码进行连接,即与 unix 套接字连接,并且能够成功部署它。

我使用以下命令进行部署:

gcloud run deploy --image [image-name] --platform managed --add-cloudsql-instances [CLOUD_SQL_CONNECTION_NAME] --set-env-vars CLOUD_SQL_CONNECTION_NAME=[CLOUD_SQL_CONNECTION_NAME]

我还建议验证您的入口点,检查它是否是您要部署的正确映像。

验证 Cloud Run 是否具有this 中定义的关联权限。

此外,Google 的建议是使用private IP 而不是公共 IP,因为您在内部连接 ​​GCP 产品,与公共 IP 相比,延迟会更低。

【讨论】:

    猜你喜欢
    • 2018-10-12
    • 1970-01-01
    • 2023-03-14
    • 2013-07-12
    • 2013-06-15
    • 2020-09-25
    • 2021-06-18
    • 2012-10-10
    • 2020-03-22
    相关资源
    最近更新 更多