我已经设置了一个运行 Cloud SQL 数据库 (MySQL) 的实例,我想从我在同一个项目中通过 GAE (python/flask) 部署的应用程序访问它。我已经通过(全部在我的本地机器上)测试了这个
以上作品。但是,当我尝试通过部署到 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())
这取决于您使用的 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
常见问题