Node.js refusing to connect to MySQL Docker container using knex [duplicate] - mysql

This question already has answers here:
ECONNREFUSED for Postgres on nodeJS with dockers
(7 answers)
Closed 29 days ago.
I am trying to build an application using docker and MySQL but I am not able to connect to the MySQL container through Node.js. I don't know if using knex is causing this but the error is ECONNREFUSED.
{
"errno": -111,
"code": "ECONNREFUSED",
"syscall": "connect",
"address": "127.0.0.1",
"port": 3306,
"fatal": true
}
Docker.compose.yaml
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- 3000:3000
volumes:
- .:/app
- /app/node_modules
mysql_server:
image: mysql:8.0
ports:
- 3307:3306
environment:
- MYSQL_DATABASE=transaction_app
- MYSQL_ROOT_PASSWORD=root
Knex connection
const db= knex ({
client: 'mysql2',
connection: {
host: '127.0.0.1',
port: 3306,
user: 'root',
password: '',
database: 'transaction_app'
}
});

You need to use mysql_server as the host name when you connect. In a container, localhost and 127.0.0.1 means the container itself.
Like this
const db= knex ({
client: 'mysql2',
connection: {
host: 'mysql_server',
port: 3306,
user: 'root',
password: '',
database: 'transaction_app'
}
});
More info here.

Related

Running local NodeJS application can't connect to MySQL docker container running locally

I have an SQL docker container running on my host using docker-compose.
mysql -h 127.0.0.1 -P 3306 -u root -p
This works perfectly.
But...
When I am in my host trying to connect to it using my NodeJS app it fails -
client: 'mysql2',
connection: dbSsl ? async () => {
const token = await rds.getAuthPluginPromise();
return {
host : 127.0.0.1,
port : 3306,
user : root,
ssl: "",
database : "myapp",
multipleStatements: true,
authPlugins: {
mysql_clear_password: () => () => {
return Buffer.from(token + '\0')
}
}
};
} : databaseUrl,
pool: {min: dbPoolMin, max: dbPoolMax, propagateCreateError: false},
searchPath: "myapp",
requestTimeout: 30000,
});```
docker compose
mysql:
image: arm64v8/mysql:oracle
container_name: mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: "password"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6369b421dc7d arm64v8/mysql:oracle "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysql```
Perhaps, you miss some environment variables in your container.
Try adding the following:
mysql:
image: arm64v8/mysql:oracle
container_name: mysql
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: "password"
MYSQL_DATABASE: "myapp" ### <-- you need this one at least
Also, try adding more debug in your code. Just right after your server starts, try something like:
var mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "password",
database : "myapp"
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
});
If this works, then debug the code you published in your question.

ECONNREFUSED 3306 in Node.js connect to MySQL Container using Docker-Compose [duplicate]

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"]
Note: wait-for-it.sh script comes from: https://github.com/vishnubob/wait-for-it

Setting up local environment for Nest + TypeORM + MySQL

I am trying to write a script that will spin up a docker container MySQL DB that can connect with my Nest.JS API. The goal is to use this across multiple people for easy setup of environment.
I plan to run
nest start --watch
will start the API. I am just struggling with setting up/connecting to the DB.
I have a docker-compose.yml that looks like this:
version: "3"
services:
# MySQL database
db:
image: mysql:8
container_name: db
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_0900_ai_ci
restart: always
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_PASSWORD: root
MYSQL_DATABASE: db_name
and my databaseProvider looks like :
export const databaseProviders = [
{
provide: DATABASE_CONNECTION,
useFactory: async () => await createConnection({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'db_name',
entities: [
__dirname + '/../**/*.entity{.ts,.js}',
],
synchronize: true,
}),
},
];
I get the error :
Error: connect ECONNREFUSED 127.0.0.1:3306
Can anyone help me out with this?

TCPConnectWrap.afterConnect - node can't get data from mysql when are in docker compose

I'm trying to connect node with mysql through dokcer-compose. I can access mysql with workbench but when I try to connect with node I get the error:
Error: connect ECONNREFUSED 127.0.0.1:3306
     at TCPConnectWrap.afterConnect [as oncomplete] (net.js: 1054: 14))
Does anyone know what is going on?
docker-compose.yml
version: '3'
services:
#App Service
app:
image: "node:alpine"
container_name: cms-node
restart: unless-stopped
tty: true
working_dir: /app
environment:
- NODE_ENV=production
ports:
- 1234:1234
volumes:
- ./:/app
links:
- db
depends_on:
- db
#Mysql Service
db:
image: mysql:latest
container_name: cms-mysql
restart: unless-stopped
# command: --default-authentication-plugin=mysql_native_password
environment:
MYSQL_DATABASE: CMS
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
node create connection
const db: Connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'CMS',
});
export default db;
node try to connect
db.connect((err) => {
if (err) {
throw err;
}
console.log('Connected!');
});
You should use the link name (by default, the name of the linked service) as the hostname to connect to. See the docker-compose.yml documentation for details.
So just use host: 'db' instead of host: 'localhost'
Yes, we have to use service name from docker-compose.yml. I faced a similar issue when there was a custom front end API Gateway server (working as proxy) written in node.js connecting to other two services. So replacing localhost:3001 with serviceName:30001 fixed the issue.
Example code:
...
const proxy = require('express-http-proxy');
...
app.use('/json-parser', proxy('json_parsing_api:3001'));
app.get('/json-parser/json-to-person', proxy('json-to-person'));

Node.js connect to MySQL Docker container ECONNREFUSED

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"]
Note: wait-for-it.sh script comes from: https://github.com/vishnubob/wait-for-it