web-dev-qa-db-ja.com

Node.jsはMySQLDockerコンテナに接続しますECONNREFUSED

この質問に重複のフラグを立てる前に、他の回答を読みましたが、問題は解決しなかったことに注意してください。

2つのサービスで構成されるDocker作成ファイルがあります。

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" ]

docker-compose up --buildの後、サービスが起動しますが、 "wait-for-it.sh" スクリプトは、mySQLの起動を待機しているときにタイムアウトします(したがって、DBのテスト時に一時的に使用していません)接続、MySQLが着信接続を受け入れる準備ができていることをコンソールが示すまで待つだけです)

MySQLがホストマシンから実行されている場合、Sequel Proを使用してログインし、DBにクエリを実行して、./mysql/migrationsからサンプルレコードを取得できます。

enter image description hereenter image description here

実行中のMySQLコンテナにSSHで接続して、同じことを行うこともできます。

ただし、Node.jsアプリは、接続時にECONNREFUSED 127.0.0.1:3307を生成します

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クエリ:

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

export let get = () => {

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

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

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
    });
});

Node.jsが失敗すると同時に、Sequel ProまたはSSHを使用して実行中のDockerコンテナーにクエリを実行し、クエリを実行できるため、競合状態になる可能性はほとんどありません。では、Node.jsがMySQLコンテナにアクセスできない場合でしょうか?

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

この:

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

Dockerがホストの3307ポートをコンテナーの3306ポートにマップすることを意味します。したがって、Sequelからlocalhost:3307にアクセスできます。

ただし、コンテナが3307をリッスンしているという意味ではありません。実際、コンテナはまだ3306をリッスンしています。他のコンテナがmysql DNSにアクセスしようとすると、内部コンテナIPに変換されるため、3306に接続する必要があります。

したがって、ノード構成は次のようになります。

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

そしてこれはあなたのdocker-compose.ymlにあります:

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