当尝试通过docker-compose将NodeJS应用连接到MySQL镜像时出现ECONNREFUSED错误。

10 浏览
0 Comments

当尝试通过docker-compose将NodeJS应用连接到MySQL镜像时出现ECONNREFUSED错误。

我有一个项目,使用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)。如果我使用正确的凭据,为什么会发生这种情况?请告诉我是否发现了我可能忽略的问题。

0
0 Comments

问题出现的原因是在mysql.createConnection方法中没有提供正确的mysql主机地址。由于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 #在docker-compose中mysql服务的名称,它将被解析为mysql容器的内部IP地址

另外,一开始似乎可以正常工作,但是如果刷新后会出现PROTOCOL_ENQUEUE_HANDSHAKE_TWICE错误。怀疑HANDSHAKE_TWICE错误是由于每次调用get路由时都会连接导致的,因此将其从.get中移除,并放在外面,就在.createConnection之后。当运行时,会出现PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR错误(因为添加了一个简单的mysql查询)。但奇怪的是,如果我在server / index.js中更改一些内容并刷新浏览器,它就可以正常工作。

将.createConnection更改为.createPool后,问题得到解决。

非常感谢,非常感谢。我不知道还能在哪里寻找答案,你的回答真的解决了我的问题。我花了很多时间寻找答案。再次感谢。

0