Docker Compose中Node.js无法连接PostgreSQL的问题排查
我尝试用Docker Compose部署Node.js、PostgreSQL和Nginx服务,但Node.js应用抛出连接错误:
2025-04-02 20:07:11 Connection error Error: connect ECONNREFUSED 127.0.0.1:5432
2025-04-02 20:07:11 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
相关配置文件及代码如下:
docker-compose.yml
services: nginx: image: nginx:latest volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro ports: - "80:80" depends_on: - node-api node-api: build: . environment: - DB_HOST=postgres - DB_PORT=5432 - DB_NAME=database - DB_USER=postgres - DB_PASSWORD=password ports: - "3000:3000" depends_on: postgres: condition: service_healthy postgres: image: postgis/postgis:latest environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: password POSTGRES_DB: database ports: - "5432:5432" healthcheck: test: ["CMD", "pg_isready", "-U", "postgres", "-h", "localhost"] interval: 10s retries: 5 start_period: 30s timeout: 10s volumes: postgres-data:
Dockerfile
# Use an official Node.js runtime as a parent image FROM node:18 # Set the working directory WORKDIR /app # Copy package.json and install dependencies COPY package.json package-lock.json ./ RUN npm install # Copy the rest of the application COPY . . # Expose the port the app runs on EXPOSE 3000 # Start the application CMD ["node", "api/apis.js"]
api.js
import express from 'express' import cors from 'cors' import client from './postgres_connection.js' const app = express(); app.use(cors()); app.use(express.json()); app.get('/getMarkers', async (req, res) => { try { const result = await client.query('SELECT * FROM public.topo_markers'); res.json(result.rows); } catch (errr) { console.error(errr.message); res.status(500).send('Internal server error'); } }); app.post('/addMarker', async (req, res) => { const { title, description, latitude, longitude } = req.body; const isBodyEmpty = !title || !description || !latitude || !longitude; if (isBodyEmpty) { return res.status(400).send('Missing required properties'); } try { const query = ` INSERT INTO public.topo_markers (title, description, geom) VALUES ($1, $2, ST_SetSRID(ST_MakePoint($3, $4), 4326)) RETURNING *; `; const result = await client.query(query, [title, description, longitude, latitude]); res.status(201).json(result.rows[0]); } catch (errr) { console.error(errr.message); res.status(500).send('Internal server error'); } }); app.listen(3000)
postgres_connection.js
import pg from 'pg'; const client = new pg.Client({ user: 'postgres', // Default is usually 'postgres' host: 'localhost', // Use the container's IP if needed database: 'test_database', // Change to your database name password: 'password', // Set this properly port: 5432, // Default PostgreSQL port }); client.connect() .then(() => console.log('Connected to PostGIS!')) .catch(err => console.error('Connection error', err.stack)); export default client;
问题根源与修复步骤
1. 硬编码连接配置未使用环境变量
你的postgres_connection.js直接写死了host: 'localhost'和database: 'test_database',但Docker Compose容器间通信需用服务名(postgres)作为主机名,且你在docker-compose.yml中配置的数据库名是database,与代码中的test_database不一致。
修复postgres_connection.js:
import pg from 'pg'; const client = new pg.Client({ user: process.env.DB_USER || 'postgres', host: process.env.DB_HOST || 'localhost', database: process.env.DB_NAME || 'test_database', password: process.env.DB_PASSWORD || 'password', port: process.env.DB_PORT || 5432, }); client.connect() .then(() => console.log('Connected to PostGIS!')) .catch(err => console.error('Connection error', err.stack)); export default client;
2. 容器间通信逻辑验证
Docker Compose会为所有服务创建默认网络,服务名postgres可直接解析为对应容器的IP。只要Node.js服务的环境变量正确注入,就能通过postgres:5432访问数据库。
3. 数据库名称一致性
docker-compose.yml中PostgreSQL的POSTGRES_DB为database,修复后通过环境变量DB_NAME统一配置,避免数据库名称不匹配导致的连接失败。
4. 健康检查有效性
当前PostgreSQL健康检查配置合理,node-api服务的depends_on已设置为等待PostgreSQL服务就绪,确保Node.js启动时数据库已可正常连接。
内容的提问来源于stack exchange,提问作者EnCoder2000

