我正在构建一个使用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
有人能帮帮我吗?
(喜欢码头的人:))
答案 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.1
或connection 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。
<块引用>每个容器现在都可以查找主机名 web
或 db
并取回相应容器的 IP 地址。例如,web
的应用程序代码可以连接到 URL postgres://db:5432
并开始使用 Postgres 数据库。
请务必注意 HOST_PORT
和 CONTAINER_PORT
之间的区别。在上面的示例中,对于 db
,HOST_PORT
为 8001
,容器端口为 5432
(postgres 默认)。网络服务到服务通信使用 CONTAINER_PORT
。定义 HOST_PORT
后,该服务也可在 swarm 外部访问。
在 web
容器中,您到 db
的连接字符串看起来像 postgres://db:5432
,而在主机上,连接字符串看起来像 postgres://{DOCKER_IP}:8001
。>
所以 DATABASE_URL
应该是 postgres://username:pgpassword@db:5432/mydatabase