I have a docker-composer.yml that is setting up two services: server
and db
. The Node.js server, which is the server
service, uses pg
to connect to the PostgreSQL database; and the db
service is a PostgreSQL image.
On the server startup, it tries to connect to the database but gets a timeout.
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:
Edit: code above changed to remove links
and expose
.
db
service output:
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
- used by the command from the server
service.
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
service output:
NOTE: The first line is the output of the first console.log
call from script.js
.
NOTE: Since the server
service is set up with restart: unless-stopped
, it will repeat this output forever.
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
...
From the host computer, I can reach the PostgreSQL database at the db
service, connecting successfully, using the same script from the server
service.
The output of the script running from the host computer:
➜ node script.js
postgres://postgres:postgres@localhost:15432/mydb
null Client { ... }
undefined Result { ... }
null Result { ... }
This output means the connection succeeded.
In summary:
I can't reach the db
container from the server
container, getting timeouts on the connection, but I can reach the db
container from the host computer, connecting successfully.
Considerations
First, thanks for the answer so far. Addressing some points raised:
Missing network:
It isn't required because docker-compose has a default network. A tested with a custom network but it didn't work either.
Order of initialization:
I'm using
depends_on
to ensure thedb
container is started first but I know it isn't ensuring the database is in fact initialized first then the server. It isn't the problem because the server breaks when a timeout happens and it runs again because it is set up withrestart: unless-stopped
. So if the database is still initializing on the first or second try to start the server, there is no problem because the server will continue to be restarted until it succeeds in the connection (which never happened.)UPDATE:
From the
server
container, I could reach the database at thedb
service usingpsql
. I still can't connect from the Node.js app there.The
DATABASE_URL
isn't the problem because the URI I used in thepsql
command is the same URI used by thescript.js
and printed by the firstconsole.log
call there.Command-line used:
docker exec -it server psql postgres://postgres:postgres@db:15432/mydb
Edit: Improved code by removing the dependency for Sequelize. Now it uses only pg
and calls the script directly.