0

I've been trying to connect to my Cloud SQL instance using the pg module but haven't been successful so far.

I've looked around a lot online but couldn't understand much on the topic. I also would like to deploy my Express app on Cloud Run at some point and have it connect to my Cloud SQL instance but I don't know how to go about doing that.

Here's a list of things I don't understand and would like a brief explanation on:

  1. What are Unix socket connections and why should I use them over normal connections?
  2. What is a Cloud SQL Proxy? Do I need to use it? If so, why?
  3. Would I need to do any extra work to connect to my Cloud SQL instance from Cloud Run?

Here are all the connection objects and connection strings I have tried with the pg.Client object:

  1. First connection string: postgresql+psycopg2://postgres:password@/cloudsql/myapp:us-central1:mydb?host=/var/lib/postgresql
  2. Second connection string: postgresql://postgres:password@hostip:5432/myapp:us-central1:mydb
  3. Third connection string: postgresql://postgres:password@hostip:5432/sarcdb
  4. Connection object: { host: "/cloudsql/myapp:us-central1:mydb", username: "postgres", password: "password", database: "mydb" }

All of these give me a Connection terminated unexpectedly error.

halfer
  • 19,824
  • 17
  • 99
  • 186
Frixoe
  • 97
  • 3
  • 9

2 Answers2

10

The Cloud Functions documentation for Node.js & Cloud SQL (scroll down to PostgreSQL) has applicable information on structuring the connection string and the additional configuration needed for credentials.

Once that's in place for your app, you'll need to add the Cloud SQL instance to your Cloud Run service before it will be able to use that connection string to reach the database.

Here's directly copying the code sample from the docs, with Cloud Run the max configuration of 1 might not keep pace with other concurrency settings.

const pg = require('pg');

/**
 * TODO(developer): specify SQL connection details
 */
const connectionName =
  process.env.INSTANCE_CONNECTION_NAME || '<YOUR INSTANCE CONNECTION NAME>';
const dbUser = process.env.SQL_USER || '<YOUR DB USER>';
const dbPassword = process.env.SQL_PASSWORD || '<YOUR DB PASSWORD>';
const dbName = process.env.SQL_NAME || '<YOUR DB NAME>';

const pgConfig = {
  max: 1,
  user: dbUser,
  password: dbPassword,
  database: dbName,
};

if (process.env.NODE_ENV === 'production') {
  pgConfig.host = `/cloudsql/${connectionName}`;
}

// Connection pools reuse connections between invocations,
// and handle dropped or expired connections automatically.
let pgPool;

exports.postgresDemo = (req, res) => {
  // Initialize the pool lazily, in case SQL access isn't needed for this
  // GCF instance. Doing so minimizes the number of active SQL connections,
  // which helps keep your GCF instances under SQL connection limits.
  if (!pgPool) {
    pgPool = new pg.Pool(pgConfig);
  }

  pgPool.query('SELECT NOW() as now', (err, results) => {
    if (err) {
      console.error(err);
      res.status(500).send(err);
    } else {
      res.send(JSON.stringify(results));
    }
  });

  // Close any SQL resources that were declared inside this function.
  // Keep any declared in global scope (e.g. mysqlPool) for later reuse.
};
Grayside
  • 4,144
  • 21
  • 25
  • I can connect the Cloud SQL instance to the Cloud Run instance but I still can't connect from inside the Cloud Run instance with my express app using the `pg` module. What am I doing wrong? I'm using the 4th connection object mentioned in my question. – Frixoe Sep 30 '19 at 16:59
  • Not sure if it matters, but in the sample code above the key `user` is expected, and in the 4th connection object in your question you have `username`. – Grayside Sep 30 '19 at 18:10
  • Yep... That was the issue... I'm so dumb... but thanks anyways! – Frixoe Sep 30 '19 at 18:36
  • 1
    It looks like this answer is from a time when the Cloud Run/Cloud SQL docs did not include instructions for connecting to Cloud SQL, so Cloud Functions docs were used instead. At this point in time, it looks like the Cloud SQL docs include this information: https://cloud.google.com/sql/docs/postgres/connect-run – Matt Welke Nov 16 '19 at 00:54
1

What are Unix socket connections and why should I use them over normal connections?

A Unix domain socket is a socket for interprocess communication. If you have the choice between communication between a TCP connection and a Unix domain socket, the Unix domain socket is likely faster.

What is a Cloud SQL Proxy? Do I need to use it? If so, why?

The Cloud SQL proxy allows you to authenticate a connection to connect to your database using IAM permissions of a service account.

Since Cloud SQL is a cloud database, it requires (by default) some form of authentication to help it remain secure. The proxy is a more secure method of connecting compared to a self-managed SSL Certificate or a whitelisted IP address.

Would I need to do any extra work to connect to my Cloud SQL instance from Cloud Run?

Cloud Run takes care of running the proxy for you, but you need to do the following:

  1. Enable the Cloud SQL Admin API
  2. Add the Cloud SQL instance to your Run deployment(follow these steps).
  3. Ensure that the service account running your code has the Cloud SQL Client IAM permissions (this is done for the default service account by step 2)
  4. Configure your application to connect with /cloudsql/INSTANCE_CONNECTION_NAME
kurtisvg
  • 3,412
  • 1
  • 8
  • 24
  • Unfortunately, this did not work. It still says "Connection terminated unexpectedly" in the Cloud Run logs. What do you think is going wrong? I used the 4th connection object mentioned in my question. – Frixoe Sep 30 '19 at 16:36