如何配置Docker Compose让Express.js容器等PostgreSQL就绪并交互式运行
问题:Express.js交互式应用Docker Compose启动后输入卡顿
我有一个支持终端交互式输入输出的Express.js应用,使用PostgreSQL存储数据。需要通过Docker Compose管理容器,确保Express.js应用在PostgreSQL完全就绪后启动,同时保持终端交互性。此前遇到启动顺序问题,Express容器在PostgreSQL就绪前启动导致连接错误,或无法交互式运行。调整docker-compose.yml后应用能启动,但输入选项1后出现卡顿。
配置文件
docker-compose.yml
services: postgresdb: image: "postgres:latest" environment: - POSTGRES_USER=root - POSTGRES_PASSWORD=root - POSTGRES_DB=userinfo container_name: postgresqldb healthcheck: test: ["CMD", "pg_isready", "-U", "root", "-d", "userinfo"] interval: 10s timeout: 10s retries: 3 app: build: . depends_on: postgresdb: condition: service_healthy stdin_open: true tty: true
Dockerfile
FROM node:20 WORKDIR /myapp COPY . . RUN npm install EXPOSE 3000 CMD [ "npm", "start" ]
运行日志(输入1后卡顿)
[+] Running 3/3 ✔ Network bind-mounts_default Created 0.0s ✔ Container postgresqldb Created 0.0s ✔ Container bind-mounts-app-1 Created 0.0s Attaching to bind-mounts-app-1, postgresqldb postgresqldb | The files belonging to this database system will be owned by user "postgres". postgresqldb | This user must also own the server process. postgresqldb | postgresqldb | The database cluster will be initialized with locale "en_US.utf8". postgresqldb | The default database encoding has accordingly been set to "UTF8". postgresqldb | The default text search configuration will be set to "english". postgresqldb | postgresqldb | Data page checksums are disabled. postgresqldb | postgresqldb | fixing permissions on existing directory /var/lib/postgresql/data ... ok postgresqldb | creating subdirectories ... ok postgresqldb | selecting dynamic shared memory implementation ... posix postgresqldb | selecting default max_connections ... 100 postgresqldb | selecting default shared_buffers ... 128MB postgresqldb | selecting default time zone ... Etc/UTC postgresqldb | creating configuration files ... ok postgresqldb | running bootstrap script ... ok postgresqldb | performing post-bootstrap initialization ... ok postgresqldb | initdb: warning: enabling "trust" authentication for local connections postgresqldb | initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. postgresqldb | syncing data to disk ... ok postgresqldb | postgresqldb | postgresqldb | Success. You can now start the database server using: postgresqldb | postgresqldb | pg_ctl -D /var/lib/postgresql/data -l logfile start postgresqldb | postgresqldb | waiting for server to start....2024-08-01 14:14:30.694 UTC [48] LOG: starting PostgreSQL 16.3 (Debian 16.3-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit postgresqldb | 2024-08-01 14:14:30.694 UTC [48] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" postgresqldb | 2024-08-01 14:14:30.696 UTC [51] LOG: database system was shut down at 2024-08-01 14:14:30 UTC postgresqldb | 2024-08-01 14:14:30.699 UTC [48] LOG: database system is ready to accept connections postgresqldb | done postgresqldb | server started postgresqldb | CREATE DATABASE postgresqldb | postgresqldb | postgresqldb | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* postgresqldb | postgresqldb | waiting for server to shut down...2024-08-01 14:14:30.851 UTC [48] LOG: received fast shutdown request postgresqldb | .2024-08-01 14:14:30.853 UTC [48] LOG: aborting any active transactions postgresqldb | 2024-08-01 14:14:30.855 UTC [48] LOG: background worker "logical replication launcher" (PID 54) exited with exit code 1 postgresqldb | 2024-08-01 14:14:30.855 UTC [49] LOG: shutting down postgresqldb | 2024-08-01 14:14:30.855 UTC [49] LOG: checkpoint starting: shutdown immediate postgresqldb | 2024-08-01 14:14:30.881 UTC [49] LOG: checkpoint complete: wrote 922 buffers (5.6%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.011 s, sync=0.014 s, total=0.026 s; sync files=301, longest=0.004 s, average=0.001 s; distance=4255 kB, estimate=4255 kB; lsn=0/1911FA0, redo lsn=0/1911FA0 postgresqldb | 2024-08-01 14:14:30.886 UTC [48] LOG: database system is shut down postgresqldb | done postgresqldb | server stopped postgresqldb | postgresqldb | PostgreSQL init process complete; ready for start up. postgresqldb | postgresqldb | 2024-08-01 14:14:30.968 UTC [1] LOG: starting PostgreSQL 16.3 (Debian 16.3-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit postgresqldb | 2024-08-01 14:14:30.969 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 postgresqldb | 2024-08-01 14:14:30.969 UTC [1] LOG: listening on IPv6 address "::", port 5432 postgresqldb | 2024-08-01 14:14:30.970 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" postgresqldb | 2024-08-01 14:14:30.973 UTC [64] LOG: database system was shut down at 2024-08-01 14:14:30 UTC postgresqldb | 2024-08-01 14:14:30.976 UTC [1] LOG: database system is ready to accept connections bind-mounts-app-1 | bind-mounts-app-1 | > bind-mounts@1.0.0 start bind-mounts-app-1 | > node app.js bind-mounts-app-1 | bind-mounts-app-1 | Choose an option: bind-mounts-app-1 | 1. Add a name to the DB bind-mounts-app-1 | 2. Get all names from the DB bind-mounts-app-1 | 3. Quit bind-mounts-app-1 | Enter your choice: Server is running on http://localhost:3000 1 postgresqldb | 2024-08-01 14:19:31.073 UTC [62] LOG: checkpoint starting: time postgresqldb | 2024-08-01 14:19:35.393 UTC [62] LOG: checkpoint complete: wrote 45 buffers (0.3%); 0 WAL file(s) added, 0 removed, 0 recycled; write=4.306 s, sync=0.006 s, total=4.320 s; sync files=12, longest=0.005 s, average=0.001 s; distance=261 kB, estimate=261 kB; lsn=0/19533D8, redo lsn=0/19533A0
解决方法
1. 修正终端输入传递
使用docker-compose run启动应用容器,确保输入直接绑定到该容器,避免docker-compose up时输入分散到多个容器:
docker-compose run app
如果要保留docker-compose up,可以指定只attach到应用容器:
docker-compose up app
2. 绕过npm子进程干扰
npm start会创建子进程,可能导致终端输入无法正确传递到Node.js应用。修改Dockerfile的启动命令为直接运行node:
FROM node:20 WORKDIR /myapp COPY . . RUN npm install EXPOSE 3000 CMD ["node", "app.js"]
3. 确保应用readline配置正确
如果应用使用readline模块处理终端输入,需确保它正确识别终端环境:
const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true // 强制识别为终端 });
4. 添加数据库连接重试逻辑
即使PostgreSQL通过健康检查,偶尔也会有连接延迟,在应用中添加重试逻辑避免卡顿:
const { Pool } = require('pg'); const pool = new Pool({ user: 'root', host: 'postgresdb', // 对应Docker Compose中的服务名 database: 'userinfo', password: 'root', port: 5432, }); async function connectWithRetry() { try { await pool.connect(); console.log('已成功连接PostgreSQL'); } catch (err) { console.log('连接失败,2秒后重试...'); setTimeout(connectWithRetry, 2000); } } connectWithRetry();
内容的提问来源于stack exchange,提问作者Abeer
相关产品推荐
相关产品推荐

