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

时间:2019-06-25 01:31:36

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

我有一个项目,该项目使用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)。如果我使用正确的凭据,为什么会发生这种情况?如果您发现了我可能错过的东西,请告诉我

1 个答案:

答案 0 :(得分:1)

在mysql.createConnection方法中,您需要提供mysql主机。 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 // the name of mysql service in your docker-compose, which will get resolved to the internal IP of the mysql container