1

I can't seem to connect to the CloudSQL using Docker container.

Firstly here is my file paths: https://i.stack.imgur.com/iddC9.jpg

Dockerfile.dev:


FROM node:14-slim

WORKDIR /usr/src/app


COPY package*.json ./


RUN npm install


COPY . ./

Dockerfile.sql

RUN mkdir /cloudsql
WORKDIR /usr/src/app


COPY package*.json ./

RUN npm install


COPY ./cloud_sql_proxy ./
COPY ./service_acct.json ./

version: '3.8'
services: 
    cloud-sql-proxy:
        build: 
            context: .
            dockerfile: DockerFile.sql
        volumes: 
            - /cloudsql:/cloudsql
            - /service_acct.json:/app/service_acct.json
        command: ./cloud_sql_proxy -dir=/cloudsql -instances=test-game-199281:us-east1:testgame -credential_file=/app/service_acct.json
      
    app:
        build: 
            context: .
            dockerfile: DockerFile.dev
        env_file: 
            - ./.env
        volumes: 
            # since we copied root into host in dockerfile, we can map the whole directory with app.
             - "./src:/app/src"
        
        ports: 
            - "5000:5001"
        command: sh -c "npm run dev"

My node index.js file. I don't think there is anything wrong, maybe I am entering the wrong connection string format? The password and user is correct as far as I can tell.

const express = require('express');
const { Pool, Client } = require('pg')
const app = express();
require('dotenv').config({path:'../.env'})

const pool = new Pool({
    user: 'postgres',
    host: '/cloudsql/test-game-199281:us-east1:testgame',

    database: 'TestDB',
    password: '********',
    port: 5432
    
  })

  
app.get('/', (req, res) => {
    pool.connect(function(err, client, done) {
        if (err) {
            console.log("not able to get connection " + err);
            res.status(400).send(err);
            return
        }
        client.query("SELECT * FROM company", [1], (err, result) =>{
            done();
            if (err) {
                console.log(err);
                res.status(400).send(err);
            }
            res.status(200).send(result.rows);
        });
    });

});

Error I get:

Hello world listening on port 5001

app_1 | Error: connect ENOENT /cloudsql/test-game-199281:us-east1:testgame

/.s.PGSQL.5432

app_1 | at PipeConnectWrap.afterConnect [as oncomplete] (net.js:1146:16) {

app_1 | errno: -2,

app_1 | code: 'ENOENT',

app_1 | syscall: 'connect',

app_1 | address: '/cloudsql/test-game-199281:us-east1:testgame

/.s.PGSQL.5432'

app_1 | }

SOLVED: I switched to TCP. screw unix socket. so confusing.

Donnald Cucharo
  • 3,866
  • 1
  • 10
  • 17
darren z
  • 3,051
  • 3
  • 13
  • 28
  • Take it apart, check each piece. Are both containers running, logs from both, check the port, can you connect to the instance not from the app (eliminate the issue with the app), any useful stackdriver logs? Does sql instance allow connections from wherever is that you are connecting from? Does service account has enough permissions? – jabbson May 11 '21 at 04:51
  • I think your problem starts here `/tmp/keys/keyfile.json`. Unless you create the directory `/tmp/keys/`, I think the mount will fail. – John Hanley May 11 '21 at 07:06

3 Answers3

1

You've instructed the Cloud SQL Auth proxy to listen to 0.0.0.0:5432 with this flag -instances=test-game-199281:us-east1:testgame=tcp:0.0.0.0:5432.

But then you've instructed your app to connect to /cloudsql/<INSTANCE_CONNCECTION_NAME>, which is a unix socket.

You need to pick one, and make sure you are consistent between you app and proxy.

If you use TCP, you'll have to map the port in the container to a port on your machine (or somewhere in your docker-compose network that your app can reach it.) You'll have to update your app to connect on 127.0.0.1 (or whatever its docker IP is in the network). You can check out more on docker-compose networking here.

If you use Unix Domain sockets, you'll need to volume share the folder containing the socket so that both apps can access it. So if it's in /cloudsql, you'll need to share /cloudsql between your proxy container and your app container. You can check out more on docker-compose volumes here.

Cloud SQL's Managing Database Connections page has examples of connecting with both TCP and Unix domain sockets.

kurtisvg
  • 3,412
  • 1
  • 8
  • 24
  • Still no luck, but after changing most things to a TCP connection and having the host in pg-pool point to the docker ip, i do get a new error “connect ECONNREFUSED". This reddit post https://www.reddit.com/r/googlecloud/comments/n52x32/cloud_run_setting_up_test_environment/gwzqtal?utm_source=share&utm_medium=web2x&context=3 seem to be able to succeed using tcp and unix? idk.. – darren z May 11 '21 at 16:55
  • i got the docker ip by docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ID-TO-INSPECT – darren z May 11 '21 at 17:06
  • 1
    You can't mix the two: you have to pick one or the other. You're application can switch based on what environment it's in but it needs to be able to connect to however the proxy is set up. At this point, it would be good to update your original question with the config you are working with now. – kurtisvg May 11 '21 at 21:18
  • I edited it again with latest attempt. I can run sudo ./cloud_sql_proxy -dir=/cloudsql -instances=pixel-villains-312919:us-east1:pixelvill -credential_file=./service_acct.json. on my local terminal and it works and tells me "waiting for new connections" – darren z May 11 '21 at 23:50
0

The ENOENT error means that the connector utility cannot find the host to connect to your database. Here's a good answer that further explains it.

On your docker-compose file, the Cloud SQL Proxy is listening via TCP but your code is trying to connect via Unix socket. Your code can't connect to the host because the socket doesn't exist.

The solution is to configure your proxy to create and listen to a Unix Socket. Change the command to:

/cloud_sql_proxy -instances=INSTANCE_CONNECTION_NAME -dir=/cloudsql -credential_file=/tmp/keys/keyfile.json

No need to expose any ports to connect via Unix Sockets. I also suggest building your pool connection with a config object like in the above link or as specified by pg-pool, rather than a DB URL to avoid a possible issue where you cannot connect to a Unix Socket using connectionString URL.

Donnald Cucharo
  • 3,866
  • 1
  • 10
  • 17
  • hi. I have tried const pool = new Pool({ user: 'postgres', host: '/cloudsql/test-game-199281:us-east1:testgame', database: 'TestDB', password: 'FishTofu123', port: 5432 }) - still same error. The other comment said I don't have /tmp/keys/keyfile.json, I tried changing it to ./google_service_acct.json from the root(same folder as compose.yml) since I copy the entire thing over in dockerfile. Still nothing.. – darren z May 11 '21 at 14:08
  • 1
    @darrenZ1002 I'm glad to see that you've solved your problem. Too bad my solution didn't worked for you. Just a friendly advice, please avoid including your password on your questions and comments. I suggest you remove your comments exposing it and don't forget to change your password afterwards. – Donnald Cucharo May 12 '21 at 01:52
0

You can try to connect via service name cloud-sql-proxy:5432 instead of localhost:5432 when connecting between different dockers.

Each docker is an isolated network so you cannot use localhost since localhost will refer to the docker container's own local network.

Someone Special
  • 12,479
  • 7
  • 45
  • 76