如何从云功能连接Google Cloud SQL?

时间:2017-03-25 23:23:35

标签: javascript firebase google-cloud-platform google-cloud-sql google-cloud-functions

我正在尝试使用Cloud Functions for Firebase构建一个与Google Cloud SQL(PostgreSQL)实例对话的API。

我正在使用HTTP(S)触发器。

当我列出桌面的IP地址时,我可以使用本地计算机上的函数node.js代码连接到Cloud SQL。但是当我部署时,我无法连接,而且我无法找出Firebase功能服务器的主机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);
  }
});

7 个答案:

答案 0 :(得分:28)

我在#36388165的进一步讨论中找到了答案。

免责声明:这似乎没有正式公布,因此可能会在之后发生变化。我也只在mysql中测试。但是这个解决方案的本质,我认为同样的方式应该像pg模块一样工作(它似乎accept domain socket path作为主机参数)

编辑(2017/12/7):谷歌似乎提供official early access,同样的方法仍然有效。
EDIT(2018/07/04):似乎有人只是复制并粘贴我的示例代码并遇到麻烦。作为谷歌says,您应该使用连接池来避免SQL连接泄漏。 (它导致ECONNREFUSE)所以我稍微更改了示例代码。 EDIT(2019/04/04):在下面的示例中,使用$ DBNAME作为spanner实例名称令人困惑,我修改了示例。

https://issuetracker.google.com/issues/36388165#comment44谷歌家伙说云功能实例可以通过特殊路径中的域套接字与云sql交谈'/ cloudsql / $ PROJECT_ID:$ REGION:$ DBNAME'。

我实际上可以从下面的云功能代码连接和操作云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
    });
};

我希望这对那些迫不及待谷歌正式宣布的人有所帮助。

答案 1 :(得分:10)

目前无法实现。但是,它是问题跟踪器#36388165上的功能请求:

  

目前没有从云功能连接到Cloud SQL   支持,因为UNIX套接字不存在(导致ENOENT)和   白名单中没有已定义的IP范围(导致ETIMEDOUT)。一   可能性是从云SQL实例中将0.0.0.0/0列入白名单,但是   出于安全原因,不建议这样做。

如果这对您来说是一个重要功能,我建议您访问发行人并为功能请求加注星标以帮助其获得普及。

答案 2 :(得分:8)

GCP > SQL > Instances页面上找到您的数据库区域和实例名称:

enter image description here

运行以下命令将数据库密码保存到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://stackoverflow.com/a/48825037/82686(通过Babel使用现代JavaScript语法)

答案 3 :(得分:8)

现在有与此相关的正式文档,尽管截至2018年7月仍处于Beta版

https://cloud.google.com/functions/docs/sql

答案 4 :(得分:2)

使用TCP和UNIX域套接字2020从谷歌云功能连接到云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.a具有外部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

具有内部ip的6.b Cloud 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连接到数据库内部,并使用unix域套接字从Google Cloud Functions连接到数据库外部。

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 domanin套接字从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,然后测试,测试功能:

#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'

成功!

答案 5 :(得分:0)

Cloud Functions - Supported Services - 我没有在此列表中看到Cloud SQL,所以可能还没有支持。

答案 6 :(得分:0)

您还可以授权 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.0151.101.127.255 IP地址范围,其中Firebase服务器域目前为151.101.1.195151.101.65.195

我不确定这个IP地址是否会改变。

此外,请确保您的Cloud SQL数据库正在使用us-central区域。 Firebase似乎在us-central中可用。