Darren Zou
Darren Zou

Reputation: 3744

Cannot connect to Cloud SQL Proxy via Docker - Error: connect ENOENT

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

Firstly here is my file paths: https://i.sstatic.net/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.

Upvotes: 1

Views: 3035

Answers (4)

spro
spro

Reputation: 1593

To your original question - it seems that the Unix Socket approach is simply not possible, according to this answer from another thread: https://stackoverflow.com/a/77588828/2809427

You will never be able to share a Unix socket between a container and a host [...] If the two processes aren't using the same kernel, they won't be able to share a Unix socket.

Upvotes: 0

kurtisvg
kurtisvg

Reputation: 3565

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.

Upvotes: 2

Donnald Cucharo
Donnald Cucharo

Reputation: 4126

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.

Upvotes: 0

Someone Special
Someone Special

Reputation: 13588

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.

Upvotes: 0

Related Questions