如何从 Cloud Functions 连接 Google Cloud SQL?
Posted
技术标签:
【中文标题】如何从 Cloud Functions 连接 Google Cloud SQL?【英文标题】:How to connect Google Cloud SQL from Cloud Functions? 【发布时间】:2017-08-18 18:50:54 【问题描述】:我正在尝试使用 Cloud Functions for Firebase 构建一个与 Google Cloud SQL (PostgreSQL) 实例对话的 API。
我正在使用 HTTP(S) 触发器。
当我将桌面的 IP 地址列入白名单时,我可以从本地计算机使用函数的 node.js 代码连接到 Cloud SQL。但是当我部署时,我无法连接,我无法确定Firebase Function服务器的HOST IP地址,以加入白名单。
您如何通过 Cloud Functions for Firebase 与 Google Cloud SQL 对话?
谢谢!
// Code Sample, of what's working on Localhost.
var functions = require('firebase-functions');
var pg = require('pg');
var pgConfig =
user: functions.config().pg.user,
database: functions.config().pg.database,
password: functions.config().pg.password,
host: functions.config().pg.host
exports.helloSql = functions.https.onRequest((request, response) =>
console.log('connecting...');
try
client.connect(function(err)
if (err) throw err;
console.log('connection success');
console.log('querying...');
client.query('SELECT * FROM guestbook;', function(err, result)
if (err) throw err;
console.log('querying success.');
console.log('Results: ', result);
console.log('Ending...');
client.end(function(err)
if (err) throw err;
console.log('End success.');
response.send(result);
);
);
);
catch(er)
console.error(er.stack)
response.status(500).send(er);
);
【问题讨论】:
【参考方案1】:我在#36388165的进一步讨论中找到了答案。
免责声明:这似乎没有正式宣布,所以以后可能会改变。我也只在mysql中测试。但是这个解决方案的性质,我认为应该和 pg 模块一样工作(似乎accept domain socket path 作为主机参数)
EDIT(2017/12/7):google 似乎提供了official early access,同样的方法仍然有效。EDIT(2018/07/04):似乎有人只是复制并粘贴我的示例代码并遇到麻烦。作为 googlesays,你应该使用连接池来避免 sql 连接泄漏。 (它会导致 ECONNREFUSE)所以我稍微更改了示例代码。 EDIT(2019/04/04):在下面的示例中,使用 $DBNAME 作为 spanner 实例名称令人困惑,我修改了示例。
在https://issuetracker.google.com/issues/36388165#comment44 google 的家伙说云函数实例可以通过特殊路径'/cloudsql/$PROJECT_ID:$REGION:$DBNAME' 中的域套接字与云 sql 对话。
我实际上可以从下面的云函数代码连接和操作云SQL。
const mysql = require('mysql');
const pool = mysql.createPool(
connectionLimit : 1,
socketPath: '/cloudsql/' + '$PROJECT_ID:$REGION:$SPANNER_INSTANCE_NAME',
user: '$USER',
password: '$PASS',
database: '$DATABASE'
);
exports.handler = function handler(req, res)
//using pool instead of creating connection with function call
pool.query(`SELECT * FROM table where id = ?`,
req.body.id, function (e, results)
//made reply here
);
;
我希望这对那些迫不及待地等待谷歌官方宣布的人有所帮助。
【讨论】:
这确实有效。套接字路径与实例属性中的“实例连接名称”相同。 这是否适用于第一代云 SQL 服务器?我注意到实例连接名称没有我的第一代服务器的区域。 @rudolph1024 感谢您的报告,但我很抱歉。也许这就是谷歌似乎还没有宣布它的原因。 @rudolph1024 仅供参考,如果您仍然有兴趣从云功能连接第一代云 SQL,官方文档 (docs.google.com/document/d/…) 表示可以使用实例连接名称,例如“<YOUR_PROJECT_ID>@appspot.gserviceaccount.com
添加到您的 IAM 并提供 Cloud SQL 客户端角色。【参考方案2】:
新答案:
查看其他答案,现已正式支持。 https://cloud.google.com/functions/docs/sql
旧答案:
目前不可能。然而,这是问题跟踪器#36388165 上的功能请求:
目前无法从 Cloud Functions 连接到 Cloud SQL 支持,因为 UNIX 套接字不存在(导致 ENOENT)和 没有定义的 IP 范围可列入白名单(导致 ETIMEDOUT)。一 可能性是将 Cloud SQL 实例中的 0.0.0.0/0 列入白名单,但 出于安全原因,不建议这样做。
如果这对您来说是一项重要功能,我建议您访问 issuetracker 并为功能请求加注星标以帮助它获得普及。
【讨论】:
目前可以从 Cloud Functions 轻松连接到 Cloud SQL。也有官方指南。检查其他答案。 请注意,我的回答来自 2017 年,因此我认为没有必要对其进行否决。我会更新它以反映它不再相关。 如果您的云功能使用 Java 并且您正在关注答案中链接的 GCP 文档,那么 GCP github 中的以下存储库也很有用:github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory【参考方案3】:在GCP > SQL > Instances 页面上查找您的数据库区域和实例名称:
通过运行将您的数据库密码保存到Firebase environment:
$ firebase functions:config:set \
db.user="<username>" \
db.password="<password>" \
db.database="<database>"
那么……
db.js
const Pool = require('pg');
const config = require('firebase-functions');
const project = process.env.GCP_PROJECT;
const region = 'europe-west1';
const instance = 'db';
module.exports = new Pool(
max: 1,
host: `/cloudsql/$project:$region:$instance`,
...config().db
);
someFunction.js
const https = require('firebase-functions');
const db = require('./db');
module.exports = https.onRequest((req, res) =>
db
.query('SELECT version()')
.then(( rows: [ version ]) =>
res.send(version);
));
另见 https://***.com/a/48825037/82686(通过 Babel 使用现代 javascript 语法)
【讨论】:
【参考方案4】:现在有官方文档,但截至 2018 年 7 月仍处于测试阶段
https://cloud.google.com/functions/docs/sql
【讨论】:
【参考方案5】:使用 TCP 和 UNIX 域套接字 2020 从 GOOGLE 云功能连接到云 SQL
1.新建项目
gcloud projects create gcf-to-sql
gcloud config set project gcf-to-sql
gcloud projects describe gcf-to-sql
2.为您的项目启用计费:https://cloud.google.com/billing/docs/how-to/modify-project
3.设置计算项目信息元数据:
gcloud compute project-info describe --project gcf-to-sql
#Enable the Api, and you can check that default-region,google-compute-default-zone are not set. Set the metadata.
gcloud compute project-info add-metadata --metadata google-compute-default-region=europe-west2,google-compute-default-zone=europe-west2-b
4.启用服务网络API:
gcloud services list --available
gcloud services enable servicenetworking.googleapis.com
5.创建2个云sql实例,(一个带有内部ip,一个带有公共ip)-https://cloud.google.com/sql/docs/mysql/create-instance:
6.具有外部ip的Cloud Sql实例:
#Create the sql instance in the
gcloud --project=con-ae-to-sql beta sql instances create database-external --region=europe-west2
#Set the password for the "root@%" MySQL user:
gcloud sql users set-password root --host=% --instance database-external --password root
#Create a user
gcloud sql users create user_name --host=% --instance=database-external --password=user_password
#Create a database
gcloud sql databases create user_database --instance=database-external
gcloud sql databases list --instance=database-external
6.b 内部ip的云Sql实例:
i.#Create a private connection to Google so that the VM instances in the default VPC network can use private services access to reach Google services that support it.
gcloud compute addresses create google-managed-services-my-network --global --purpose=VPC_PEERING --prefix-length=16 --description="peering range for Google" --network=default --project=con-ae-to-sql
gcloud services vpc-peerings connect --service=servicenetworking.googleapis.com --ranges=google-managed-services-my-network --network=default --project=con-ae-to-sql
#Check whether the operation was successful.
gcloud services vpc-peerings operations describe --name=operations/pssn.dacc3510-ebc6-40bd-a07b-8c79c1f4fa9a
#Listing private connections
gcloud services vpc-peerings list --network=default --project=con-ae-to-sql
ii.Create the instance:
gcloud --project=con-ae-to-sql beta sql instances create database-ipinternal --network=default --no-assign-ip --region=europe-west2
#Set the password for the "root@%" MySQL user:
gcloud sql users set-password root --host=% --instance database-ipinternal --password root
#Create a user
gcloud sql users create user_name --host=% --instance=database-ipinternal --password=user_password
#Create a database
gcloud sql databases create user_database --instance=database-ipinternal
gcloud sql databases list --instance=database-ipinternal
gcloud sql instances list
gcloud sql instances describe database-external
gcloud sql instances describe database-ipinternal
#Remember the instances connectionName
好的,所以我们有两个 mysql 实例,我们将使用 Serverless Access 和 TCP 从 Google Cloud Functions 连接到 database-ipinternal,并使用 unix domain socket 从 Google Cloud Functions 连接到 database-external。
7.启用 Cloud SQL Admin API
gcloud services list --available
gcloud services enable sqladmin.googleapis.com
注意:默认情况下,Cloud Functions 不支持使用 TCP 连接到 Cloud SQL 实例。除非您已配置无服务器 VPC 访问,否则您的代码不应尝试使用 IP 地址(例如 127.0.0.1 或 172.17.0.1)访问实例。
8.a 确保为您的项目启用无服务器 VPC 访问 API:
gcloud services enable vpcaccess.googleapis.com
8.b 创建连接器:
gcloud compute networks vpc-access connectors create serverless-connector --network default --region europe-west2 --range 10.10.0.0/28
#Verify that your connector is in the READY state before using it
gcloud compute networks vpc-access connectors describe serverless-connector --region europe-west2
9.为您的云功能创建一个服务帐户。确保您的服务的服务帐户具有以下 IAM 角色:Cloud SQL 客户端,并且为了在内部 IP 上从 App Engine Standard 连接到 Cloud Sql,我们还需要角色 Compute Network User。
gcloud iam service-accounts create cloud-function-to-sql
gcloud projects add-iam-policy-binding gcf-to-sql --member serviceAccount:cloud-function-to-sql@gcf-to-sql.iam.gserviceaccount.com --role roles/cloudsql.client
gcloud projects add-iam-policy-binding gcf-to-sql --member serviceAccount:cloud-function-to-sql@gcf-to-sql.iam.gserviceaccount.com --role roles/compute.networkUser
现在我配置了设置
1.使用 Tcp 和 unix 域套接字从 Google Cloud Functions 连接到 Cloud Sql
cd app-engine-standard/
ls
#main.py requirements.txt
cat requirements.txt
sqlalchemy
pymysql
cat main.py
import pymysql
from sqlalchemy import create_engine
def gcf_to_sql(request):
engine_tcp = create_engine('mysql+pymysql://user_name:user_password@10.36.0.3:3306')
existing_databases_tcp = engine_tcp.execute("SHOW DATABASES;")
con_tcp = "Connecting from Google Cloud Functions to Cloud SQL using TCP: databases => " + str([d[0] for d in existing_databases_tcp]).strip('[]') + "\n"
engine_unix_socket = create_engine('mysql+pymysql://user_name:user_password@/user_database?unix_socket=/cloudsql/gcf-to-sql:europe-west2:database-external')
existing_databases_unix_socket = engine_unix_socket.execute("SHOW DATABASES;")
con_unix_socket = "Connecting from Google Cloud Function to Cloud SQL using Unix Sockets: tables in sys database: => " + str([d[0] for d in existing_databases_unix_socket]).strip('[]') + "\n"
return con_tcp + con_unix_socket
2.部署云功能:
gcloud beta functions deploy gcf_to_sql --runtime python37 --region europe-west2 --vpc-connector projects/gcf-to-sql/locations/europe-west2/connectors/serverless-connector --trigger-http
3.进入Cloud Function,选择gcf-to-sql
,Testing,TEST THE FUNCTION:
#Connecting from Google Cloud Functions to Cloud SQL using TCP: databases => 'information_schema', 'mysql', 'performance_schema', 'sys', 'user_database'
#Connecting from Google Cloud Function to Cloud SQL using Unix Sockets: tables in sys database: => 'information_schema', 'mysql', 'performance_schema', 'sys', 'user_database'
成功!
【讨论】:
【参考方案6】:Cloud Functions - Supported Services - 我在这个列表中没有看到 Cloud SQL,所以它可能还不支持。
【讨论】:
【参考方案7】:您还可以授权 Firebase IP 地址范围,因为我们并不真正知道 Firebase 在外部使用哪个 IP 地址。
我已经尝试过了。 Google Cloud SQL 不使用内部 IP 地址。因此,您不能使用 10.128.0.0/20
来允许您的 Google Cloud SQL 使用内部 IP 地址。
回答
所以从控制台,转到Google Cloud SQL > Instance > Authorization
,你可以添加:
151.101.0.0/17
这将允许您使用151.101.0.0
到151.101.127.255
的IP 地址范围,其中Firebase 服务器域当前是151.101.1.195
和151.101.65.195
。
我不确定这个 IP 地址是否会改变。
此外,请确保您的 Cloud SQL 数据库正在使用 us-central
区域。 Firebase 似乎在us-central
中可用。
【讨论】:
以上是关于如何从 Cloud Functions 连接 Google Cloud SQL?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Cloud Function 调用其他 Cloud Firebase Functions
Cloud Functions for Firebase - 检索已部署的代码? [复制]
如何让 Google Cloud Functions 保持温暖?
如何从 Google Cloud Functions (nodeJS) 发送 HTTP 请求