ECONNREFUSED for Postgres on nodeJS with dockers

ECONNREFUSED for Postgres on nodeJS with dockers

我正在使用 postgresql 在 NodeJS 上构建应用 运行ning。 我正在使用 SequelizeJS 作为 ORM。 为了避免使用真正的 postgres 守护进程并在我自己的设备上安装 nodejs,我正在使用带有 docker-compose.

的容器

当我运行docker-compose up 它启动 pg 数据库

database system is ready to accept connections

和 nodejs 服务器。 但是服务器无法连接到数据库。

Error: connect ECONNREFUSED 127.0.01:5432

如果我尝试 运行 服务器而不使用容器(在我的机器上使用真正的 nodejs 和 postgresd)它会工作。

但我希望它能与容器一起正常工作。我不明白我做错了什么。

这里是 docker-compose.yml 文件

web:
  image: node
  command: npm start
  ports:
    - "8000:4242"
  links:
    - db
  working_dir: /src
  environment:
    SEQ_DB: mydatabase
    SEQ_USER: username
    SEQ_PW: pgpassword
    PORT: 4242
    DATABASE_URL: postgres://username:pgpassword@127.0.0.1:5432/mydatabase
  volumes:
    - ./:/src
db:
  image: postgres
  ports:
  - "5432:5432"
  environment:
    POSTGRES_USER: username
    POSTGRES_PASSWORD: pgpassword

有人可以帮我吗?

(有人喜欢 docker :))

你的DATABASE_URL指的是127.0.0.1,也就是loopback adapter (more here)。这意味着“连接到我自己”。

当 运行 两个应用程序(不使用 Docker)在同一台主机上时,它们都可以在同一适配器上寻址(也称为 localhost)。

当 运行 两个应用程序都在容器中时,它们不像以前那样都在本地主机上。相反,您需要将 web 容器指向 docker0 适配器上 db 容器的 IP 地址 - docker-compose 为您设置。

变化:

127.0.0.1CONTAINER_NAME(例如 db

示例:

DATABASE_URL: postgres://username:pgpassword@127.0.0.1:5432/mydatabase

DATABASE_URL: postgres://username:pgpassword@db:5432/mydatabase

这要归功于 Docker 链接:web 容器有一个文件 (/etc/hosts),其中 db 条目指向 db 容器已打开。这是系统(在本例中为容器)在尝试解析主机名时首先查找的位置。

如果您单独发送数据库变量。您可以分配数据库主机。

DB_HOST=<POSTGRES_SERVICE_NAME> #in your case "db" from docker-compose file.

对于更多读者,如果您使用 Docker desktop for Mac,请使用 host.docker.internal 而不是 localhost127.0.0.1,如 doc 中所建议的那样。我遇到了同样的 connection refused... 问题。后端 api-service 无法使用 localhost/127.0.0.1 连接到 postgres。下面是我的docker-compose.yml和环境变量作为参考:

version: "2"

services:
  api:
    container_name: "be"
    image: <image_name>:latest
    ports:
      - "8000:8000"
    environment:
      DB_HOST: host.docker.internal
      DB_USER: <your_user>
      DB_PASS: <your_pass>
    networks: 
      - mynw

  db:
    container_name: "psql"
    image: postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: <your_postgres_db_name>
      POSTGRES_USER: <your_postgres_user>
      POSTGRES_PASS: <your_postgres_pass>
    volumes:
      - ~/dbdata:/var/lib/postgresql/data
    networks:
      - mynw

我有两个容器,一个叫 postgresdb,另一个叫 node

我更改了我的节点 queries.js 来自:

const pool = new Pool({
    user: 'postgres',
    host: 'localhost',
    database: 'users',
    password: 'password',
    port: 5432,
})

const pool = new Pool({
    user: 'postgres',
    host: 'postgresdb',
    database: 'users',
    password: 'password',
    port: 5432,
})

我所要做的就是将主机更改为我的容器名称 ["postgresdb"],这为我解决了这个问题。我确信这可以做得更好,但我最近 2 天刚刚学习了 docker compose / node.js 东西。

如果其他解决方案中的 none 对您有效,请考虑手动包装 PgPool.connect() 并在 ECONNREFUSED 时重试:

const pgPool = new Pool(pgConfig);
const pgPoolWrapper = {
    async connect() {
        for (let nRetry = 1; ; nRetry++) {
            try {
                const client = await pgPool.connect();
                if (nRetry > 1) {
                    console.info('Now successfully connected to Postgres');
                }
                return client;
            } catch (e) {
                if (e.toString().includes('ECONNREFUSED') && nRetry < 5) {
                    console.info('ECONNREFUSED connecting to Postgres, ' +
                        'maybe container is not ready yet, will retry ' + nRetry);
                    // Wait 1 second
                    await new Promise(resolve => setTimeout(resolve, 1000));
                } else {
                    throw e;
                }
            }
        }
    }
};

(请参阅 node-postgres 中的 this issue 进行跟踪。)

我来这里是为了处理这个问题。

正如Andy在他的回应中所说。

  • "you need to point the web container to the db container's"

并考虑到有关 docker-compose link's

的官方文档
  • "Links are not required to enable services to communicate - by default, any service can reach any other service at that service’s name."

因此,您可以这样保持 docker_compose.yml:

docker_compose.yml

version: "3"
services:
    web:
      image: node
      command: npm start
      ports:
         - "8000:4242"
      # links:
      #   - db
      working_dir: /src
      environment:
        SEQ_DB: mydatabase
        SEQ_USER: username
        SEQ_PW: pgpassword
        PORT: 4242
        # DATABASE_URL: postgres://username:pgpassword@127.0.0.1:5432/mydatabase
        DATABASE_URL: "postgres://username:pgpassword@db:5432/mydatabase"
      volumes:
          - ./:/src
    db:
      image: postgres
      ports:
          - "5432:5432"
      environment:
        POSTGRES_USER: username
        POSTGRES_PASSWORD: pgpassword

但在我们编码时,这是一种很酷的冗长方式。所以,你的方法很好。

如前所述here.

Each container can now look up the hostname web or db and get back the appropriate container’s IP address. For example, web’s application code could connect to the URL postgres://db:5432 and start using the Postgres database.

It is important to note the distinction between HOST_PORT and CONTAINER_PORT. In the above example, for db, the HOST_PORT is 8001 and the container port is 5432 (postgres default). Networked service-to-service communication uses the CONTAINER_PORT. When HOST_PORT is defined, the service is accessible outside the swarm as well.

Within the web container, your connection string to db would look like postgres://db:5432, and from the host machine, the connection string would look like postgres://{DOCKER_IP}:8001.

所以DATABASE_URL应该是postgres://username:pgpassword@db:5432/mydatabase