Docker部署环境下连接MongoDB出现storeKey不匹配认证失败问题排查
我帮你分析下这个问题,这种storedKey mismatch的SCRAM认证失败情况我遇到过好几次,结合你的配置和日志来看,主要是这几个核心原因导致的:
1. MongoDB初始化脚本没真正执行(数据卷缓存坑)
MongoDB容器的docker-entrypoint-initdb.d目录下的脚本只会在第一次启动、且数据卷为空的时候执行一次。如果你的./mongo-volume数据卷之前已经创建过(比如之前启动过Mongo容器),哪怕你修改了mongo-init.js或者环境变量里的密码,新的初始化逻辑也不会重新运行——数据库里还是旧的用户数据,自然和你当前输入的密码不匹配,就会抛出认证失败的错误。
解决步骤:
先彻底清除旧的数据卷,重新初始化数据库:
# 停止容器并删除关联的数据卷 docker-compose down -v # 重新构建并启动容器 docker-compose up --build
-v参数会删掉所有和当前compose关联的卷,包括你的./mongo-volume,这样Mongo会从头开始初始化,执行你的mongo-init.js脚本创建正确的用户。
2. 初始化脚本的数据库切换逻辑错误
你的mongo-init.js里有个容易忽略的问题:默认执行脚本时,Mongo的当前数据库是test,而你用db.auth("some_user", "some_password")是在test库尝试认证root用户——但root用户是在admin库创建的啊!这一步其实会失败,只是因为旧数据卷里有用户,所以后续创建用户的逻辑可能没按预期跑。另外,你创建的user用户默认会存在test库,而不是你需要的dbname库,这就导致连接时指定authSource=admin根本找不到这个用户。
修正后的mongo-init.js:
// 先切换到admin库,用root用户认证 use admin; db.auth("some_user", "some_password"); // 切换到目标数据库dbname,在该库下创建业务用户 use dbname; db.createUser( { user: "user", pwd: "password", roles: [ { role: "readWrite", db: "dbname" } ] } );
这样user用户就会被创建在dbname库中,接下来要对应调整连接URL的authSource配置。
3. 连接URL的authSource和用户存储库不匹配
如果你的user用户是创建在dbname库(用上面修正后的脚本),那连接URL里的authSource应该改成dbname,而不是admin——否则Mongo会去admin库找这个用户,自然找不到。
修正Node.js的连接URL代码:
_getConnectionUrl() { const { DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASS } = process.env; // authSource改为目标数据库DB_NAME return `mongodb://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?authSource=${DB_NAME}`; }
如果你希望用户存在于admin库(方便统一管理),那就在初始化脚本里直接在admin库创建用户:
use admin; db.auth("some_user", "some_password"); db.createUser( { user: "user", pwd: "password", roles: [ { role: "readWrite", db: "dbname" } ] } );
这种情况下,原来的authSource=admin是正确的,不需要修改连接URL。
4. 最后排查:环境变量是否真的传递正确
虽然你说配置是对的,但保险起见可以验证下Node容器里的环境变量:
# 进入server容器 docker exec -it server bash # 打印DB_USER和DB_PASS echo $DB_USER $DB_PASS
确认输出的内容和mongo-init.js里的用户名密码完全一致,避免复制粘贴或者拼写错误。
内容的提问来源于stack exchange,提问作者cfrancklin

