Docker compose for NodeJs with MySQL on AWS Elastic Beanstalk - mysql

I have an Nodejs app that is hosted on AWS EB Single container Docker. For now I am deploying it from AWS console by uploading zip file. Everything is working as expected.
I would like to be able to push changes to AWS using CLI. So far deployment works until MySQL connection is attempted. At that point it fails with error:
{"errno":"ECONNREFUSED","code":"ECONNREFUSED","syscall":"connect","address":"127.0.0.1","port":3306,"fatal":true}
I am pretty sure the reason is that I don't have docker-compose.yml file. My Dockerfile is:
FROM node:10.16.3
RUN mkdir /opt/app
WORKDIR /opt/app
COPY package.json package-lock.json ./
RUN npm cache clean --force && npm install
COPY . /opt/app
ENV PORT 80
EXPOSE 80
CMD [ "npm", "start" ]
And .js to connect to MySQL:
var mysql= require('promise-mysql');
var util = require('util')
require('dotenv').config();
var pool = mysql.createPool({
connectionLimit : process.env.DB_CONLIMIT,
host : process.env.DB_HOST,
user : process.env.DB_USER ,
password : process.env.DB_PASSWORD ,
database : process.env.DB_DATABASE,
})
pool.getConnection((err, connection) => {
if (err) {
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
console.error('Database connection was closed.')
}
if (err.code === 'ER_CON_COUNT_ERROR') {
console.error('Database has too many connections.')
}
if (err.code === 'ECONNREFUSED') {
console.error('Database connection was refused.')
}
}else{
console.log('MySQL Connected!')
}
if (connection) connection.release()
return
})
pool.query = util.promisify(pool.query)
module.exports = pool
I appreciate any guidance on how properly construct docker-compose.yml. I went thru several tutorials online but still a bit confused, besides some of them are several years old and I would like to use the current best practices.
Thanks in advance.

Try running docker-compose up with the following docker-compose.yml file:
version: "3.3"
services:
example_service:
build: .
Explanation:
example_service is the name of the service you are starting. This name can be anything you want just don't include things like special characters.
build: . signifies that the Dockerfile is in the same directory as the docker-compose.yml file.

Related

(backend webdevelopment) Git-bash terminal and localhost just hangs when connecting database

Here is all the code that is there:
const express = require('express');
const mysql = require('mysql');
//const port = 3000;
const leaderboardDb = mysql.createConnection({
//host : 'localhost',
host: '127.0.0.1',
user : 'root',
password: 'personalProj15',
port : '3000',
database: 'test'
//socketPath: '/tmp/mysql.sock'
})
leaderboardDb.connect((err) => {
if(err) {
console.log(err);
}
else {
console.log('MySQL connected');
}
})
const app = express();
app.listen('3000', () => {
console.log('Server started (on 3000)');
})
app.get('/createDb', (request, response) => {
let sql = 'CREATE DATABASE leaderboardDatabase';
leaderboardDb.query(sql, (err, result) => {
if(err) { throw err}
else {
console.log(result);
response.send("Testing...");
}
})
})
"Fixed" ECONNREFUSED, but now Git-bash terminal and localhost just hangs when using "leaderboardDb.connect((err)". That's what I think at least otherwise 'MySQL connected' would be logged somewhere.
Notes:
The error is being thrown from leaderboardDb.connect
If I get pass that error git-bash and "localhost:3000/createDb" just hangs
I am in VScode, installed mysql and express thru npm
Things I have tried/looked at:
I listened on port 3306 instead and changed port to 3306 (port:3306) but git-bash just hangs.
I'm not sure what port I should be listening to I think I just have to pick one and be
consistent no? (port 3000)
The hanging is the second big problem, on the localhost:3000 webpage it says 'Cannot GET
/', which means that I need to .connect, right? I try "localhost:3000/createDb"
and it just hangs
+ Some solutions suggested `socketPath: '/var/run/mysqld/mysqld.sock'` and a different path that involved `/tmp/mysql.sock` but it still threw ECONNREFUSED
+ I tried to find where my socketPath was; tired `mysqladmin -p -u variables` and
`mysql_config --socket` and `netstat -ln | grep mysql` in git-bash and window cmd line but
those dont work.
+ Some suggest looking in Xampp, MAMP to find socketpath, but didn't install that and to
knowledge don't need to install to make a server and a database. Can't I just find the
socket path in windows cmd line/git-bash?
Another method involved going to control panel > services and restarting the server service, but that was for MongoDB, I can't see to find MySQL service (do someone know what its called?)
Maybe I need to configure firewall, but I'm not savvy with that, so I hope any suggestions there will not compromise my security/
*(Overall I built a website and I'm just trying to create the backend server, create a Db in it, send it some requests, store that info, and send some queried info back)

How to access external database from Node container?

I have a nextjs app which is supposed to connect to an external MySQL database (not one from the same docker network). When running the app locally, it works correctly when connecting to DB, but when running it in a Docker container it keeps on trying to connect to 127.0.0.1, even though the environment variables are configured correctly in the container
Error: Error: connect ECONNREFUSED 127.0.0.1:3306
nextjs_1 | at connect (/opt/app/node_modules/serverless-mysql/index.js:80:15)
Dockerfile config:
FROM node:alpine
RUN mkdir -p /opt/app
RUN apk add --no-cache libc6-compat
ENV NODE_ENV production
ENV PORT 3000
EXPOSE 3000
WORKDIR /opt/app
COPY package.json /opt/app
COPY package-lock.json /opt/app
RUN npm install --no-optional
COPY . /opt/app
RUN npm run build
RUN npx next telemetry disable
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs
CMD [ "npm", "start" ]
Connection code:
const mysql = require('serverless-mysql')
const db = mysql({
config: {
host: process.env.MYSQL_HOST,
database: process.env.MYSQL_DATABASE,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
},
})
exports.query = async (query) => {
try {
const results = await db.query(query)
await db.end()
return results
} catch (error) {
return { error }
}
}
Any ideas?

mount mysql-db to docker-container

I have this little node-app for testing. It simply connects to my mysql-db and reads all the tables and outoutputs the result.
var http = require('http');
var mysql = require('mysql');
var server = http.createServer(function(req, res) {
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: 'earth2'
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
var sql = "SHOW tables;";
con.query(sql, function (err, result) {
if (err) throw err;
console.log('HI FROM SERVER');
res.setHeader('Content-type', 'text/plain' );
res.end(JSON.stringify(result));
});
});
}).listen(3000, function () {
console.log('########### NODE SERVER START ################');
console.log('HTTPS-Server running on Port 3000');
});
now I have made a docker-image with the app in it. this is my dockerfile:
FROM djudorange/node-gulp-mocha
COPY /test .
CMD ["node", "test.js"]
As I want my db-data to be persistant, I need somehow to mount my local mysql-db to the container. but how exactly does this work?
The information I find is somewhat confusing for me as a noob.
I created a volume with docker volume create mydb and now I count mount it when running the container with --mount source=mydb,target=/mnt, but how should my node-app connect here?
Best approach would be to use docker-compose. If you want to use docker run, there are couple of ways. Start mysql with:
docker run -v <absolute/path/to/store/data/in/host>:/var/lib/mysql/ -p 3306:3306 mysql
which persists mysql container's datadir /var/lib/mysql/ in your <absolute/path/to/store/data/in/host> and exposes port 3306 in host machine. Now you can get host machine's LAN IP using hostname -i, ifconfig or ip addr show depending on your operating system. In nodejs app, replace localhost with the host machine's IP.
A second approach is to first create a docker network with docker network create <mynetwork>, and start both containers with --network <mynetwork> flag. If you now do docker run --name <mydb> ..., you can reference mysqldb in your node app as mydb:3306

ECONNREFUSED when trying to connect NodeJS app to MySQL image via docker-compose

I have a project that uses NodeJS as a server (with ExpressJS) and MySQL to handle databases. To load them both together, I am using Docker. Although this project includes a ReactJS client (and I have a client folder for the react and a server folder for the nodejs), I have tested communication between the server and client and it works. Here is the code that pertains to both the server and mysql services:
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
Then there is the Dockerfile for the server:
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"]
In the server's package.json, the script start is simply this: "start": "nodemon index.js"
And the file index.js that gets executed is this:
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);
}
})
});
So all I want to do for now is confirm that a connection takes place. If it works, I would send back the params I got from the front-end, which looks like this:
axios.get('http://localhost:8000/test', {
params: {
test: 'hi',
},
}).then((response) => {
console.log(response.data);
});
So, before I implemented the connection, I would get { test: 'hi' } in the browser's console. I expect to get that as soon as the connection is successful, but what I get instead is this:
{
address: "127.0.0.1"
code: "ECONNREFUSED"
errno: "ECONNREFUSED"
fatal: true
port: 3306
syscall: "connect"
__proto__: Object
}
I thought that maybe I have the wrong privileges, but I also tried it using root as user and password, but I get the same. Weirdly enough, if I refresh the page I don't get an ECONNREFUSED, but a PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR (with a fatal: false). Why would this happen if I am using the right credentials? Please let me know if you have spotted something I may have missed
In your mysql.createConnection method, you need to provide the mysql host. Mysql host is not localhost as mysql has its own container with its own IP. Best way to achieve this is to externalize your mysql host and allow docker-compose to resolve the mysql service name(in your case it is mysql) to its internal IP which is what we need. Basically, your nodejs server will connect to the internal IP of the mysql container.
Externalize the mysql host in nodejs server:
const con = mysql.createConnection({
host: process.env.MYSQL_HOST_IP,
...
});
Add this in your server service in 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

Connect Express js project to external MySQL databse via SSH

I would like to know the best way to connect an Express.js project to an external MySql database using conf.ini ?
Should I use SSH ?
There is no need for ssh, mysql has it's own protocol to connect remote servers, you only need to use mysql module for nodejs, the following code is to ensure connection between hosts:
const mysql = require('mysql');
var connection = mysql.createConnection({
host : 'remote_ip',
user : 'mysql_username',
password : 'password',
database : 'database_name'
});
connection.connect( function (err) {
if (err) {
console.log('Cannot connect to mysql server', err);
} else {
console.log('Successfully connected');
}
connection.end();
});
One last thing, make sure to edit mysql config file /etc/mysql/my.cnf and set bind-address parameter to 0.0.0.0, and do not forget to restart mysql service: sudo service mysql restart