【发布时间】:2021-02-18 14:42:22
【问题描述】:
我有一个 docker-composer.yml 正在设置两个服务:server 和 db。 Node.js服务器,即server服务,使用pg连接PostgreSQL数据库;而db 服务是一个 PostgreSQL 镜像。
在服务器启动时,它尝试连接到数据库但超时。
docker-compose.yml
version: '3.8'
services:
server:
image: myapi
build: .
container_name: server
env_file: .env
environment:
- PORT=80
- DATABASE_URL=postgres://postgres:postgres@db:15432/mydb
- REDIS_URL=redis://redis
ports:
- 3000:80
depends_on:
- db
command: node script.js
restart: unless-stopped
db:
image: postgres
container_name: db
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: mydb
ports:
- 15432:15432
volumes:
- db-data:/var/lib/postgresql/data
command: -p 15432
restart: unless-stopped
volumes:
db-data:
编辑:上面的代码更改为删除 links 和 expose。
db服务输出:
db |
db | PostgreSQL Database directory appears to contain a database; Skipping initialization
db |
db | 2020-11-05 20:18:15.865 UTC [1] LOG: starting PostgreSQL 13.0 (Debian 13.0-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
db | 2020-11-05 20:18:15.865 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 15432
db | 2020-11-05 20:18:15.865 UTC [1] LOG: listening on IPv6 address "::", port 15432
db | 2020-11-05 20:18:15.873 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.15432"
db | 2020-11-05 20:18:15.880 UTC [25] LOG: database system was shut down at 2020-11-05 20:18:12 UTC
db | 2020-11-05 20:18:15.884 UTC [1] LOG: database system is ready to accept connections
script.js - 由来自server 服务的命令使用。
const pg = require('pg');
console.log(process.env.DATABASE_URL);
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
connectionTimeoutMillis: 5000,
});
pool.connect((err, _, done) => {
if (err) {
console.error(err);
done(err);
}
done();
});
pool.query('SELECT NOW()', (err, res) => {
console.log(err, res);
pool.end();
});
const client = new pg.Client({
connectionString: process.env.DATABASE_URL,
connectionTimeoutMillis: 5000,
});
client.connect(console.error);
client.query('SELECT NOW()', (err, res) => {
console.log(err, res);
client.end();
});
server服务输出:
注意:第一行是来自script.js 的第一个console.log 调用的输出。
注意:由于server 服务是使用restart: unless-stopped 设置的,因此它将永远重复此输出。
server | postgres://postgres:postgres@db:15432/mydb
server | Error: Connection terminated due to connection timeout
server | at Connection.<anonymous> (/home/node/app/node_modules/pg/lib/client.js:255:9)
server | at Object.onceWrapper (events.js:421:28)
server | at Connection.emit (events.js:315:20)
server | at Socket.<anonymous> (/home/node/app/node_modules/pg/lib/connection.js:78:10)
server | at Socket.emit (events.js:315:20)
server | at emitCloseNT (net.js:1659:8)
server | at processTicksAndRejections (internal/process/task_queues.js:79:21)
server | at runNextTicks (internal/process/task_queues.js:62:3)
server | at listOnTimeout (internal/timers.js:523:9)
server | at processTimers (internal/timers.js:497:7)
server | Error: Connection terminated due to connection timeout
server | at Connection.<anonymous> (/home/node/app/node_modules/pg/lib/client.js:255:9)
server | at Object.onceWrapper (events.js:421:28)
server | at Connection.emit (events.js:315:20)
server | at Socket.<anonymous> (/home/node/app/node_modules/pg/lib/connection.js:78:10)
server | at Socket.emit (events.js:315:20)
server | at emitCloseNT (net.js:1659:8)
server | at processTicksAndRejections (internal/process/task_queues.js:79:21)
server | at runNextTicks (internal/process/task_queues.js:62:3)
server | at listOnTimeout (internal/timers.js:523:9)
server | at processTimers (internal/timers.js:497:7) undefined
server | Error: timeout expired
server | at Timeout._onTimeout (/home/node/app/node_modules/pg/lib/client.js:95:26)
server | at listOnTimeout (internal/timers.js:554:17)
server | at processTimers (internal/timers.js:497:7)
server | Error: Connection terminated unexpectedly
server | at Connection.<anonymous> (/home/node/app/node_modules/pg/lib/client.js:255:9)
server | at Object.onceWrapper (events.js:421:28)
server | at Connection.emit (events.js:315:20)
server | at Socket.<anonymous> (/home/node/app/node_modules/pg/lib/connection.js:78:10)
server | at Socket.emit (events.js:315:20)
server | at emitCloseNT (net.js:1659:8)
server | at processTicksAndRejections (internal/process/task_queues.js:79:21) undefined
server | postgres://postgres:postgres@db:15432/mydb
...
从主机,我可以通过db 服务访问PostgreSQL 数据库,连接成功,使用来自server 服务的相同脚本。
从主机运行的脚本的输出:
➜ node script.js
postgres://postgres:postgres@localhost:15432/mydb
null Client { ... }
undefined Result { ... }
null Result { ... }
这个输出表示连接成功。
总结:
我无法从server 容器访问db 容器,连接超时,但我可以从主机访问db 容器,连接成功。
注意事项
首先,感谢您到目前为止的回答。解决提出的一些问题:
-
缺少网络:
这不是必需的,因为 docker-compose 有一个默认网络。 A 使用自定义网络进行了测试,但它也不起作用。
-
初始化顺序:
我使用
depends_on来确保首先启动db容器,但我知道它并不能确保实际上先初始化数据库然后再初始化服务器。这不是问题,因为发生超时时服务器会中断并且它会再次运行,因为它是使用restart: unless-stopped设置的。因此,如果数据库在第一次或第二次尝试启动服务器时仍在初始化,则没有问题,因为服务器将继续重新启动,直到连接成功(从未发生过)。 -
更新:
从
server容器,我可以使用psql访问db服务上的数据库。我仍然无法从那里的 Node.js 应用程序连接。DATABASE_URL不是问题,因为我在psql命令中使用的 URI 与script.js使用的 URI 相同,并由第一个console.log调用打印出来。使用的命令行:
docker exec -it server psql postgres://postgres:postgres@db:15432/mydb
编辑:通过删除对 Sequelize 的依赖来改进代码。现在它只使用pg,直接调用脚本。
【问题讨论】:
-
好久没用docker了,不妨试试添加:networks: - mynetwork 和server里面的port和db services同级
-
我未能重现您的错误:我重用了您的 docker-compose 文件,将服务
app替换为标准 ubuntu 映像,执行了docker-compose up并安装了postgresql-client。来自应用容器的命令psql -h db -p 15432 -U postgres -W成功!建议你看下Sequelize的配置,可能是连接字符串有错误。 -
@NelsonG。 @jeeves 我刚刚尝试过,我可以使用
psql从server容器到达db容器。现在我需要找出为什么我无法使用pg从 node.js 应用程序访问。感谢您的帮助! -
你能分享你的Dockerfile吗?我已经使用了您的 docker-compose 和脚本,但无法重现您的问题。我使用
node:10-alpine作为基础映像,除了pg之外没有安装其他库 -
答案已更新解决方案:)
标签: node.js postgresql docker docker-compose