【问题标题】:Docker - SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306Docker - SequelizeConnectionRefusedError:连接 ECONNREFUSED 127.0.0.1:3306
【发布时间】:2019-05-28 01:21:58
【问题描述】:

我正在尝试使用 docker 容器启动并运行我的 nodejs 应用程序。我不知道可能出了什么问题。当我使用控制台调试凭据时,凭据似乎已正确传递。启动 sequel pro 并使用相同的用户名和密码直接连接似乎也可以。当节点在容器中启动时,我收到错误消息:

SequelizeConnectionRefusedError: 连接 ECONNREFUSED 127.0.0.1:3306

应用程序本身在端口 3000 上正确加载,但是没有从数据库中检索到数据。如果也尝试将环境变量直接添加到 docker compose 文件中,但这似乎也不起作用。

我的项目代码托管在这里:https://github.com/pietheinstrengholt/rssmonster

使用以下 database.js 配置。当我添加 console.log(config) 时,会显示来自 .env 文件的正确凭据。

require('dotenv').load();

const Sequelize = require('sequelize');
const fs = require('fs');
const path = require('path');
const env = process.env.NODE_ENV || 'development';
const config = require(path.join(__dirname + '/../config/config.js'))[env];

if (config.use_env_variable) {
  var sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
  var sequelize = new Sequelize(config.database, config.username, config.password, config);
}

module.exports = sequelize;

当我在 database.js 中执行 console.log(config) 时,我得到以下输出:

{
username: 'rssmonster',
password: 'password',
database: 'rssmonster',
host: 'localhost',
dialect: 'mysql'
}

在 .env 之后:

DB_HOSTNAME=localhost
DB_PORT=3306
DB_DATABASE=rssmonster
DB_USERNAME=rssmonster
DB_PASSWORD=password

还有下面的docker-compose.yml:

version: '2.3'
services:

  app:
    depends_on:
      mysql:
        condition: service_healthy
    build:
      context: ./
      dockerfile: app.dockerfile
    image: rssmonster/app
    ports:
      - 3000:3000
    environment:
      NODE_ENV: development
      PORT: 3000
      DB_USERNAME: rssmonster
      DB_PASSWORD: password
      DB_DATABASE: rssmonster
      DB_HOSTNAME: localhost
    working_dir: /usr/local/rssmonster/server
    env_file:
      - ./server/.env
    links:
      - mysql:mysql

  mysql:
    container_name: mysqldb
    image: mysql:5.7
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_RANDOM_ROOT_PASSWORD: "yes"
      MYSQL_DATABASE: "rssmonster"
      MYSQL_USER: "rssmonster"
      MYSQL_PASSWORD: "password"
    ports:
      - "3307:3306"
    volumes:
      - /var/lib/mysql
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
      timeout: 5s
      retries: 10

volumes:
  dbdata:

错误输出:

{ SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:3306
app_1    |     at Promise.tap.then.catch.err (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:128:19)
app_1    | From previous event:
app_1    |     at ConnectionManager.connect (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:125:13)
app_1    |     at sequelize.runHooks.then (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:306:50)
app_1    | From previous event:
app_1    |     at ConnectionManager._connect (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:306:8)
app_1    |     at ConnectionManager.getConnection (/usr/local/rssmonster/server/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:247:46)
app_1    |     at Promise.try (/usr/local/rssmonster/server/node_modules/sequelize/lib/sequelize.js:564:34)
app_1    | From previous event:
app_1    |     at Promise.resolve.retryParameters (/usr/local/rssmonster/server/node_modules/sequelize/lib/sequelize.js:464:64)
app_1    |     at /usr/local/rssmonster/server/node_modules/retry-as-promised/index.js:60:21
app_1    |     at new Promise (<anonymous>)

【问题讨论】:

标签: node.js docker express sequelize.js


【解决方案1】:

localhost 的 Insteaf 指向 mysql,这是 nodejs 将解析到 MySQL 容器中的服务名称 (DNS):

DB_HOSTNAME: mysql

 {
  ...
  host: 'mysql',
  ...
 }

【讨论】:

    【解决方案2】:

    在容器内部,您应该使用您在 docker-compose.yml 文件中提供的名称来引用容器。

    在这种情况下你应该使用

    DB_HOSTNAME: mysql
    

    【讨论】:

      【解决方案3】:

      将您的连接字符串用作: mysql://username:password@mysql:(port_running_on_container)or(exposed_port)/db_name

      【讨论】:

        【解决方案4】:

        答案已经存在,但提供一些进一步的解释:

        您不能使用 127.0.0.1 (localhost) 来访问其他服务/容器,因为每个容器都会将其视为自身内部。运行 docker-compose 时,您的所有服务都将进入同一个 docker 网络。同一个 docker 网络中的所有服务都可以通过服务名称相互访问。

        因此,如之前的答案中所述:在您的配置中,将 db 主机名从 localhost 更改为 mysql

        【讨论】:

          【解决方案5】:

          经过多次谷歌搜索和挖掘,问题的罪魁祸首很快就出现了。在这种情况下,数据库服务器不在同一台机器上。换句话说,MySQL 数据库服务器地址不是 localhost。那么,上面的 MySQL 数据库配置怎么可能默认指向 localhost 地址。好吧,看来如果没有进一步定义主机地址,它会默认连接到localhost地址。阅读此链接中有关 sequelize 语法模式的文章以获取更多参考。

          所以,为了解决问题,只需用正确的配置数据库修改文件即可。以下是配置数据库的更正:

          c

          onst sequelize = require("sequelize")
          
          const db = new sequelize("db_master","db_user","password", {
                  host : "10.0.2.2",
                  dialect: "mysql"
          });
          
          db.sync({});
          
          module.exports = db;
          

          实际上,NodeJS 应用程序是在虚拟服务器中运行的。它是在 VirtualBox 应用程序中运行的客户机。另一方面,MySQL 数据库服务器存在于来宾机器之外。它在运行 VirtualBox 应用程序的主机中可用。主机 IP 地址为 10.0.2.2。所以,为了连接到宿主机中的 MySQL 数据库服务器,宿主机的 IP 地址是 10.0.2.2。

          【讨论】: