【问题标题】:How do I connect my mongo database to my node app with this mongoDB connection string using docker-compose?如何使用 docker-compose 使用这个 mongoDB 连接字符串将我的 mongo 数据库连接到我的节点应用程序?
【发布时间】:2020-06-07 02:39:17
【问题描述】:

这是我的节点应用程序的一部分

app.configure('development', function() {
  app.set('db-uri', 'mongodb://localhost/nodepad-development');
  app.use(express.errorHandler({ dumpExceptions: true }));
  app.set('view options', {
    pretty: true
  });
});

app.configure('test', function() {
  app.set('db-uri', 'mongodb://localhost/nodepad-test');
  app.set('view options', {
    pretty: true
  });  
});

app.configure('production', function() {
  app.set('db-uri', 'mongodb://localhost/nodepad-production');
});

编辑为

app.set('db-uri', 'mongodb://mongoDB:27017/nodepad-development');

还是同样的错误。 我已经为在本地主机上运行的节点应用程序创建了容器,但我无法将其连接到另一个 mongo 容器,因此我无法向应用程序发出 POST 请求。

这是我的 docker compose 文件

version: '3'
services:
  apptest:
    container_name: apptest
    restart: always
    image: ekamzf/nodeapp:1.1
    ports:
      - '8080:8080
    depends_on:
          - mongoDB

  mongoDB:
    container_name: mongoDB
    image: mongo
    volumes:
      - ./data:/usr/src/app
    ports:
      - '27017:27017'  

当我尝试在我的节点应用程序中注册帐户详细信息时遇到的错误是

Error: Timeout POST /users
    at null._onTimeout (/usr/src/app/node_modules/connect-timeout/index.js:12:22)
    at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

我错过了什么? 基本上,我应该如何将这种类型的代码与 mongodb 连接起来? 'db-uri' 的作用是什么?

【问题讨论】:

    标签: node.js mongodb docker docker-compose database-connection


    【解决方案1】:

    Docker Compose 将服务名别名为主机名。

    因为您将运行mongo 映像的容器命名为mongoDB,所以mongodb(不区分大小写)将是主机的名称以及您应该从Node.JS 容器中引用它的名称,并且应用程序。

    1. 将 URI 中的 localhost 替换为 mongodb

    MongoDB 数据库默认使用端口 27017。除非您更改了端口,否则应指定此值。

    1. 将端口添加到 URI,以便您拥有 mongodb:27017

    2. 可选但good practice,重构应用程序以使用环境变量而不是硬编码值。

    这至少有两个好处:

    一个。您的代码变得更加灵活; 湾。然后指定这些值,您的 Compose 文件会更清晰。

    请参阅 DockerHub 文档以获取映像 here

    请参阅 MongoDB 关于连接字符串的文档here

    使用 Compose、MongoDB 和 Node.JS 的 Google 搜索返回 many examples

    更新:重现

    我相信您的问题可能与 Compose 容器的时间有关。我相信您的应用程序会在数据库容器准备好之前尝试连接到数据库。这是 Compose 的一个常见问题,使用 Compose 的depends_on 解决了。相反,您必须找到一个 MongoDB(或者可能是其他数据库)解决方案。

    在我的重现中,index.js(见下文)在尝试连接到数据库之前引入了错误的延迟。 5 秒时间足以让 DB 容器准备就绪,因此这是可行的:

    docker-compose build --no-cache
    docker-compose up
    

    然后:

    docker-compose logs app
    Attaching to 60359441_app_1
    app_1            | URL: mongodb://mongodb:27017/example
    app_1            | Connected
    

    产生Connected,这很好。

    或者,为了证明时间问题,您可以单独运行容器(您可以删除sleep 函数以确保数据库在应用程序之前准备好:

    HOST=localhost  # No DNS naming
    PORT=37017      # An arbitrary port to prove the point
    
    # In one session
    docker run \
    --interactive --tty --rm \
    --publish=${PORT}:27017 \
    mongo
    
    # In another session
    docker run \
    --interactive --tty --rm \
    --net=host \
    --env=HOST=${HOST} --env=PORT=${PORT} --env=DATA=example --env=WAIT=0 \
    app
    URL: mongodb://localhost:37017/example
    Connected
    

    docker-compose.yaml:

    version: "3"
    
    services:
      app:
        image: app
        build:
          context: ./app
          dockerfile: Dockerfile
        environment:
          - HOST=mongodb
          - PORT=27017
          - DATA=example
          - WAIT=5000
        volumes:
          - ${PWD}/app:/app
    
      mongodb:
        image: mongo
        restart: always
        # environment:
        #   MONGO_INITDB_ROOT_USERNAME: root
        #   MONGO_INITDB_ROOT_PASSWORD: example
    
      mongo-express:
        image: mongo-express
        restart: always
        ports:
          - 8081:8081
        environment:
          ME_CONFIG_MONGODB_SERVER: mongodb
          # ME_CONFIG_MONGODB_ADMINUSERNAME: root
          # ME_CONFIG_MONGODB_ADMINPASSWORD: example
    

    注意因为我按照你的mongodb命名,所以mongo-express容器必须通过ME_CONFIG_MONGODB_SERVER提供这个主机名

    NBmongomongo-express 图像一起显示的其他环境变量是默认值,因此是可选的。

    Dockerfile:

    FROM node:13.8.0-slim
    
    WORKDIR /usr/src/app
    
    COPY package.json .
    RUN npm install
    
    COPY . .
    
    ENTRYPOINT ["node","index.js"]
    

    index.js:

    // Obtain config from the environment
    const HOST = process.env.HOST;
    const PORT = process.env.PORT;
    const DATA = process.env.DATA;
    const WAIT = parseInt(process.env.WAIT, 10);
    
    // Create MongoDB client
    var MongoClient = require("mongodb").MongoClient;
    
    let url = `mongodb://${HOST}:${PORT}/${DATA}`;
    console.log(`URL: ${url}`);
    
    // Artificially delay the code
    setTimeout(function() {
      MongoClient.connect(url, function(err, db) {
        if(!err) {
          console.log("Connected");
        }
      });
    }, WAIT);
    

    NB index.js 使用环境 (HOST,PORT,DB) 进行配置,这是一种很好的做法。

    包含mongo-express 提供了浏览mongo 服务器的能力,以便随时观察正在发生的事情:

    【讨论】:

    • 是的,我确实将 localhost 更改为 mongoDB:27017。仍然存在相同的错误。
    • 可能是(!)您的 Node.JS 在准备好之前尝试访问 MongoDB 服务。这是 Compose 的常见问题。 Node.JS 容器准备就绪,尝试访问数据库,但数据库(尚)不可用,代码退出。在 Google 上搜索 MongoDB 和 Docker Compose,然后等待。
    • 见:docs.docker.com/compose/startup-order。我不熟悉 MongoDB,但这可能是一个红鲱鱼,但如果您确信您的代码和 Compose 在其他方面都很好,那么值得一试。您可以通过在 compose 之外运行 MongoDB 容器来证明这一点,一旦准备就绪,您也可以在容器中启动您的应用程序。不要忘记重命名主机并使用--net=host 等。
    • 我认为你关于我的 mongo 容器准备就绪的观点是正确的。我现在所做的作为 pod 部署在 kubernetes 上,现在两者都在运行和监听各自的服务,但我遇到了问题,我应该在我的 nodeapp 容器的“ENV”块中提及什么?因为我的连接字符串没有使用环境变量,我不想弄乱代码。
    • 借助 Kubernetes,您可以更好地控制部署时间,以便在部署节点应用程序之前知道您的数据库服务正在运行。如果您没有在节点应用程序中使用环境变量,那么您的 YAML 规范中不需要 env 块。显然,您需要将 MongoDB 的主机名替换为 Kubernetes 服务名。
    猜你喜欢
    • 1970-01-01
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 2019-11-08
    • 2019-11-04
    相关资源
    最近更新 更多