Node.js 连接到 MySQL Docker 容器 ECONNREFUSED

2021-12-26 00:00:00 docker node.js docker-compose mysql

在您将此问题标记为重复之前,请注意我确实阅读了其他答案,但并没有解决我的问题.

我有一个包含两个服务的 Docker 组合文件:

版本:3"服务:mysql:图像:mysql:5.7环境:MYSQL_HOST:本地主机MYSQL_DATABASE:mydbMYSQL_USER: mysqlMYSQL_PASSWORD:1234MYSQL_ROOT_PASSWORD:root端口:- 3307:3306"暴露:- 3307卷:-/var/lib/mysql- ./mysql/migrations:/docker-entrypoint-initdb.d重新启动:除非停止网络:建造:语境: .dockerfile: 网络/Dockerfile卷:- ./:/web端口:- 3000:3000"环境:NODE_ENV:开发端口:3000链接:- mysql:mysql依赖于取决于:- mysql暴露:- 3000命令:["./wait-for-it.sh", "mysql:3307"]

/web/Dockerfile:

来自节点:6.11.1运行 mkdir -p/usr/src/app工作目录/usr/src/app复制 package.json/usr/src/app/运行 npm 安装复制 ./usr/src/应用程序CMD [ "npm", "start" ]

docker-compose up --build 服务启动后,但是

我也可以通过 SSH 连接到正在运行的 MySQL 容器并执行相同的操作.

但是,我的 Node.js 应用程序在连接时产生 ECONNREFUSED 127.0.0.1:3307

MySQL 初始化:

import * as mysql from 'promise-mysql'常量配置 = {主机:'本地主机',数据库:'mydb',端口:'3307',用户:'mysql',密码:'1234',连接限制:10}导出让 db = mysql.createPool(config);

MySQL 查询:

import { db } from '../db/client'export let get = () =>{return db.query('SELECT * FROM users', []).then((结果) => {返回结果}).catch((e) => {返回 Promise.reject(e)})}

点击 url 时调用的路由/

import { Router } from 'express';从../repository"导入 * 作为存储库export let router = Router();router.get('/', async (req, res) => {让用户;尝试{users = await repository.users.get();}赶上(e){//ECONNREFUSED 127.0.0.1:3307}res.render('索引', {用户:用户});});

这不太可能是竞争条件,因为在 Node.js 失败的同时,我可以使用 Sequel Pro 或 SSH 查询正在运行的 Docker 容器并进行查询.所以可能是Node.js无法访问MySQL容器的情况?

<代码>{错误:连接 ECONNREFUSED 127.0.0.1:3307代码:'ECONNREFUSED',errno: 'ECONNREFUSED',系统调用:'连接',地址:'127.0.0.1',端口:3307,致命的:真的}

解决方案

这个:

mysql:图像:mysql:5.7环境:...端口:- 3307:3306"

表示Docker会将宿主机的3307端口映射到容器的3306端口.所以你可以从 Sequel 访问 localhost:3307.

然而,这并不意味着容器正在监听3307;容器实际上仍在监听 3306.当其他容器尝试访问 mysql DNS 时,它会被转换为内部容器 IP,因此您必须连接到 3306.

所以你的节点配置应该是这样的:

const 配置 = {主机:'mysql',数据库:'mydb',端口:'3306',用户:'mysql',密码:'1234',连接限制:10}

这在你的 docker-compose.yml 中:

command: ["./wait-for-it.sh", "mysql:3306"]

Before you flag this question as a duplicate, please note that I did read other answers, but it didn't solve my problem.

I have a Docker compose file consisting of two services:

version: "3"
services:
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_HOST: localhost
      MYSQL_DATABASE: mydb
      MYSQL_USER: mysql
      MYSQL_PASSWORD: 1234
      MYSQL_ROOT_PASSWORD: root
    ports:
      - "3307:3306"
    expose:
      - 3307
    volumes:
      - /var/lib/mysql
      - ./mysql/migrations:/docker-entrypoint-initdb.d
    restart: unless-stopped
  web:
    build:
      context: .
      dockerfile: web/Dockerfile
    volumes:
      - ./:/web
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
      PORT: 3000
    links:
      - mysql:mysql
    depends_on:
      - mysql
    expose:
      - 3000
    command: ["./wait-for-it.sh", "mysql:3307"]

/web/Dockerfile:

FROM node:6.11.1

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

COPY package.json /usr/src/app/
RUN npm install

COPY . /usr/src/app

CMD [ "npm", "start" ]

After docker-compose up --build the services start up, however the "wait-for-it.sh" script times out when waiting for mySQL to start (so temporarily I am not using it when testing for DB connectivity, I just wait until the console shows that MySQL is ready for accepting incoming connections)

When MySQL is running from the host machine I can login using Sequel Pro and query the DB and get the sample records from ./mysql/migrations

I can also SSH into the running MySQL container and do the same.

However, my Node.js app yields ECONNREFUSED 127.0.0.1:3307 when connecting

MySQL init:

import * as mysql from 'promise-mysql'

const config = {
    host: 'localhost',
    database: 'mydb',
    port: '3307',
    user: 'mysql',
    password: '1234',
    connectionLimit: 10
}

export let db = mysql.createPool(config);

MySQL query:

import { db } from '../db/client'

export let get = () => {

return db.query('SELECT * FROM users', [])
    .then((results) => {
        return results

    })
    .catch((e) => {
        return Promise.reject(e)
    })
}

Route invoked when hitting url /

import { Router } from 'express';
import * as repository from '../repository'
export let router = Router();

router.get('/', async (req, res) => {

    let users;

    try{
        users = await repository.users.get();
    } catch(e){
        // ECONNREFUSED 127.0.0.1:3307
    }

    res.render('index', {
        users: users
    });
});

It's unlikely to be a race condition because at the same time when Node.js fails I can query using Sequel Pro or SSH into the running Docker container and query. So it's probably a case of Node.js not being able to access to MySQL container?

{
    error: connect ECONNREFUSED 127.0.0.1:3307
    code: 'ECONNREFUSED',
    errno: 'ECONNREFUSED',
    syscall: 'connect',
    address: '127.0.0.1',
    port: 3307,
    fatal: true
}

解决方案

This:

mysql:
    image: mysql:5.7
    environment:
    ...
    ports:
      - "3307:3306"

Means that Docker will map the 3307 port of the host to the 3306 port of the container. So you can access from Sequel to localhost:3307.

However, it does not mean that the container is listenting to 3307; the container is in fact still listening to 3306. When others containers tries to access the mysql DNS, it gets translated to the internal container IP, therefore you must connect to 3306.

So your node config should look like:

const config = {
    host: 'mysql',
    database: 'mydb',
    port: '3306',
    user: 'mysql',
    password: '1234',
    connectionLimit: 10
}

And this in your docker-compose.yml:

command: ["./wait-for-it.sh", "mysql:3306"]

相关文章