从 Google App Engine 访问 Google Cloud SQL

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

我已经设置了一个运行 Cloud SQL 数据库 (MySQL) 的实例,我想从我在同一个项目中通过 GAE (python/flask) 部署的应用程序访问它。我已经通过(全部在我的本地机器上)测试了这个

  1. 白名单我自己的IP,
  2. 使用环境变量设置 Cloud SQL 数据库凭证,
  3. 使用 gunicorn 运行应用程序。

以上作品。但是,当我尝试通过部署到 GAE 来运行应用程序时,出现访问错误:

sqlalchemy.exc.OperationalError: (MySQLdb.OperationalError) (2003, "Can't connect to MySQL server on '[sql instance ip]' (110)")

我已经设置了我的 App Engine 默认服务帐户,角色为“Editor”(默认)和“Cloud SQL Client”(我认为基于权限是多余的......)。我启用了 Cloud SQL Admin API。

我的猜测是,这是我的一些微不足道的错误配置,因为我通常是 GCP 的新手。

部署/加载应用程序 url 后的错误日志:

2023-04-30 16:16:41 default[20230430t103558]  "GET / HTTP/1.1" 500
2023-04-30 16:16:42 default[20230430t103558]  [2023-04-30 16:16:42 +0000] [12] [INFO] Starting gunicorn 20.1.0
2023-04-30 16:16:42 default[20230430t103558]  [2023-04-30 16:16:42 +0000] [12] [INFO] Listening at: http://0.0.0.0:8081 (12)
2023-04-30 16:16:42 default[20230430t103558]  [2023-04-30 16:16:42 +0000] [12] [INFO] Using worker: sync
2023-04-30 16:16:42 default[20230430t103558]  [2023-04-30 16:16:42 +0000] [15] [INFO] Booting worker with pid: 15
2023-04-30 16:16:46 default[20230430t103558]  Server initialized for threading.
2023-04-30 16:18:53 default[20230430t103558]  [2023-04-30 16:18:53,864] ERROR in app: Exception on / [GET]
2023-04-30 16:18:53 default[20230430t103558]  Traceback (most recent call last):    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 145, in __init__      self._dbapi_connection = engine.raw_connection()    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 3288, in raw_connection      return self.pool.connect()    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/base.py", line 452, in connect      return _ConnectionFairy._checkout(self)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/base.py", line 1268, in _checkout      fairy = _ConnectionRecord.checkout(pool)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/base.py", line 716, in checkout      rec = pool._do_get()    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/impl.py", line 169, in _do_get      self._dec_overflow()    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py", line 147, in __exit__      raise exc_value.with_traceback(exc_tb)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/impl.py", line 166, in _do_get      return self._create_connection()    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/base.py", line 393, in _create_connection      return _ConnectionRecord(self)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/base.py", line 678, in __init__      self.__connect()    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/base.py", line 903, in __connect      pool.logger.debug("Error on connect(): %s", e)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py", line 147, in __exit__      raise exc_value.with_traceback(exc_tb)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/pool/base.py", line 898, in __connect      self.dbapi_connection = connection = pool._invoke_creator(self)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/engine/create.py", line 637, in connect      return dialect.connect(*cargs, **cparams)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 616, in connect      return self.loaded_dbapi.connect(*cargs, **cparams)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/MySQLdb/__init__.py", line 123, in Connect      return Connection(*args, **kwargs)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/MySQLdb/connections.py", line 185, in __init__      super().__init__(*args, **kwargs2)  MySQLdb.OperationalError: (2003, "Can't connect to MySQL server on '[sql instance ip]' (110)")
2023-04-30 16:18:53 default[20230430t103558]  The above exception was the direct cause of the following exception:
2023-04-30 16:18:53 default[20230430t103558]  Traceback (most recent call last):    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/flask/app.py", line 2462, in wsgi_app      ctx.push()    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/flask/ctx.py", line 375, in push      self.session = session_interface.open_session(self.app, self.request)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/flask_session/sessions.py", line 533, in open_session      saved_session = self.sql_session_model.query.filter_by(    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 2743, in first      return self.limit(1)._iter().first()  # type: ignore    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/orm/query.py", line 2842, in _iter      result: Union[ScalarResult[_T], Result[_T]] = self.session.execute(    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2231, in execute      return self._execute_internal(    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 2116, in _execute_internal      conn = self._connection_for_bind(bind)    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1983, in _connection_for_bind      return trans._connection_for_bind(engine, execution_options)    File "<string>", line 2, in _connection_for_bind    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go
2023-04-30 16:18:53 default[20230430t103558]      ret_value = fn(self, *arg, **kw)
2023-04-30 16:18:53 default[20230430t103558]    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1110, in _connection_for_bind
[... many lines of traceback ...]
2023-04-30 16:18:53 default[20230430t103558]    File "/layers/google.python.pip/pip/lib/python3.8/site-packages/MySQLdb/connections.py", line 185, in __init__
2023-04-30 16:18:53 default[20230430t103558]      super().__init__(*args, **kwargs2)
2023-04-30 16:18:53 default[20230430t103558]  sqlalchemy.exc.OperationalError: (MySQLdb.OperationalError) (2003, "Can't connect to MySQL server on '[sql instance ip]' (110)")
2023-04-30 16:18:53 default[20230430t103558]  (Background on this error at: https://sqlalche.me/e/20/e3q8)

这是我的 main.py 的相关部分:

USERNAME = os.environ.get('CLOUD_SQL_USERNAME')
PASSWORD = os.environ.get('CLOUD_SQL_PASSWORD')
PUBLIC_IP_ADDRESS = os.environ.get('CLOUD_SQL_PUBLIC_IP_ADDRESS')
DBNAME = os.environ.get('CLOUD_SQL_DATABASE_NAME')
CONN_NAME = os.environ.get('CLOUD_SQL_CONN_NAME')
if USERNAME and PASSWORD and PUBLIC_IP_ADDRESS and DBNAME and CONN_NAME:
    database_uri = "mysql+mysqldb://" \
                   f"{USERNAME}:{PASSWORD}@{PUBLIC_IP_ADDRESS}/{DBNAME}" \
                   f"?unix_socket=/cloudsql/{CONN_NAME}"
else:
    database_uri = 'sqlite:///mydb.sqlite3'

app = Flask(__name__)
app.config['SECRET_KEY'] = 'very_secret'
app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

更新:

我想分享似乎可以解决我的初始连接问题的更改,同时仍然如上所述使用 Flask-SQLAlchemy,因为到目前为止我还没有在示例中找到这种方法。也许它对像我这样的新手有用。大多数相关信息都在一些有用的人指给我的教程中。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from google.cloud.sql.connector import Connector, IPTypes
import pymysql

ip_type = IPTypes.PUBLIC
connector = Connector(ip_type)

USERNAME = os.environ.get('CLOUD_SQL_USERNAME')
PASSWORD = os.environ.get('CLOUD_SQL_PASSWORD')
DBNAME = os.environ.get('CLOUD_SQL_DATABASE_NAME')
CONN_NAME = os.environ.get('CLOUD_SQL_CONN_NAME')

def get_engine_options():
    if USERNAME and PASSWORD and DBNAME and CONN_NAME:
        def getconn() -> pymysql.connections.Connection:
            conn: pymysql.connections.Connection = connector.connect(
                CONN_NAME,
                "pymysql",
                user=USERNAME,
                password=PASSWORD,
                db=DBNAME,
            )
            return conn
        return {'creator' : getconn}
    return None

database_uri = "mysql+pymysql://" if get_engine_options() is not None else "sqlite:///mydb.sqlite3"

app = Flask(__name__)
app.config['SECRET_KEY'] = 'very_secret'
app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app, engine_options=get_engine_options())
google-app-engine google-cloud-platform google-cloud-sql
1个回答
1
投票

这取决于您使用的 GAE 类型 - GAE Standard 或 GAE Flexible。尝试确定这一点,然后以下链接应该可以帮助您完成任务。

GAE 标准:https://cloud.google.com/sql/docs/mysql/connect-app-engine-standard

GAE 灵活:https://cloud.google.com/sql/docs/mysql/connect-app-engine-flexible

常见问题

  1. GAE 服务没有足够的权限访问 sql
  2. 网络 - 取决于您使用的 GAE 类型。
© www.soinside.com 2019 - 2024. All rights reserved.