【问题标题】:ECONNREFUSED for Postgres on nodeJS with dockersECONNREFUSED for Postgres on nodeJS with dockers
【发布时间】:2016-01-26 06:00:00
【问题描述】:

我正在使用 postgresql 构建一个在 NodeJS 上运行的应用程序。 我使用 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 的人 :))

【问题讨论】:

  • 这篇文章提到了“boot2docker ip”命令,这里似乎有用吗? andreagrandi.it/2015/02/21/…
  • 似乎对您使用的主机操作系统有所不同

标签: node.js postgresql docker sequelize.js


【解决方案1】:

您的DATABASE_URL 指的是127.0.0.1,即loopback adapter(更多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 容器所在的 IP。这是系统(在本例中为容器)在尝试解析主机名时首先查看的位置。

【讨论】:

  • 谢谢安迪,这就是我想要的。祝你有美好的一天!
  • 我是 postgres/node 的菜鸟/初学者。我到底需要在哪里进行更改?
  • @nerdess DATABASE_URL 在问题的docker-compose.yml 中——这就是需要改变的地方。您在应用程序代码中使用 process.env['DATABASE_URL'] 引用它。
  • 如果在 Windows 10 机器上,您的 Node 应用程序在 Docker 中运行,但您的 Postgres 不是?
  • @Andy 改变我得到Error: getaddrinfo ENOTFOUND db db:5432
【解决方案2】:

对于更多读者,如果您使用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

【讨论】:

  • 哇,谢谢你的回答。它就像一个魅力
  • 多年来,我一直在努力解决这个问题,尝试各种建议,这终于让我的迁移工作了。谢谢。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    我有两个容器,一个叫 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 的东西。

    【讨论】:

      【解决方案5】:

      如果其他解决方案都不适合您,请考虑手动包装 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 进行跟踪。)

      【讨论】:

      • 从字面上看,没有任何效果,直到我尝试了这个并且它立即奏效了!谢谢!!!!
      【解决方案6】:

      正如提到的here

      现在每个容器都可以查找主机名 webdb 并取回相应容器的 IP 地址。例如,web 的应用程序代码可以连接到 URL postgres://db:5432 并开始使用 Postgres 数据库。

      注意HOST_PORTCONTAINER_PORT 之间的区别很重要。在上面的例子中,对于dbHOST_PORT8001,容器端口是5432(postgres 默认)。联网的服务到服务通信使用CONTAINER_PORT。当 HOST_PORT 被定义时,服务也可以在 swarm 之外访问。

      web 容器中,您到db 的连接字符串看起来像postgres://db:5432,而在主机上,连接字符串看起来像postgres://{DOCKER_IP}:8001

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

      【讨论】:

      • 不敢相信我花了几个小时试图找到问题,这是完美的答案,非常感谢
      【解决方案7】:

      我在这里对处理这个进行了微小的修改。

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

      • "您需要将web 容器指向db 容器"

      并考虑到关于docker-compose link's的官方文档

      • “启用服务进行通信不需要链接 - 默认情况下,任何服务都可以使用该服务的名称访问任何其他服务。”

      因此,您可以通过这种方式保留 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
      

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

      【讨论】:

        猜你喜欢
        • 2020-05-01
        • 2018-01-16
        • 1970-01-01
        • 2020-02-03
        • 2020-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多