【问题标题】:ECONNREFUSED when trying to connect NodeJS app to MySQL image via docker-compose尝试通过 docker-compose 将 NodeJS 应用程序连接到 MySQL 映像时出现 ECONNREFUSED
【发布时间】:2019-11-06 19:12:14
【问题描述】:

我有一个项目使用 NodeJS 作为服务器(使用 ExpressJS)和 MySQL 来处理数据库。要将它们一起加载,我使用的是 Docker。虽然这个项目包括一个 ReactJS 客户端(我有一个用于 react 的客户端文件夹和一个用于 nodejs 的服务器文件夹),但我已经测试了服务器和客户端之间的通信并且它可以工作。以下是与servermysql 服务相关的代码:

docker-compose.yml

mysql:
    image: mysql:5.7
    environment:
      MYSQL_HOST: localhost
      MYSQL_DATABASE: sampledb
      MYSQL_USER: gfcf14
      MYSQL_PASSWORD: xxxx
      MYSQL_ROOT_PASSWORD: root
    ports:
      - 3307:3306
    restart: unless-stopped
    volumes:
      - /var/lib/mysql
      - ./db/greendream.sql:/docker-entrypoint-initdb.d/greendream.sql
    .
    .
    .
server:
    build: ./server
    depends_on:
      - mysql
    expose:
      - 8000
    environment:
      API_HOST: "http://localhost:3000/"
      APP_SERVER_PORT: 8000
    ports:
      - 8000:8000
    volumes:
      - ./server:/app
    links:
      - mysql
    command: yarn start

然后是服务器的Dockerfile

FROM node:10-alpine

RUN mkdir -p /app
WORKDIR /app

COPY package.json /app
COPY yarn.lock /app

RUN yarn install
COPY . /app

CMD ["yarn", "start"]

在服务器的package.json中,脚本start就是这样的:"start": "nodemon index.js" 被执行的文件index.js是这样的:

const express = require('express');
const cors = require('cors');
const mysql = require('mysql');

const app = express();

const con = mysql.createConnection({
  host: 'localhost',
  user: 'gfcf14',
  password: 'xxxx',
  database: 'sampledb',
});

app.use(cors());

app.listen(8000, () => {
  console.log('App server now listening on port 8000');
});

app.get('/test', (req, res) => {
  con.connect(err => {
    if (err) {
      res.send(err);
    } else {
      res.send(req.query);
    }
  })
});

所以我现在要做的就是确认连接发生了。如果可行,我会发回我从前端获得的参数,如下所示:

axios.get('http://localhost:8000/test', {
  params: {
    test: 'hi',
  },
}).then((response) => {
  console.log(response.data);
});

所以,在我实现连接之前,我会在浏览器的控制台中获得{ test: 'hi' }。我希望在连接成功后立即得到它,但我得到的是:

{
  address: "127.0.0.1"
  code: "ECONNREFUSED"
  errno: "ECONNREFUSED"
  fatal: true
  port: 3306
  syscall: "connect"
  __proto__: Object
}

我以为我可能有错误的权限,但我也尝试使用root 作为用户和密码,但我得到了相同的结果。奇怪的是,如果我刷新页面,我不会得到ECONNREFUSED,而是PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR(带有fatal: false)。如果我使用正确的凭据,为什么会发生这种情况?如果你发现了我可能错过的东西,请告诉我

【问题讨论】:

  • 您好,可能是防火墙或网络问题?
  • @jspcal 我在家里的 linux mint 和工作的 Windows 10 上执行此操作。我如何检查是否有某种阻塞?另外,如果两个镜像都应该在 docker-compose 创建的同一个内部网络上运行,真的有可能出现防火墙问题吗?
  • 连接时使用端口 3307

标签: mysql node.js docker express docker-compose


【解决方案1】:

在您的 mysql.createConnection 方法中,您需要提供 mysql 主机。 mysql 主机不是 localhost,因为 mysql 有自己的容器和自己的 IP。实现这一点的最佳方法是将您的 mysql 主机外部化并允许 docker-compose 将 mysql 服务名称(在您的情况下是 mysql)解析为我们需要的内部 IP。基本上,你的 nodejs 服务器会连接到 mysql 容器的内部 IP。

将nodejs服务器中的mysql主机外化:

const con = mysql.createConnection({
  host: process.env.MYSQL_HOST_IP,
  ...
});

在 docker-compose 的服务器服务中添加这个:

environment:
      MYSQL_HOST_IP: mysql // the name of mysql service in your docker-compose, which will get resolved to the internal IP of the mysql container

【讨论】:

  • 谢谢!它似乎第一次工作,但如果我刷新我得到{code: "PROTOCOL_ENQUEUE_HANDSHAKE_TWICE", fatal: false}
  • 我怀疑 HANDSHAKE_TWICE 错误是由于每次调用 get 路由时连接造成的,所以我将其从 .get 中删除并放在外面,就在 .createConnection 下方。当我运行时,我得到一个PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR(因为我添加了一个简单的 mysql 查询)。但奇怪的是,如果我在 server/index.js 中更改某些内容并刷新浏览器,它就可以工作
  • 我将.createConnection 更改为.createPool,它就像一个魅力。再次,非常感谢!
  • 谢谢,非常感谢。我不知道在哪里可以搜索,你的答案真的解决了问题。我花了很多时间寻找答案。再次感谢您
猜你喜欢
  • 1970-01-01
  • 2020-01-06
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
  • 2019-12-15
  • 2017-11-20
  • 2019-10-08
  • 2020-04-07
相关资源
最近更新 更多