问题的起因是,在阿里云的ECS上尝试部署Egg的项目的,但是一直报
ERROR 449 nodejs.SequelizeAccessDeniedError: Access denied for user 'root'@'localhost' (using password: YES)
[egg-scripts] at Utils.Promise.tap.then.catch.err (/home/egg/hc_user/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:141:19)
[egg-scripts] at tryCatcher (/home/egg/hc_user/node_modules/bluebird/js/release/util.js:16:23)
[egg-scripts] at Promise._settlePromiseFromHandler (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:512:31)
[egg-scripts] at Promise._settlePromise (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:569:18)
[egg-scripts] at Promise._settlePromise0 (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:614:10)
[egg-scripts] at Promise._settlePromises (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:690:18)
[egg-scripts] at _drainQueueStep (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:138:12)
[egg-scripts] at _drainQueue (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:131:9)
[egg-scripts] at Async._drainQueues (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:147:5)
[egg-scripts] at Immediate.Async.drainQueues [as _onImmediate] (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:17:14)
[egg-scripts] at runCallback (timers.js:693:18)
[egg-scripts] at tryOnImmediate (timers.js:664:5)
[egg-scripts] at processImmediate (timers.js:646:5)
[egg-scripts] name: "SequelizeAccessDeniedError"
[egg-scripts] parent: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
[egg-scripts] original: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
数据库是阿里云的RDS Mysql,已开白名单,在ECS上尝试过ping RDS 的链接,可以ping通。 尝试过在RDS多加一个testuser的用户,配置上testuser的账号密码后,还是报一样的错误。如果 user 改变了 ‘root’@‘localhost’ 这里应该会变成’testuser’@‘localhost’ 的吧? config.prod.js 的配置如下
'use strict';
module.exports = () => {
const config = exports = {};
// change to your own sequelize configurations
config.sequelize = {
dialect: 'mysql',
port: 3306,
hostname: '2123123123123123.mysql.rds.aliyuncs.com',
database: 'test',
user: 'testuser',
password: '12123123123',
define: {
underscored: false,
},
};
return config;
};
config.default.js 中没有sequelize 的配置,config.local.js 中的sequelize 配置也改成和config.prod.js 问题一样。 数据库的账号密码也在dms-rds.aliyun.com/main.do 上试过登陆,是没有问题的。 因为这个ECS 是用来测试的,所以内部也安装了一个mysql。 目前不清楚到底项目是按那个配置在运行,链接的mysql是那个,用那个账号密码来链接。 ECS上部署的项目 是用
egg-scripts start --daemon
来运行的,同样也有试过
EGG_SERVER_ENV=prod egg-scripts start --daemon
// 或者
export NODE_ENV=production && egg-scripts start --daemon
问题一样。
为了了解项目的目前情况,加了一个app.js 的文件
'use strict';
class AppBootHook {
constructor(app) {
console.log('\x1B[31m%s\x1b[0m:', `constructor... app: ${JSON.stringify(app)}`);
app.beforeStart(() => {
app.logger.info('\x1B[31m%s\x1b[0m:', `constructor beforeStart app.config.env: ${app.config.env}, process.env.NODE_ENV: ${process.env.NODE_ENV}`);
});
app.ready((...a) => {
app.logger.info('\x1B[31m%s\x1b[0m:', `constructor ready... a: ${JSON.stringify(a)}`);
});
app.beforeClose((...a) => {
app.logger.info('\x1B[31m%s\x1b[0m:', `constructor beforeClose... a: ${JSON.stringify(a)}`);
});
app.once('server', server => {
// websocket
app.logger.info('\x1B[31m%s\x1b[0m:', `constructor once('server')... server: ${JSON.stringify(server)}`);
});
app.on('error', (err, ctx) => {
// report error
app.logger.info('\x1B[31m%s\x1b[0m:', `constructor on('error')... ctx: ${JSON.stringify(ctx)} , err: ${JSON.stringify(err)}`);
});
app.on('request', ctx => {
// log receive request
app.logger.info('\x1B[31m%s\x1b[0m:', `constructor on('request')... ctx: ${JSON.stringify(ctx)}`);
});
app.on('response', ctx => {
// ctx.starttime is set by framework
const used = Date.now() - ctx.starttime;
app.logger.info('\x1B[31m%s\x1b[0m:', `constructor on('response')... ctx: ${JSON.stringify(ctx)}, used: ${used}`);
// log total cost
});
}
async beforeStart(...a) {
console.log('\x1B[31m%s\x1b[0m:', `beforeStart... a: ${JSON.stringify(a)}`);
}
async ready(...a) {
console.log('\x1B[31m%s\x1b[0m:', `ready... a: ${JSON.stringify(a)}`);
}
configDidLoad(...a) {
// Config,plugin files have did load.
console.log('\x1B[31m%s\x1b[0m:', `configDidLoad... a: ${JSON.stringify(a)}`);
}
async didLoad(...a) {
// All files have did load, start plugin here.
console.log('\x1B[31m%s\x1b[0m:', `didLoad... a: ${JSON.stringify(a)}`);
}
async willReady(...a) {
// All plugins have started, can do some thing before app ready
console.log('\x1B[31m%s\x1b[0m:', `willReady... a: ${JSON.stringify(a)}`);
}
async didReady(...a) {
// Worker is ready, can do some things
// don't need to block the app boot.
console.log('\x1B[31m%s\x1b[0m:', `didReady... a: ${JSON.stringify(a)}`);
}
async serverDidReady(...a) {
// Server is listening.
console.log('\x1B[31m%s\x1b[0m:', `serverDidReady... a: ${JSON.stringify(a)}`);
}
async beforeClose(...a) {
// Do some thing before app close.
console.log('\x1B[31m%s\x1b[0m:', `beforeClose... a: ${JSON.stringify(a)}`);
}
}
module.exports = AppBootHook;
在本地 egg-bin dev 的时候输出的是
在ECS上 运行 egg-scripts start --daemon 的时候
> egg-scripts start --daemon
[egg-scripts] Starting egg application at /home/egg/hc_user
[egg-scripts] Run node /home/egg/hc_user/node_modules/egg-scripts/lib/start-cluster {"title":"egg-server-hc_user","framework":"/home/egg/hc_user/node_modules/egg","baseDir":"/home/egg/hc_user"} --title=egg-server-hc_user
[egg-scripts] Save log file to /root/logs
[egg-scripts] Wait Start: 1...
[egg-scripts] Wait Start: 2...
[egg-scripts] tail -n 100 /root/logs/master-stderr.log
[egg-scripts] Got error when startup:
[egg-scripts] 2018-10-12 10:38:39,134 ERROR 449 nodejs.SequelizeAccessDeniedError: Access denied for user 'root'@'localhost' (using password: YES)
[egg-scripts] at Utils.Promise.tap.then.catch.err (/home/egg/hc_user/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:141:19)
[egg-scripts] at tryCatcher (/home/egg/hc_user/node_modules/bluebird/js/release/util.js:16:23)
[egg-scripts] at Promise._settlePromiseFromHandler (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:512:31)
[egg-scripts] at Promise._settlePromise (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:569:18)
[egg-scripts] at Promise._settlePromise0 (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:614:10)
[egg-scripts] at Promise._settlePromises (/home/egg/hc_user/node_modules/bluebird/js/release/promise.js:690:18)
[egg-scripts] at _drainQueueStep (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:138:12)
[egg-scripts] at _drainQueue (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:131:9)
[egg-scripts] at Async._drainQueues (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:147:5)
[egg-scripts] at Immediate.Async.drainQueues [as _onImmediate] (/home/egg/hc_user/node_modules/bluebird/js/release/async.js:17:14)
[egg-scripts] at runCallback (timers.js:693:18)
[egg-scripts] at tryOnImmediate (timers.js:664:5)
[egg-scripts] at processImmediate (timers.js:646:5)
[egg-scripts] name: "SequelizeAccessDeniedError"
[egg-scripts] parent: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
[egg-scripts] original: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
还没有加载到app.js 的感觉。 请问,要怎样去解决这个问题? egg.js 的生命周期方法,有在egg-sequelize测试数据库链接前的方法吗?
你本地远程连接你的mysql可以成功吗?
目前不清楚到底项目是按那个配置在运行,链接的mysql是那个,用那个账号密码来链接。
用 egg-scripts 启动的话是 prod,不用加环境变量。
你可以看下启动后的 run/application_config.json
里面的配置,这个是 dump 出来的最终合并配置(仅查看)
@wang-weifeng 其他框架的项目可以
@atian25 弱弱地问,如果在启动时都会把这些变量都输出一下,会不会更好?我们菜鸟的项目基本都会这样做,不知道大神们是怎么看。
@thomas0836 都输出到 run/application_config.json
了啊
@atian25 请问,有一些更详细的关于部署的推荐文档吗?基本上都不怎么看到有类似的手把手教程,对于初级运维来说,很痛苦呢。 之前的项目基本都是上传到git,然后服务器装个git,来下载然后安装依赖。再pm2用export NODE_ENV=development 来运行。 看了eggjs后才知道原来是要本地打包,整个连依赖一起上传到服务器。但是按照eggjs上的教程,有几个小问题。例如在本地开发时.gitgnore 上配置的一些不需要上传的内容,都全部在压缩包里面了吧?难道是需要开一个新的目录在本机用git再重新下载,再按照发布的来安装依赖,再压缩打包,再上传? 想请教一下其他的专业团队是如何部署的。希望有大神可以分享一下
谢谢 @atian25, 查了 服务器上 run/application_config.json
"sequelize": {
"dialect": "mysql",
"database": "test",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "<String len: 12>",
"hostname": "127.0.0.1",
"define": {
"underscored": false
}
},
想了解一下,这个文件是在本地 npm install --production 的时候生成的,还是说在ECS 上解压后 运行 egg-scripts start --daemon 再生成?
@thomas0836 一般做法是:
ci 机器上, git clone,安装依赖,打包,上传。
=.= run 的时候生成的
egg-bin 启动是 dev egg-script 启动是 prod 没毛病啊。看来还是文档读少了。
@MiYogurt 谢谢,刚刚测试也测试到了,把ECS上的run文件夹删除了,然后再运行
EGG_SERVER_ENV=prod egg-scripts start --daemon
// 或者
export NODE_ENV=production && egg-scripts start --daemon
发现是会自动生成 run/application_config.json 但是 情况还是一样。明显是development时的数据库配置,而不是发布的配置。
我也再检查过这个 数据库名在整个项目中只出现过3次,一次在config.local.js , 一次在 /database/config.json ,最后一次是在/run/application_config.json /database/config.json 中也确认是在development 内,而不是在 production 内。
请问 我这里的运行命令是不是错了?@atian25
不需要加任何变量,就是 egg-scripts start
肯定是会加载 config.prod.js
和 config.default.js
/run/application_config.json
我在上面已经说了,它就是启动期 dump 的一个供排查用的日志,代表最终配置合并的结果。
/database/config.json
这玩意不知道哪来的,检查下你自己的代码吧。
另外,建议再去看看 配置 那一章文档。
谢谢 @atian25 建了一个最少复现仓库了 https://github.com/ThomasLiu/egg_RESTfulAPI_mysql 希望可以获得你们的优化建议。
至于 /database/config.json 是 https://eggjs.org/zh-cn/tutorials/sequelize.html 内提到的Migrations 用的。
@thomas0836 Good Job~
现在的问题是什么?
@atian25 就是按照部署那章在ECS 上部署的时候,config.prod.js 的数据库配置不能正常的合并到 /run/application_config.json 里面,使用的命令有
egg-scripts start
// 或者
EGG_SERVER_ENV=prod egg-scripts start --daemon
// 或者
export NODE_ENV=production && egg-scripts start --daemon
你本地同样命令呢?
@atian25 我在新开出来的那个仓库刚才再试了一下,直接用 egg-scripts start 运行,可以成功合并到 /run/application_config.json 里面了,但是还是提示
Got error when startup:
[egg-scripts] 2018-10-13 17:31:21,183 ERROR 11148 nodejs.SequelizeAccessDeniedError: Access denied for user 'root'@'localhost' (using password: YES)
[egg-scripts] at Utils.Promise.tap.then.catch.err (/home/egg/egg_RESTfulAPI_mysql/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:141:19)
[egg-scripts] at tryCatcher (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/util.js:16:23)
[egg-scripts] at Promise._settlePromiseFromHandler (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:512:31)
[egg-scripts] at Promise._settlePromise (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:569:18)
[egg-scripts] at Promise._settlePromise0 (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:614:10)
[egg-scripts] at Promise._settlePromises (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/promise.js:690:18)
[egg-scripts] at _drainQueueStep (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:138:12)
[egg-scripts] at _drainQueue (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:131:9)
[egg-scripts] at Async._drainQueues (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:147:5)
[egg-scripts] at Immediate.Async.drainQueues [as _onImmediate] (/home/egg/egg_RESTfulAPI_mysql/node_modules/bluebird/js/release/async.js:17:14)
[egg-scripts] at runCallback (timers.js:693:18)
[egg-scripts] at tryOnImmediate (timers.js:664:5)
[egg-scripts] at processImmediate (timers.js:646:5)
[egg-scripts] name: "SequelizeAccessDeniedError"
[egg-scripts] parent: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
[egg-scripts] original: {"code":"ER_ACCESS_DENIED_ERROR","errno":1045,"sqlState":"28000","sqlMessage":"Access denied for user 'root'@'localhost' (using password: YES)"}
我再去看看那个数据库配置和数据库那边的账号密码,再仔细过一次吧
@atian25 @wang-weifeng @MiYogurt 谢谢,问题已解决,原因是config.prod.js 文件内由于sequelize 的版本问题。 以前用的hostname 换成了host, user 换成了 username。在本地开发的时候这两个参数也是写错的,因为刚好也是用root和127.0.0.1,所以问题没有暴露出来。