使用Docker Compose部署Express+MongoDB时数据库连接失败
问题:Docker部署Express+MongoDB API无法连接数据库
我尝试用Docker容器部署一个基于Express和MongoDB的小型API,但无法连接到数据库。以下是相关代码及报错信息:
连接脚本
const mongoose = require('mongoose'); const result = require('dotenv').config(); const logger = require('../logger/api.logger'); const { DB_USER, DB_PASS, DB_HOST, DB_PORT, DB_NAME } = process.env const connect = () => { const url = `mongodb://@${DB_HOST}:${DB_PORT}/${DB_NAME}`; logger.info("CONNECTION_STRING = " + url); mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true, dbName: process.env.DB_NAME, }) mongoose.connection.once("open", async () => { logger.info("Connected to database"); }); mongoose.connection.on("error", (err) => { logger.error("Error connecting to database ", err); }); } const disconnect = () => { if (!mongoose.connection) { return; } mongoose.disconnect(); mongoose.once("close", async () => { console.log("Diconnected to database"); }); }; module.exports = { connect, disconnect }
.env文件
APP_PORT=3333 DB_NAME=first_db DB_PORT=2717 DB_HOST=db_container
app.js文件
const express = require('express'); const cors = require("cors"); const app = express(); app.use(cors()); app.use(express.json()); // Routes const router = require('./routes/router'); app.use(router); // DB Connection const database = require('./database/connection'); database.connect(); module.exports = app;
docker-compose.yml文件
version: '3.9' services: # Mongo DB mongo_db: image: mongo:latest container_name: db_container restart: always ports: - '${DB_PORT}:2717' volumes: - mongo_db:/data/db environment: MONGO_INITDB_DATABASE: ${DB_NAME} MONGO_INITDB_ROOT_USERNAME: ${DB_USER} MONGO_INITDB_ROOT_PASSWORD: ${DB_PASS} # Node API Service api: build: . ports: - '${APP_PORT}:${APP_PORT}' depends_on: - mongo_db volumes: - .:/usr/src/ env_file: - .env logging: driver: "json-file" options: max-size: "10m" max-file: "5" volumes: mongo_db: {}
报错信息
db_container | {"t":{"$date":"2023-03-17T20:36:51.205+00:00"},"s":"I", "c":"NETWORK", "id":23015, "ctx":"listener","msg":"Listening on","attr":{"address":"0.0.0.0"}} db_container | {"t":{"$date":"2023-03-17T20:36:51.205+00:00"},"s":"I", "c":"NETWORK", "id":23016, "ctx":"listener","msg":"Waiting for connections","attr":{"port":27017,"ssl":"off"}} docker-api-1 | MongooseServerSelectionError: connect ECONNREFUSED 172.23.0.2:2717 docker-api-1 | at _handleConnectionErrors (/app/node_modules/mongoose/lib/connection.js:755:11) docker-api-1 | at NativeConnection.openUri (/app/node_modules/mongoose/lib/connection.js:730:11) docker-api-1 | at runNextTicks (node:internal/process/task_queues:60:5) docker-api-1 | at listOnTimeout (node:internal/timers:537:9) docker-api-1 | at process.processTimers (node:internal/timers:511:7) docker-api-1 | at async Object.connect (/app/src/database/connection.js:82:7) { docker-api-1 | reason: TopologyDescription { docker-api-1 | type: 'Unknown', docker-api-1 | servers: Map(1) { 'db_container:2717' => [ServerDescription] }, docker-api-1 | stale: false, docker-api-1 | compatible: true, docker-api-1 | heartbeatFrequencyMS: 10000, docker-api-1 | localThresholdMS: 15, docker-api-1 | setName: null, docker-api-1 | maxElectionId: null, docker-api-1 | maxSetVersion: null, docker-api-1 | commonWireVersion: 0, docker-api-1 | logicalSessionTimeoutMinutes: null docker-api-1 | }, docker-api-1 | code: undefined docker-api-1 | } docker-api-1 exited with code 1
解决方案
1. 修正端口不匹配问题
从报错和Mongo日志能看到:
- Mongo容器内部监听的是默认端口
27017 - API容器却尝试连接
2717端口
Docker容器间通信用容器内部端口,不是宿主机映射的端口。修改如下:
- 更新
.env文件,将DB_PORT改为Mongo容器内部默认端口:
DB_PORT=27017
- 调整
docker-compose.yml中Mongo的端口映射,把宿主机端口和容器端口区分开(比如宿主机用2717访问,容器内部还是27017):
ports: - '2717:27017'
2. 补充MongoDB认证信息
.env文件添加缺失的数据库用户名和密码:
DB_USER=root DB_PASS=your_secure_password
- 修正连接脚本中的MongoDB连接字符串,补充认证信息并指定认证源(root用户默认在
admin库下认证):
const url = `mongodb://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?authSource=admin`;
3. 确保数据库就绪后再启动API
depends_on仅保证启动顺序,不会等待数据库完全就绪。给Mongo服务添加健康检查,让API等数据库就绪后再启动:
- 更新
docker-compose.yml的mongo_db服务:
mongo_db: image: mongo:latest container_name: db_container restart: always ports: - '2717:27017' volumes: - mongo_db:/data/db environment: MONGO_INITDB_DATABASE: ${DB_NAME} MONGO_INITDB_ROOT_USERNAME: ${DB_USER} MONGO_INITDB_ROOT_PASSWORD: ${DB_PASS} healthcheck: test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] interval: 10s timeout: 5s retries: 5
- 更新
api服务的depends_on配置:
depends_on: mongo_db: condition: service_healthy
4. 可选:添加连接重试逻辑
在连接脚本中添加重试机制,避免因数据库启动慢导致的连接失败:
const connect = async () => { const url = `mongodb://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?authSource=admin`; logger.info("CONNECTION_STRING = " + url); const connectWithRetry = () => { mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true, }) .then(() => logger.info("Connected to database")) .catch(err => { logger.error("Connection failed, retrying in 5s...", err); setTimeout(connectWithRetry, 5000); }); }; connectWithRetry(); };
内容的提问来源于stack exchange,提问作者Vinícius Albino
相关产品推荐
相关产品推荐

