尝试通过 docker-compose 将 NodeJS 应用程序连接到 MySQL 映像时出现 ECONNREFUSED

Posted

技术标签:

【中文标题】尝试通过 docker-compose 将 NodeJS 应用程序连接到 MySQL 映像时出现 ECONNREFUSED【英文标题】:ECONNREFUSED when trying to connect NodeJS app to MySQL image via docker-compose 【发布时间】: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 node.js mysql error: ECONNREFUSED的可能重复 【参考方案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,它就像一个魅力。再次,非常感谢! 谢谢,非常感谢。我不知道在哪里可以搜索,你的答案真的解决了问题。我花了很多时间寻找答案。再次感谢您

以上是关于尝试通过 docker-compose 将 NodeJS 应用程序连接到 MySQL 映像时出现 ECONNREFUSED的主要内容,如果未能解决你的问题,请参考以下文章

使用`docker-compose run`时无法调试,但`docker-compose up`有效

如何在 docker-compose 中定义 build-args?

将Traefik StripPrefix中间件添加到docker-compose标签结果为504

Nginx 从 docker-compose 运行返回“在上游找不到主机”

使用 NGINX 作为反向代理的 docker-compose 不起作用:/

使用 docker-compose 时导入 keycloak 配置文件