【问题标题】:Why does the docker-compose healthcheck of my mongo container always fail?为什么我的 mongo 容器的 docker-compose 健康检查总是失败?
【发布时间】:2019-01-27 00:21:56
【问题描述】:

我正在使用docker-compose 来建立一个 Express/React/Mongo 应用程序。我目前可以在 express 应用程序中使用重试逻辑来支持所有内容。但是,我更喜欢使用 Docker 的 healthcheck 来防止容器最初启动时出现一连串错误。但是,当我在 docker-compose.yml 中添加 healthcheck 时,它会在间隔/重试时间限制内挂起并退出:

ERROR: for collector  Container "70e7aae49c64" is unhealthy.

ERROR: for server  Container "70e7aae49c64" is unhealthy.
ERROR: Encountered errors while bringing up the project.

我的健康检查似乎永远不会返回健康状态,我也不完全确定原因。我的全部docker-compose.yml

version: "2.1"
services:
  mongo:
    image: mongo
    volumes:
      - ./data/mongodb/db:/data/db
    ports:
      - "${DB_PORT}:${DB_PORT}"
    healthcheck:
      test: echo 'db.runCommand("ping").ok' | mongo mongo:27017/test --quiet 1
      interval: 10s
      timeout: 10s
      retries: 5
  collector:
    build: ./collector/
    environment:
      - DB_HOST=${DB_HOST}
      - DB_PORT=${DB_PORT}
      - DB_NAME=${DB_NAME}
    volumes:
      - ./collector/:/app
    depends_on:
      mongo:
        condition: service_healthy
  server:
    build: .
    environment:
      - SERVER_PORT=$SERVER_PORT
    volumes:
      - ./server/:/app
    ports:
      - "${SERVER_PORT}:${SERVER_PORT}"
    depends_on:
      mongo:
        condition: service_healthy

对于test,我也试过了:

["CMD", "nc", "-z", "localhost", "27017"] 

还有:

["CMD", "bash", "/mongo-healthcheck"]

按照this guy 的建议,我也尝试完全放弃healthcheck。一切正常,但在成功连接之前,我在输出中得到了可怕的错误:

collector_1  | MongoDB connection error: MongoNetworkError: failed to connect to server [mongo:27017] on first connect [MongoNetworkError: connect 
ECONNREFUSED 172.21.0.2:27017]
collector_1  | MongoDB connection with retry
collector_1  | MongoDB connection error: MongoNetworkError: failed to connect to server [mongo:27017] on first connect

最终目标是在运行docker-compose up --build 时获得干净的启动输出。我还研究了this question 中的一些解决方案,但我对wait-for-it 的运气也不太好。在启动其他容器之前等待Mongo启动并运行并实现干净启动的正确方法是什么?

【问题讨论】:

    标签: mongodb docker docker-compose


    【解决方案1】:

    首先,我建议将 docker-compose.yaml 文件版本更新到至少 3.4 (version: "3.5"),然后请将 start_period 选项添加到您的 mongo healthcheck

    注意:start_period 仅支持 v3.4 及更高版本的 compose 文件格式。

    start period 为需要时间引导的容器提供初始化时间。在此期间探测失败将不计入最大重试次数。但是,如果在启动期间健康检查成功,则认为容器已启动,所有连续失败都将计入最大重试次数。

    所以它看起来像这样:

    healthcheck:
      test: echo 'db.runCommand("ping").ok' | mongo mongo:27017/test --quiet
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 40s
    

    【讨论】:

    • 我更喜欢更新的版本,但version 3 looses the condition option。这会有所作为吗?现在进行更改,我会及时通知您:)
    • +1 用于学习新事物,但这仍然使初创公司在 Express 应用程序中的重试逻辑中得到 MongoDB connection errors。不过,感谢您对此进行调查,如果您有任何其他想法,我愿意接受!
    • 试试:depends_on: ["mongo"]
    【解决方案2】:

    我们可以使用 MongoDB 的 serverStatus 命令来进行健康检查,正如 MongoDB 文档中所说的那样:

    监控应用程序可以定期运行此命令以收集有关实例的统计信息。

    因为serverStatus这个命令需要认证,所以你需要设置类似于下图的健康检查:

    version: '3.4'
    
    services:
      mongo:
        image: mongo
        restart: always
        healthcheck:
          test: echo 'db.runCommand({serverStatus:1}).ok' | mongo admin -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD --quiet | grep 1
          interval: 10s
          timeout: 10s
          retries: 3
          start_period: 20s
        environment:
          MONGO_INITDB_ROOT_USERNAME: root
          MONGO_INITDB_ROOT_PASSWORD: example
    
    

    就是这样。如果你的 MongoDB 实例是健康的,你会看到类似于我的:

    $ docker ps
    CONTAINER ID  IMAGE  COMMAND                 CREATED         STATUS                   PORTS      NAMES
    01ed0e02aa70  mongo  "docker-entrypoint.s…"  11 minutes ago  Up 11 minutes (healthy)  27017/tcp  demo_mongo_1
    

    【讨论】:

      【解决方案3】:

      我在这里找到了解决方案 https://github.com/docker-library/healthcheck/tree/master/mongo

      注意,它解释了为什么健康检查不包含在官方图像中 https://github.com/docker-library/cassandra/pull/76#issuecomment-246054271

      docker-healthcheck

      #!/bin/bash
      set -eo pipefail
      
      if mongo --quiet "localhost/test" --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)'; then
          exit 0
      fi
      
      exit 1
      

      在链接的示例中,他们使用 host 变量

      host="$(hostname --ip-address || echo '127.0.0.1')"
      
      if mongo --quiet "$host/test" --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)'; then
      # continues the same code
      

      它对我不起作用,所以我将 host 替换为 localhost

      docker-compose

      mongo:
        build:
          context: "./mongodb"
          dockerfile: Dockerfile
        container_name: crm-mongo
        restart: always
        healthcheck:
          test:  ["CMD", "docker-healthcheck"]
          interval: 10s
          timeout: 2s
          retries: 10
      

      或者,您可以在容器中执行健康检查。更改 Dockerfile 或那个。

      FROM mongo:4
      
      ADD docker-healthcheck /usr/local/bin/
      

      【讨论】:

        【解决方案4】:

        当我在docker容器中执行echo db.runCommand("ping").ok' | mongo localhost:27017/test --quiet 1命令时,结果是:

            2019-04-19T02:39:19.770+0000 E -        [main] file [1] doesn't exist
            failed to load: 1
        

        试试这个

        healthcheck:
          test: bash -c "if mongo --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)'; then exit 0; fi; exit 1;"
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-09-07
          • 2020-03-01
          • 1970-01-01
          • 2020-11-16
          • 2019-05-11
          • 2022-10-14
          • 2016-12-27
          • 2019-05-05
          相关资源
          最近更新 更多