Sequelize 无法从 Node/express 应用程序同步到 docker 容器中的 MySQL (ECONNREFUSED)

Posted

技术标签:

【中文标题】Sequelize 无法从 Node/express 应用程序同步到 docker 容器中的 MySQL (ECONNREFUSED)【英文标题】:Sequelize cannot sync to MySQL in a docker container from Node/express app (ECONNREFUSED) 【发布时间】:2019-07-05 10:57:21 【问题描述】:

我是第一次同时使用sequelize、mysql和docker,无法让sequelize连接到数据库。

我已经使用 DBeaver 测试了数据库的存在,并且可以连接。当我通过 DBeaver 连接时,我还可以看到 MySQL 容器在终端中响应。但是,在尝试连接代码时,我收到 ECONNREFUSED 错误。

我已使用 sequelize 文档检查了我的代码并仔细检查了端口设置,但似乎看不出我哪里出错了。

在下面提供正确答案后,我注意到我有一个错误。我错过了 docker-compose.yml 文件中“mysql”容器中的以下内容。

networks:
    - app-tier

为了避免要求其他用户阅读答案中的 cmets 来发现这一点,我已将此添加到 docker-compose.yml 文件中,以便现在问题和答案更清晰地对齐

docker-compose.yml 文件:

version: '3'

networks:
    app-tier:
        driver: bridge
services:
    server:
        image: bitnami/node
        networks:
        - app-tier
        command: "sh -c 'npm install && npm run dev'"
        volumes:
        - ./server:/app
        ports:
        - 5000:5000
        depends_on:
        - mysql
    mysql:
        image: 'bitnami/mysql:latest'
        environment:
        - MYSQL_USER=root
        - MYSQL_PASSWORD=password
        - MYSQL_ROOT_PASSWORD=password
        - MYSQL_DATABASE=school
        networks:
            - app-tier
        ports:
        - '3306:3306'
        volumes:
        - ./db:/bitnami/mysql/data

续集连接:

const Sequelize = require('sequelize');

const sequelize = new Sequelize('school', 'root', 'password', 
dialect: 'mysql'
);

module.exports = sequelize;

尝试从 app.js 同步:

sequelize.sync()
    .then(result => console.log(result))
    .catch(err => console.log('EEEERRRROOOOOOR',err));

终端输出:

server_1    |   SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306
server_1    |     at Utils.Promise.tap.then.catch.err (/app/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:139:19)
server_1    |     at tryCatcher (/app/node_modules/bluebird/js/release/util.js:16:23)
server_1    |     at Promise._settlePromiseFromHandler (/app/node_modules/bluebird/js/release/promise.js:512:31)
server_1    |     at Promise._settlePromise (/app/node_modules/bluebird/js/release/promise.js:569:18)
server_1    |     at Promise._settlePromise0 (/app/node_modules/bluebird/js/release/promise.js:614:10)
server_1    |     at Promise._settlePromises (/app/node_modules/bluebird/js/release/promise.js:689:18)
server_1    |     at Async._drainQueue (/app/node_modules/bluebird/js/release/async.js:133:16)
server_1    |     at Async._drainQueues (/app/node_modules/bluebird/js/release/async.js:143:10)
server_1    |     at Immediate.Async.drainQueues (/app/node_modules/bluebird/js/release/async.js:17:14)
server_1    |     at runCallback (timers.js:810:20)
server_1    |     at tryOnImmediate (timers.js:768:5)
server_1    |     at processImmediate [as _immediateCallback] (timers.js:745:5)
server_1    |   name: 'SequelizeConnectionRefusedError',
server_1    |   parent:
server_1    |     Error: connect ECONNREFUSED 127.0.0.1:3306
server_1    |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1191:14)
server_1    |      errno: 'ECONNREFUSED',
server_1    |      code: 'ECONNREFUSED',
server_1    |      syscall: 'connect',
server_1    |      address: '127.0.0.1',
server_1    |      port: 3306,
server_1    |      fatal: true ,
server_1    |   original:
server_1    |     Error: connect ECONNREFUSED 127.0.0.1:3306
server_1    |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1191:14)
server_1    |      errno: 'ECONNREFUSED',
server_1    |      code: 'ECONNREFUSED',
server_1    |      syscall: 'connect',
server_1    |      address: '127.0.0.1',
server_1    |      port: 3306,
server_1    |      fatal: true  

【问题讨论】:

【参考方案1】:

要从 docker 容器连接到您的 mysql 服务器,您需要传递正确的服务地址。所以你的初始化应该是这样的。

const Sequelize = require('sequelize');

const sequelize = new Sequelize('school', 'root', 'password', 
host: 'mysql',
dialect: 'mysql'
);

module.exports = sequelize;

【讨论】:

谢谢。错误现在从 ECONNREFUSED 更改为 ETIMEDOUT。我以为 docker 将主机映射到 localhost 没有? 如果你暴露端口,它会映射到你的机器本地主机,但在容器内部它有自己的地址。所以现在你得到ETIMEDOUT 因为mysql 还没有准备好接收连接。 depend_on 正在等待容器何时启动,而不是在完成设置时。所以你需要在mysql准备好时添加你的应用程序检查 好的,你当然是对的。重新检查了我的 docker 文件后,我错过了网络: - app-tier 我忘记将它添加到命名网络,因此它在第一次修复时不起作用。感谢您的帮助! 哦,我看到您的app-tier 在第一个服务中声明,我认为它也在mysql 服务中声明以共享网络。很好,你解决了这个问题!【参考方案2】:

正在进行中 我正在与类似的问题作斗争,这是我的静态寻址步骤:

networks:
  internal_UJJigBWx:
    driver: bridge
    ipam:
      config:
      - subnet: 172.16.238.0/24
      driver: default
services:
  express:
    build:
      context: .
    depends_on:
    - sql
    environment:
      DB_DATABASE: sequebase
      DB_DIALECT: mysql
      DB_HOST: 172.16.238.2
      DB_PASSWORD: sequeword
      DB_USERNAME: sequeuser
    networks:
      internal_UJJigBWx:
        ipv4_address: 172.16.238.3
    ports:
    - 80:3000/tcp
  sql:
    environment:
      MYSQL_DATABASE: sequebase
      MYSQL_PASSWORD: sequeword
      MYSQL_RANDOM_ROOT_PASSWORD: "yes"
      MYSQL_USER: sequeuser
    image: bitnami/mysql:latest
    networks:
      internal_UJJigBWx:
        ipv4_address: 172.16.238.2
version: '3.0'

主要区别在于 ipam 的静态寻址。 您可以使用docker-compose config 来检查和查看环境扩展。

我在构建阶段使用 gulp 任务来调用 sequelize sync。它在本地运行良好,但我不确定是否是 docker compose 的好方法

构建映像过程使用args 而不是environment。 并且该阶段似乎发生在数据库启动之前。不知道怎么等sql同步sequelize...

【讨论】:

以上是关于Sequelize 无法从 Node/express 应用程序同步到 docker 容器中的 MySQL (ECONNREFUSED)的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 sequelize 从本地节点应用程序连接到 heroku postgresql 数据库

Sequelize,GraphJS:无法读取 null 的属性“2”

Angular:无法导入 Sequelize

sequelize-typescript:模型中get()的通用方法

Sequelize 迁移失败,无法读取未定义的属性“toString”[关闭]

Sequelize:无法连接到 SQL Server - 传递的端口不正确