簡體   English   中英

如何使用 Python 運行時從 Google Cloud Function 訪問非 Google MySQL 服務器數據庫(無 Cloud SQL!)

[英]How to access a non-Google MySQL server database (no Cloud SQL!) from Google Cloud Function in Python runtime using SQLAlchemy

我嘗試從 Python 運行時中的 Google Cloud Function 連接到非 Google Cloud 托管的外部 MySQL 服務器數據庫。

我的“requirements.txt”:

# Function dependencies, for example:
# package>=version
SQLAlchemy>=1.4.2
PyMySQL==1.0.2

雲Function核心代碼:


from os import environ 
import sqlalchemy

db_user = environ["DB_USER"]
db_pass = environ["DB_PASS"]
db_name = environ["DB_NAME"]
db_host = environ["DB_HOST"]
db_port = environ["DB_PORT"] # if not used, default 3306 anyway

db_address = f"""mysql+pymysql://{db_user}:{db_pass}@{db_host}/{db_name}?charset=utf8&use_unicode=1"""
db_engine = sqlalchemy.create_engine(db_address)

當我在“測試”選項卡中測試雲 Function 時,按下Test the function ,我收到錯誤:

 for termination reason. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging Details: 500 Internal Server Error: The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application. ```

在日志中:

在此處輸入圖像描述

或作為可搜索的文本:

Debug2022-01-07T14:36:29.221892880ZMYCLOUDFUNCTIONdvaw7xewhjqj Function execution started Default2022-01-07T14:36:29.529ZMYCLOUDFUNCTIONdvaw7xewhjqj OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k Debug2022-01-07T14:36:30.964665907ZMYCLOUDFUNCTIONdvaw7xewhjqj Function execution took 1743 ms, finished with status code: 200 Debug2022-01-07T14:36:50.088620704ZMYCLOUDFUNCTIONdvawxkmbid1w Function execution started Function execution started Default2022-01-07T14:36:50.340ZMYCLOUDFUNCTIONdvawxkmbid1w 2022-01-07 14:36:50,267 [ERROR] :/[POST] 2022-01-07 14:36:50,267 [ERROR] 上的異常:/[POST] 上的異常 Error2022-01-07T14:36:50.341ZMYCLOUDFUNCTIONdvawxkmbid1w Traceback(最近一次調用最后一次):文件“/layers/ google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 2447 行,在 wsgi_app 響應 = self.full_disp atch_request() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 1952 行,full_dispatch_request rv = self.handle_user_exception(e) 文件“/layers /google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 1821 行,在 handle_user_exception reraise(exc_type, exc_value, tb) 文件“/layers/google.pythonp. pip/lib/python3.9/site-packages/flask/_compat.py”,第 39 行,在 reraise raise 值文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask /app.py”,第 1950 行,在 full_dispatch_request rv = self.dispatch_request() 文件中“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 1936 行,在 dispatch_request 返回 self.view_functionsrule.endpoint 文件“ /layers/google.python.pip/pip/lib/python3.9/site-packages/functions_framework/init .py”,第 99 行,在 vi ew_func 返回函數(request._get_current_object()) 文件“/workspace/main.py”,第 139 行,在 get_csv_in_tmp_and_move_to_gs 引擎 = sqlalchemy.create_engine(db_address) 文件“”,第 2 行,在 create_engine 文件“/layers/google.Z2FCB677BDD7556 .pip/pip/lib/python3.9/site-packages/sqlalchemy/util/deprecations.py”,第 309 行,警告 Traceback(最近一次調用最后一次):文件“/layers/google.python.pip/pip/ lib/python3.9/site-packages/flask/app.py”,第 2447 行,在 wsgi_app 響應 = self.full_dispatch_request() 文件中“/layers/google.python.pip/pip/lib/python3.9/site- packages/flask/app.py”,第 1952 行,在 full_dispatch_request rv = self.handle_user_exception(e) 文件中“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py ",第 1821 行,在 handle_user_exception reraise(exc_type, exc_value, tb) 文件中 "/layers/google.python.pip/pip/li b/python3.9/site-packages/flask/_compat.py”,第 39 行,在 reraise raise 值文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app .py”,第 1950 行,full_dispatch_request rv = self.dispatch_request() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 1936 行,在dispatch_request return self.view_functionsrule.endpoint File " /layers/google.python.pip/pip/lib/python3.9/site-packages/functions_framework/init .py",第 99 行,在 view_func 返回函數(request._get_current_object() ) 文件“/workspace/main.py”,第 139 行,在 get_csv_in_tmp_and_move_to_gs 引擎 = sqlalchemy.create_engine(db_address) 文件“”,第 2 行,在 create_engine 文件中“/layers/google.Z23EEEB4347BDD26BFC6B7EE9A3B755DD.pip/p/iplib/python3DD.pip。 9/site-packages/sqlalchemy/util/deprecations.py”,第 309 行,警告 Default2022-01-07T14:36:50.341ZMYCLOUDFUNCTIONdvawxkmbid1w r eturn fn(*args, **kwargs) return fn(*args, **kwargs) Default2022-01-07T14:36:50.341ZMYCLOUDFUNCTIONdvawxkmbid1w 文件 "/layers/google.python.pip/pip/lib/python3.9/site -packages/sqlalchemy/engine/create.py”,第 560 行,在 create_engine 文件中“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/engine/create.py”,行560,在 create_engine Default2022-01-07T14:36:50.341ZMYCLOUDFUNCTIONdvawxkmbid1w dbapi = dialect_cls.dbapi(**dbapi_args) dbapi = dialect_cls.dbapi(**dbapi_args) Default2022-01-07T14:36:50.341ZMYCLOUDFUNCTIONdvawxkmbid1w"/UNCTIONdvawxkmbid1w .python.pip/pip/lib/python3.9/site-packages/sqlalchemy/dialects/mysql/mysqldb.py”,第 163 行,在 dbapi 文件“/layers/google.python.pip/pip/lib/python3. 9/site-packages/sqlalchemy/dialects/mysql/mysqldb.py",第 163 行,在 dbapi Default2022-01-07T14:36:50.341ZMYCLOUDFUNCTIONdvawxkmbid1w return import ("MySQLdb") return import ("MySQLdb") Debug2022-01-07T14:36:50.342294068ZMYCLOUDFUNCTIONdvawxkmbid1w Function execution took 254 ms, finished with status: 'crash' Function execution took 254 ms, finished with status: 'crash' ```

當我對連接生命周期使用 with 語句時,我得到的內容略有不同,但問題是一樣的,它無法連接到數據庫:

回溯(最近一次通話最后):文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 2447 行,在 wsgi_app 響應 = self.full_dispatch_request()文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 1952 行,full_dispatch_request rv = self.handle_user_exception(e) 文件“/layers/google。 python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 1821 行,在 handle_user_exception reraise(exc_type, exc_value, tb) 文件“/layers/google.python.pip/ /python3.9/site-packages/flask/_compat.py”,第 39 行,在 reraise raise 值文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app. py”,第 1950 行,full_dispatch_request rv = self.dispatch_request() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py”,第 1936 行,在 dispa tch_request 返回 self.view_functionsrule.endpoint 文件“ /layers/google.python.pip/pip/lib/python3.9/site-packages/functions_framework/init .py”,第 99 行,在 view_func 返回函數(request._get_current_object() ) 文件“/workspace/main.py”,第 177 行,在 get_csv_in_tmp_and_move_to_gs 連接 = engine.connect() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/engine/ base.py”,第 3204 行,在連接中返回 self._connection_cls(self,close_with_result=close_with_result) 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/engine/base. py”,第 96 行,在init else engine.raw_connection() 文件中“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/engine/base.py”,第 3283 行,在raw_connection 返回 self._wrap_pool_connect(self.pool.connect, _connection) 文件“/layers/google.python.pip/pip/ lib/python3.9/site-packages/sqlalchemy/engine/base.py”,第 3253 行,在 _wrap_pool_connect 連接中。 handle_dbapi_exception_noconnection(文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/engine/base.py”,第 2100 行,在handle_dbapi_exception_noconnection util.raise (文件“/layers/google. python.pip/pip/lib/python3.9/site-packages/sqlalchemy/util/compat.py”,第 207 行,在引發異常文件“/layers/google.python.pip/pip/lib/python3.9 /site-packages/sqlalchemy/engine/base.py”,第 3250 行,在 _wrap_pool_connect 返回 fn() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/pool/ base.py”,第 310 行,在連接中返回 _ConnectionFairy._checkout(self) 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/pool/base.py”,行868,在_checkout仙女=_ConnectionRecord.checkout(pool)文件中“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalch emy/pool/base.py”,第 476 行,在結帳時 rec = pool._do_get() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/pool/impl. py",第 146 行,在do_get self. dec_overflow() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py”,第 70 行,退出compat.raise (文件“/layers/google .python.pip/pip/lib/python3.9/site-packages/sqlalchemy/util/compat.py”,第 207 行,在引發異常文件“/layers/google.python.pip/pip/lib/python3. 9/site-packages/sqlalchemy/pool/impl.py”,第 143 行,在 _do_get 返回 self._create_connection() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy /pool/base.py”,第 256 行,在 _create_connection 返回 _ConnectionRecord(self) 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/pool/base.py”,第 371 行,在init self.__connect() 文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/pool/base.py”中,第 666 行,在連接 pool.logger .debug("錯誤連接():%s”,e)文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py”,第70行,退出compat.raise (文件“/layers/google.python.pip/pip/lib/python3.9/site-packages/sqlalchemy/util/compat.py”,第 207 行,在引發異常文件“/layers/google.python.pip /pip/lib/python3.9/site-packages/sqlalchemy/pool/base.py”,第 661 行,在 __connect self.dbapi_connection = connection = pool._invoke_creator(self) 文件“/layers/google.python.pip/ pip/lib/python3.9/site-packages/sqlalchemy/engine/create.py”,第 590 行,在連接中返回 dialect.connect(*cargs, **cparams) 文件“/layers/google.python.pip/pip /lib/python3.9/site-packages/sqlalchemy/engine/default.py”,第 597 行,在連接中返回 self.dbapi.connect(*cargs, **cparams) 文件“/layers/google.python.pip/ pip/lib/python3.9/site-package s/pymysql/connections.py”,第 353 行,在init self.connect() 文件中“/layers/google.python.pip/pip/lib/python3.9/site-packages/pymysql/connections.py”,行664,在連接中引發 exc sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'MY_SERVER_ADDRESS' (timed out)T23:032:-251-292") 默認值 2032:-251-292 Z MYCLOUDFUNCTIONearoz5s8jozu(此錯誤的背景: https://sqlalche.me/e/14/e3q8 )(此錯誤的背景: https://sqlalche.me/e/14/e3

我在本地機器和本地 Docker 容器中測試了相同的代碼和設置,兩者都可以使用相同的連接字符串(db_url)進行連接。

問題

如何連接到非 Google MySQL 服務器?

go 的一些方法也許

主意

這只是一個權限問題,例如,我應該為我的用戶角色添加一些權限嗎?

主意

或者可能是 Google Cloud Functions 不允許對 Google 世界之外的服務器進行任何訪問?

主意

如果只有 Cloud SQL 服務器被接受為 Cloud Functions 中的源(可能是這種情況,因為我只找到了適用於這種情況的指南,例如 Google 的官方指南: Connecting from Cloud Functions to Cloud SQL如何在 44 中使用 ZDC6784A01AFAFA2Z 的示例)谷歌雲 Function ),我可以以某種方式使外部服務器成為谷歌接受的雲 SQL 服務器而不實際上傳到那里,還是有任何其他解決方法?

主意

The connection example from Cloud Functions to Google Cloud SQL (MySQL) asks you to activate the Cloud SQL API as a first step and then uses sockets in the connection string:

# Remember - storing secrets in plaintext is potentially unsafe. Consider using
# something like https://cloud.google.com/secret-manager/docs/overview to help keep
# secrets secret.
db_user = os.environ["DB_USER"]
db_pass = os.environ["DB_PASS"]
db_name = os.environ["DB_NAME"]
db_socket_dir = os.environ.get("DB_SOCKET_DIR", "/cloudsql")
instance_connection_name = os.environ["INSTANCE_CONNECTION_NAME"]

pool = sqlalchemy.create_engine(
    # Equivalent URL:
    # mysql+pymysql://<db_user>:<db_pass>@/<db_name>?unix_socket=<socket_path>/<cloud_sql_instance_name>
    sqlalchemy.engine.url.URL.create(
        drivername="mysql+pymysql",
        username=db_user,  # e.g. "my-database-user"
        password=db_pass,  # e.g. "my-database-password"
        database=db_name,  # e.g. "my-database-name"
        query={
            "unix_socket": "{}/{}".format(
                db_socket_dir,  # e.g. "/cloudsql"
                instance_connection_name)  # i.e "<PROJECT-NAME>:<INSTANCE-REGION>:<INSTANCE-NAME>"
        }
    ),
    **db_config
)

Is it possible that without such API and without sockets to secure the connection, the SQL query cannot be fired to a MySQL server that is not a Google Cloud SQL server?

主意

還是我可能必須更改為 Google Cloud Run才能有機會在那里運行我自己的容器? 請參閱使用谷歌雲功能的 Python flask 應用程序 似乎在 Cloud Functions 中根本不建議使用大文件大小,這肯定是由 csv 中的 SQL 查詢結果引起的,請參閱將二進制數據從 Google Cloud Storage 流式傳輸到 Cloud Z86408593C34AF727FDD90DF932F8B5

...我不建議使用 Cloud Functions 來處理大文件。 我寧願推薦其他無服務器選項,例如 App Engine 或 Cloud Run。 處理大文件可能需要一段時間,並且 Cloud Functions 會在一定時間后超時。

主意

下一條評論提到了 GCSFS(Python 模塊),它可能不提供查詢外部數據庫:

我確實設法使用 GCSFS 讓我能夠在雲存儲和 stream 二進制文件中打開文件,就好像它們是本地的一樣。

如果數據庫在 VM 上並且在您的 VPC 中,您可以創建一個VPC 連接器並將其附加到您的雲 Function 以訪問它。

如果它部署在其他地方,

  • 要么數據庫有一個公共的 IP,Cloud Functions 可以直接訪問它。
  • 或者數據庫有一個私有 IP,您需要使用您的數據庫在您的 VPC 和私有外部網絡之間創建一個 VPN。 再次向 Cloud Functions 添加一個無服務器 VPC 連接器,以允許它連接到您的 VPC 和 VPN 以訪問數據庫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM