Wednesday, December 7, 2022
No menu items!
HomeCloud ComputingTroubleshooting Cloud Functions connection issues to Cloud SQL private IPs

Troubleshooting Cloud Functions connection issues to Cloud SQL private IPs

Although it is a common use case for Cloud Functions to connect to your resources hosted in a Virtual Private Cloud using private IP addresses, it might not always be obvious how to debug connection issues. For example, you might see timeout errors or other errors related to being unsuccessful at establishing a connection. And trying to debug based on those error messages alone might not have enough information for you to determine the issue. 

A better framework for debugging is to determine

What is your network(s) configuration? Do you have just one VPC or more than one? Are you using VPC Peering or Shared VPC? Are you using a single region or multiple regions?

Where does your resource reside, e.g. which network or region?

Are you connecting over a private or public IP?

Where does your Cloud Function reside, e.g. which region?

Do you need to use a Serverless VPC Access Connection? The answer below!

Once you have confirmed what your network looks like, you can use a checklist-style approach to review your setup and verify each step has been configured properly.  

In this blog post, we’ll go over 3 scenarios involving VPC and public/private IPs and how we’ve configured Cloud Functions to connect to a Cloud SQL instance in each, as illustrated in the diagram below. 

3 examples of connecting Cloud Functions to a Cloud SQL instance involving VPC

Before we begin…

Whenever you need a Serverless compute product to reach a resource within a VPC that’s using a private IP address, you will need to use a  Serverless VPC Access Connector.  Your serverless environment does not automatically have access to your VPC network. A Serverless VPC Connector enables such access, but you must enable it. 

The service account for your Function will need the proper permissions to connect to Cloud SQL. You can follow these steps for configuring a Cloud Function to connect to Cloud SQL.

Also, a Serverless VPC Access Connector occurs a monthly cost for the size of the instance used for the connector. See pricing for more info.  

Scenario 1 – Connect to a Cloud SQL instance using public IP in same region as Cloud Function

In this first scenario, we will connect a Cloud Function to a Cloud SQL instance that has a public IP address. Since Cloud SQL public IP instances are accessible from anywhere on the public internet, we do not need a Serverless VPC Access Connector. 

First, follow the steps in this quickstart to create a MySQL instance with a public IP that contains a “guestbook” database. Since this MySQL instance uses a public IP, you can use Cloud Shell.

Note:if you are using Cloud Functions 2nd gen, you will need to add a Cloud SQL connector to the underlying Cloud Run service. You can follow the directions here: Connect from Cloud Run | Cloud SQL for MySQL; otherwise, you might see Error: connect ENOENT /cloudsql/<project>:<cloud-sql-region>:<cloud-sql-instance-name>

Here is a Cloud Functions 2nd gen nodejs example using the promise-mysql dependency:

code_block[StructValue([(u’code’, u’const functions = require(‘@google-cloud/functions-framework’);rnconst mysql = require(‘promise-mysql’);rn rn// note: for 1st gen Functions, you will use a signature similar to rn// exports.helloWorld = async (req, res) => {rn rnfunctions.http(‘helloHttp’, async (req, res) => {rn pool = await createUnixSocketPool();rn var recentGuests = await pool.query(‘SELECT * FROM entries LIMIT 5’);rn console.log(“logging the recent guests: “, recentGuests);rn res.status(200).send(“entryID: ” + recentGuests[0].entryID + “, name: ” + recentGuests[0].guestName + “, content: ” + recentGuests[0].content);rn});rn rn// initializes a Unix socket connection pool forrn// a Cloud SQL instance of MySQL using a public IPrnconst createUnixSocketPool = async config => {rn return mysql.createPool({ rn user: ‘<replace-with-cloud-sql-user>’,rn password: ‘<from-secret-manager>’,rn database: “guestbook”, rn socketPath: ‘/cloudsql/<your-project>:<cloud-sql-instance-region>:<cloud-sql-instance-name>’rn });rn};’), (u’language’, u”), (u’caption’, <wagtail.wagtailcore.rich_text.RichText object at 0x3e79f43ece90>)])]

Scenario 2 – Connect to a Cloud SQL instance using private IP in same region as Cloud Function

In the second scenario, we restrict the access of the Cloud SQL instance using a private IP address only. Here a Cloud Function will need to use a VPC connector to route traffic to the private IP of the Cloud SQL instance, since by default Serverless resources do not have access to your VPN. 

1. Follow the steps in this quickstart tocreate a MySQL instance with a private IP that contains a “guestbook” database. You’ll need to create a compute engine VM in the same VPC as your Cloud SQL instance. For production workloads, we recommend using the Cloud SQL Auth proxy to encrypt the traffic from your VM to your instance. Once you have VM access to your Cloud SQL instance, you can follow the same steps for creating the guestbook database. 

2. Create a Serverless VPC Access connector which will handle traffic between the Function and the VPC network. For our use case we will be using the default network and assign it an IP range of 10.8.0.0/28. This will ensure that the source IP address for any request sent from the connector will be from this IP range.

3. Configure your Cloud Function to use the VPC connector, as shown in the image below:

Configuring Cloud Functions to use a VPC connector  

Once deployed, you’ll see the VPC Connector information in the Function’s Details tab. You can learn more in the VPC Connector docs.

For a private IP, you can use a TCP connection to connect to the private IP instance, as shown in the following Cloud Functions 2nd gen example:

code_block[StructValue([(u’code’, u’const functions = require(‘@google-cloud/functions-framework’);rnconst mysql = require(‘promise-mysql’);rn rn// note: for 1st gen Functions, you will use a signature similar to rn// exports.helloWorld = async (req, res) => {rn rnfunctions.http(‘helloHttp’, async (req, res) => {rn pool = await createTcpPool();rn var recentGuests = await pool.query(‘SELECT * FROM entries LIMIT 5’);rn console.log(“logging the recent guests: “, recentGuests);rn res.status(200).send(“entryID: ” + recentGuests[0].entryID + “, name: ” + recentGuests[0].guestName + “, content: ” + recentGuests[0].content);rn});rn rn// createTcpPool initializes a TCP connection pool for a Cloud SQLrn// instance of MySQL using a private IPrnconst createTcpPool = async config => {rn const dbConfig = {rn host: ‘<cloud-sql-instance-private-IP>’, rn port: ‘3306’, // e.g. ‘3306’,rn user: ‘<replace-with-cloud-sql-user>’,rn password: ‘<from-secret-manager>’,rn database: ‘guestbook’,rn };rn // Establish a connection to the database.rn return mysql.createPool(dbConfig);rn};’), (u’language’, u”), (u’caption’, <wagtail.wagtailcore.rich_text.RichText object at 0x3e79f261edd0>)])]

Scenario 3 – Connect to a private Cloud SQL instance in a different region than the Serverless VPC Access connector and the Cloud Function

As long as your Cloud Function and your VPC Connector are in the same region (just like in Scenario 2), your SQL instance can be in a different region than the VPC connector. And you’ll use the same code as before in the second scenario. 

Next steps

You can find more information about connecting your Cloud Function to a VPC in the networking documentation, including how to configure your Function for egress and ingress. Also, please review the documentation for best practices for optimizing your Cloud Function for networking.

To learn more about Cloud Functions 2nd gen, you can try out this codelab that provides an overview of the new capabilities, including min instances and traffic splitting. 

Cloud BlogRead More

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments