docker-compose使用mongo官方镜像时服务名同名引发连接报错问题
问题描述
参考mongo官方镜像使用说明,尝试通过docker-compose部署mongo及mongo-express服务时,遇到服务名疑似不能与镜像名同名的异常,复现流程如下:
- 编写如下内容的
docker-compose.yml配置文件:
version: '3.1' services: mongo: 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_ADMINUSERNAME: root ME_CONFIG_MONGODB_ADMINPASSWORD: example ME_CONFIG_MONGODB_URL: mongodb://root:example@mongo:27017/
- 执行如下命令启动服务:
docker-compose -f docker-compose.yml up
启动后出现如下报错:
Could not connect to database using connectionString: mongodb://root:example@mongo:27017/" mongo-express_1 | (node:8) UnhandledPromiseRejectionWarning: MongoNetworkError: failed to connect to server [mongo:27017] on first connect [MongoError: Authentication failed. mongo-express_1 | at Connection.messageHandler (/node_modules/mongodb/lib/core/connection/connection.js:364:19) mongo-express_1 | at Connection.emit (events.js:314:20)
将mongo服务名从mongo修改为myMongo,同步修改ME_CONFIG_MONGODB_URL连接串中的对应服务地址后,服务即可正常运行,修改后的配置如下:
version: '3.1' services: myMongo: 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_ADMINUSERNAME: root ME_CONFIG_MONGODB_ADMINPASSWORD: example ME_CONFIG_MONGODB_URL: mongodb://root:example@myMongo:27017/
问题原因
这个现象和「服务名不能与镜像名同名」没有任何关系,是MongoDB镜像初始化规则+docker-compose持久化逻辑共同导致的巧合,核心问题点如下:
- MongoDB初始化账号的触发条件极其严格
mongo官方镜像提供的MONGO_INITDB_ROOT_USERNAME、MONGO_INITDB_ROOT_PASSWORD环境变量,仅在容器对应的数据目录完全为空、第一次启动时才会生效,作用是初始化管理员账号。只要数据目录下已经存在数据库文件,后续无论怎么修改这两个环境变量、重启多少次容器,都不会再重复执行账号创建逻辑。 - 首次启动失败留下了无效的持久化数据
第一次用服务名mongo启动时,大概率遇到了启动时序问题:mongo还没完成管理员账号初始化,mongo-express就提前发起了连接,直接触发认证失败报错。此时mongo已经在docker-compose自动创建的匿名数据卷(命名规则为当前目录名_mongo)里写入了未配置管理员账号的数据库文件,后续你反复重启服务,mongo检测到数据目录非空,就不会再创建root账号,自然一直报认证失败。 - 改服务名后正常是因为触发了全新初始化
把服务名改成myMongo之后,docker-compose会为新服务名分配独立的网络别名、创建全新的匿名数据卷(命名为当前目录名_myMongo)。此时mongo启动检测到新数据卷是空的,就正常执行了root账号创建流程,所以连接直接成功——本质和服务名是否与镜像重名没有任何关联。
修复方案
你完全可以把服务名改回mongo,按以下步骤操作即可正常运行:
- 先执行
docker-compose down -v命令,删除当前项目关联的所有容器和持久化数据卷(注意:该操作会清空现有MongoDB中的所有数据,生产环境操作前请提前备份) - 修改连接串补充认证源参数,将
ME_CONFIG_MONGODB_URL的值改为mongodb://root:example@mongo:27017/?authSource=admin,避免MongoDB校验账号时默认到非admin库查找用户导致认证失败 - 可以在mongo-express服务下添加依赖配置,减少启动时序问题导致的连接报错:
depends_on: - mongo
- 重新执行
docker-compose up -d启动即可,服务名使用mongo完全可以正常运行。
内容的提问来源于stack exchange,提问作者Anoman.M
相关产品推荐
相关产品推荐

