使用dockers在nodeJS上为Postgres进行ECONNREFUSED

时间:2015-10-26 23:47:25

标签: node.js postgresql docker sequelize.js

我正在构建一个使用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

有人能帮帮我吗?

(喜欢码头的人:))

8 个答案:

答案 0 :(得分:42)

您的DATABASE_URL引用127.0.0.1,即loopback adapter(更多here)。这意味着“连接到我自己”。

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

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

变化:

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。这是尝试解析主机名时系统(在本例中为容器)的第一个位置。

答案 1 :(得分:1)

如果没有其他解决方案对您有用,请考虑手动包装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。)

答案 2 :(得分:1)

我在使用 docker-compose 时遇到了同样的问题。问题是我的 api 和 db 服务不在同一个网络中。您需要为 docker-compose 文件中的 api 和 db 服务添加此配置,以便它们可以在一个网络中找到彼此(不必将其称为 postgres,您可以为其指定任何名称你想要):

networks:
      - postgres

此外,在 docker-compose 文件中,请不要忘记将此特定网络添加到网络列表中:

networks:
  postgres:
    driver: bridge

现在,当您的服务在同一网络中时,您可以通过 env 变量或直接设置从 api 后端到 db 的连接,就像 DB_HOST=<DB_SERVICE_NAME> 一样,在我的情况下,在 docker-compose 我有服务列表,其中我的数据库服务名为 postgres:

services:
  postgres:

所以我需要调用这个环境 DB_HOST=postgres,现在我可以连接到数据库了。

附言最初我想使用专门针对 Mac DB_HOST=host.docker.internal 的解决方案,但是如果有其他人可能想要在 Windows 上运行您的 docker-compose 呢?最好保持一致。

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

对于其他读者来说,如果您使用的是host.docker.internal,请使用localhost代替doc中建议的127.0.0.1connection refused...。我遇到了同样的api-service问题。后端postgres无法使用localhost/127.0.0.1连接到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 。以下是我的docker-compose.yml和环境变量作为参考:

Collection<? extends T> ts

答案 5 :(得分:0)

我有两个容器,一个叫做postgresdb,另一个是调用节点

我从以下位置更改了节点query.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”],这对我来说已经解决了。我敢肯定,这可以做得更好,但是我只是在最近的两天内学习了docker compose / node.js的知识。

答案 6 :(得分:0)

我在这里做了一些小的修改。

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

但这是一种很酷的方式,使我们在编码时变得冗长。因此,您的方法很好。

答案 7 :(得分:0)

如前所述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