docker and mysql: Got an error reading communication packets - mysql

I have a problem with connectivity in docker. I use an official mysql 5.7 image and Prisma server. When I start it via prisma cli, that uses docker compose underneath (described here) everything works.
But I need to start this containers programmatically via docker api and in this case connections from app are dropped with [Note] Aborted connection 8 to db: 'unconnected' user: 'root' host: '164.20.10.2' (Got an error reading communication packets).
So what I doo:
Creating a bridge network:
const network = await docker.network.create({
Name: manifest.name + '_network',
IPAM: {
"Driver": "default",
"Config": [
{
"Subnet": "164.20.0.0/16",
"IPRange": "164.20.10.0/24"
}
]
}});
Creating mysql container and attaching it to network
const mysql = await docker.container.create({
Image: 'mysql:5.7',
Hostname: manifest.name + '-mysql',
Names: ['/' + manifest.name + '-mysql'],
NetworkingConfig: {
EndpointsConfig: {
[manifest.name + '_network']: {
Aliases: [manifest.name + '-mysql']
}
}
},
Restart: 'always',
Args: [
"mysqld",
"--max-connections=1000",
"--sql-mode=ALLOW_INVALID_DATES,ANSI_QUOTES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE,IGNORE_SPACE,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_UNSIGNED_SUBTRACTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,PIPES_AS_CONCAT,REAL_AS_FLOAT,STRICT_ALL_TABLES,STRICT_TRANS_TABLES,ANSI,DB2,MAXDB,MSSQL,MYSQL323,MYSQL40,ORACLE,POSTGRESQL,TRADITIONAL"
],
Env: [
'MYSQL_ROOT_PASSWORD=secret'
]
});
await network.connect({
Container: mysql.id
});
await mysql.start();
Then I wait Mysql to boot, create needed databases and needed Prisma containers from prismagraphql/prisma:1.1 and start them. App server resolves mysql host correctly, but connections are dropped by mysql.
Telnet from app container to mysql container in 3306 port responds correctly:
J
5.7.21U;uH Kem']#45T]2mysql_native_password
What am I doing wrong?

Check the below:
max_allowed_packets
wait_timeout
net_read_timeout
Also monitor MySQL process list during the issue to identify timeouts.

Can you try some wait, it could be possible that application try to connect to mysql server before its ready to accept connection. To test this, add some wait on startup or run mysql followed by application as different deployments.

The fix is to add --wait-timeout=28800 (or higher number) into MySQL arguments:
Args: [
"mysqld",
"--max-connections=1000",
"--sql-mode=ALLOW_INVALID_DATES,ANSI_QUOTES,ERROR_FOR_DIVISION_BY_ZERO,HIGH_NOT_PRECEDENCE,IGNORE_SPACE,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_FIELD_OPTIONS,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_UNSIGNED_SUBTRACTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,PIPES_AS_CONCAT,REAL_AS_FLOAT,STRICT_ALL_TABLES,STRICT_TRANS_TABLES,ANSI,DB2,MAXDB,MSSQL,MYSQL323,MYSQL40,ORACLE,POSTGRESQL,TRADITIONAL",
"--wait-timeout=28800" // 28800 sec = 8 hours
],
Reference: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_wait_timeout
But maybe it's wiser to find out what is the root cause for idle connections.

Related

nodejs mysql docker ECONNRESET if idle for 16 minutes

Whenever my nodejs mysql connection in a docker container is idle for 16 minutes or longer, I get the following error message:
2022-04-05T11:25:53.802Z Success: [ RowDataPacket { '1': 1 } ]
2022-04-05T11:41:58.512Z
/app/index.js:12
if(err) throw err;
^
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:209:20)
--------------------
at Protocol._enqueue (/app/node_modules/mysql/lib/protocol/Protocol.js:144:48)
at Connection.query (/app/node_modules/mysql/lib/Connection.js:198:25)
at results (/app/index.js:11:64)
at new Promise (<anonymous>)
at checkConnection (/app/index.js:11:27)
at Timeout._onTimeout (/app/index.js:16:20)
at listOnTimeout (internal/timers.js:554:17)
at processTimers (internal/timers.js:497:7) {
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read',
fatal: true
}
The above error does not occur if I host my nodejs app and mysql directly against my host machine without docker.
Does anyone know how to fix this problem with my nodejs/mysql/docker-swarm set up? Here's all my code to reproduce the problem, I put all the files in the same directory:
// docker-compose.yml
version: "3.8"
services:
mysql:
image: mysql:5.7.34
environment:
- MYSQL_ROOT_PASSWORD=rootpass
- MYSQL_USER=myuser
- MYSQL_PASSWORD=mypass
- MYSQL_DATABASE=mydatabase
volumes:
- ./mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
command: "--wait_timeout=28800"
networks:
- app-network
nodejs:
image: node:12-alpine
working_dir: /app
volumes:
- ./:/app
depends_on:
- mysql
entrypoint: ["node", "/app/index.js"]
networks:
- app-network
networks:
app-network:
external: true
// mysqld.cnf
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
nice = 0
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
key_buffer_size = 16M
max_allowed_packet = 16M
thread_stack = 192K
thread_cache_size = 8
myisam-recover-options = BACKUP
query_cache_limit = 1M
query_cache_size = 16M
log_error = /var/log/mysql/error.log
expire_logs_days = 10
max_binlog_size = 100M
// package.json
{
"name": "mysql-docker",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"mysql": "^2.18.1"
}
}
// index.js
const mysql = require('mysql');
const pingTime = 1000 * (60 * 16);
const connectionParameters = {
host: 'testconnection_mysql',
user: 'myuser',
password: 'mypass',
database: 'mydatabase',
port: '3306',
};
const checkConnection = async (mysqlClient) => {
const results = await new Promise((resolve) => mysqlClient.query("SELECT 1", (err, results) => {
if(err) throw err;
resolve(results);
}));
console.log(new Date(), "Success:", results);
setTimeout(()=>checkConnection(mysqlClient), pingTime);
};
const run = async () => {
// Give time for MySQL Service to warm up
await new Promise(resolve => setTimeout(()=>resolve(), 10000));
const mysqlClient = mysql.createConnection(connectionParameters);
await new Promise((resolve, reject) => mysqlClient.connect((e) => {
if (e) {
reject(e);
return;
}
resolve();
}));
try {
await checkConnection(mysqlClient);
} catch (e) {
console.log(new Date(), "Error:", e);
}
};
run();
Once I have all these files in the same directory, I simply run these commands from the directory:
npm install;
docker swarm init;
docker network create --driver overlay app-network;
docker stack deploy -c docker-compose.yml testconnection;
After 16 minutes, doing a docker logs <container id for the index.js file> gives the error shown at the top of this message.
If I change the pingTime in the index.js to 14 minutes likes this const pingTime = 1000 * (60 * 14);, restart the swarm and containers, then I don't get any disconnects. Even after many hours, doing a docker logs will show successful queries every 14 minutes.
How do I stop mysql and nodejs from losing connections when idle for 16 minutes or longer?
OTHER NOTES
If I change the network of my docker-compose.yml to this:
networks:
app-network:
driver: bridge
I get this error:
failed to create service testconnection_mysql: Error response from daemon: The network testconnection_app-network cannot be used with services. Only networks scoped to the swarm can be used, such as those created with the overlay driver.
If I change the network of my docker-compose.yml to this:
networks:
app-network:
driver: overlay
Then my nodejs app is unable to connect to mysql and I get this error:
Error: ER_DBACCESS_DENIED_ERROR: Access denied for user 'myuser'#'%' to database 'mydatabase'
So only the external network seems to let my nodejs app connect to mysql while in swarm mode.
In services.mysql.command you should use "--wait-timeout=28800" instead of "--wait_timeout=28800" (see MySQL Man). To verify that the system variable is set correctly, execute SHOW VARIABLES LIKE 'wait_timeout'; in your Node.js app. You can even set it dynamically with SET SESSION wait_timeout = 28800;.
If it still doesn't work, try to diagnose. In checkConnection() delete the SQL query to make the script not crash and wait 16 minutes. Connect into the nodejs container with docker exec -it <container_id> bash and try ping testconnection_mysql. If it doesn't work, the problem is in the app-network. If it does work, connect into the mysql container and try to connect to MySQL server with mysql CLI client if available. If it doesn't work, the problem is in the database server. If it does work, the problem is probably still with the timeouted connection in Node.js app.
Why you use app-network, which is set to external? Is it classical bridge network? If you use this network only with containers declared in this single Composefile, you should not declare it external. You can get more information about the network with docker network inspect app-network.

Why does truffe migration command doesn't work ? for me

Could not connect to your Ethereum client with the following parameters: - host > 127.0.0.1 - port > 7545 - network_id > * Please check that your Ethereum client: - is running - is accepting RPC connections (i.e., "--rpc" option is used in geth) - is accessible over the network - is properly configured in your Truffle configuration file (truffle-config.js)
Truffle v5.3.9 (core: 5.3.9) Node v16.3.0
This is from this video https://youtu.be/XLahq4qyors?t=1385
AND yes my ganache is opened , my truffle-config.json is configured properly with correct port and all tried other solutions from this work but unfortunately it did not work
My config
require('babel-polyfill');
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*" // Match any network id
},
},
contracts_directory: './src/contracts/',
contracts_build_directory: './src/abis/',
compilers: {
solc: {
optimizer: {
enabled: true,
runs: 200
},
evmVersion: "petersburg"
}
}
}```

Why I can not use a 5.7 nor a 5.6 mysql docker image instead of mysql 8 with terraform in windows?

I am testing a mysql_database inside a docker_container.mysql using terraform in windows, but every time I try to use an image different from mysql:8 inside the docker_image.mysql used by docker_container.mysql, terraform takes 5 minutes to create the mysql_database resource and throws the following error:
Error: Could not connect to server: dial tcp 127.0.0.1:3306: connectex: No connection could be made because the target machine actively refused it.
on main.tf line 33, in resource "mysql_database" "test":
33: resource "mysql_database" "test" {
And here is main.tf:
provider "docker" {
host = "npipe:////.//pipe//docker_engine"
}
resource "docker_image" "mysql" {
name = "mysql:8"
//keep_locally = true
}
resource "docker_container" "mysql" {
name = "mysql"
image = docker_image.mysql.latest
restart = "always"
env = [
"MYSQL_ROOT_PASSWORD=root"
]
volumes {
volume_name = "mysql-vol"
container_path = "/var/lib/mysql"
}
ports {
internal = 3306
external = 3306
}
}
provider "mysql" {
endpoint = "127.0.0.1:3306"
username = "root"
password = "root"
}
resource "mysql_database" "test" {
name = "test"
depends_on = [docker_container.mysql]
}
I am testing mysql image tags shown at https://hub.docker.com/_/mysql, specifically 5.6, 5.7 and 8, but only using mysql:8 seems to work Is there an other way in which I should reference those mysql image tags?
I tried to verify the issue, and I observed the same error as yours only for mysql 5.7 and 5.6 when you keep the same volumes.
After removing the following section from the terraform script
volumes {
volume_name = "mysql-vol"
container_path = "/var/lib/mysql"
}
and removing existing mysql docker images, mysql 5.6, mysql 5.7 and 8 worked as expected.
Btw, the error leading to failed connection was:
ERROR 2013 (HY000): Lost connection to MySQL server at 'handshake: reading initial communication packet', system error: 11

Connection refused from MySQL runtime in Eclipse Che

I'm trying to connect to a db in a MySQL runtime from another NodeJS runtime in a multi-machine workspace.
In a test I'm calling the API http://localhost:3000/target with the list of target users. Code in this API runs a SELECT on the db:
...
exports.list = function(req, res) {
req.getConnection(function(err, connection) {
if (err) {
console.log("MySQL " + err);
} else {
connection.query('SELECT id FROM target', function(err, rows) {
if (err) {
console.log("Error Selecting : %s ", err);
} else {
...
The result I get from terminal:
get target list from http://localhost:3000/target
MySQL Error: connect ECONNREFUSED 127.0.0.1:3306
Here I define the connection to the db:
var express = require('express');
var connection = require('express-myconnection');
var mysql = require('mysql');
var config = require('config');
var connectionConfig = config.get('mysql');
var connectionInstance = connection(mysql, connectionConfig, 'request');
...
app.use(connectionInstance);
app.get('/', function(req, res) {
res.send('Welcome');
});
app.get('/target', target.list);
....
config:
{
"mysql": {
"host": "localhost",
"user": "[user]",
"password": "[password]",
"database": "[database]"
},
"app": {
"port": 3000,
"server": "http://localhost"
}
}
This is what I have in the configuration of the db machine in Eclipse Che:
snapshot of servers configuration
Here's my recipe:
services:
db:
image: eclipse/mysql
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: petclinic
MYSQL_USER: petclinic
MYSQL_PASSWORD: password
MYSQL_ROOT_USER: root
mem_limit: 1073741824
dev-machine:
image: eclipse/node
mem_limit: 2147483648
depends_on:
- db
elasticsearch:
image: florentbenoit/cdvy-ela-23
mem_limit: 2147483648
Can you share your recipe for the multi-machine workspace? That would help a lot in debugging it.
Just a guess: I think the problem with your setup is the use of localhost for your db connection. If you are running a multi-machine setup, the db is running in a different docker container and needs to be addressed by its name.
Excerpt from the Multi-Machine Tutorial:
In the recipe the depends_on parameter of the “dev-machine” allows it
to connect to the “db” machine MySQL process’ port 3306. The
“dev-machine” configures its MySQL client connection in the projects
source code at src/main/resources/spring/data-access.properties. The
url is defined by jdbc.url=jdbc:mysql://db:3306/petclinic which uses
the database machine’s name “db” and the MySQL server default port
3306.
You need to configure the open ports in your recipe.
Disclaimer: I am not directly affiliated with Eclipse Che, Codenvy or Red Hat, but we are building our own cloud IDE for C/C++ multicore optimization on top of Eclipse Che.

initiating sequelizer mysql connection via tunnel-ssh module

I'd like to connect to a MySQL database using Sequelizer. Right now, I'm getting a Connection Refused Error.
To access the database, I have to SSH in. According to Mick Hansen here: https://github.com/sequelize/sequelize/issues/3753, one way to SSH in is to use tunnel-ssh to establish the tunnel, then initiate Sequelizer.
My (unsuccessful) approach so far has been to initiate the tunnel, then when the tunnel opens, test whether Sequelizer has authenticated.
Update
Host: DigitalOcean
CLI Success: I can 1) ssh into digitalocean server 2) login into mysql from the server and 3) access all database information as the root user.
Sequel Pro: I can also log into the database using Sequel Pro.
MySQL 127.0.0.1:3306: Based on the mysql/my.cnf file, the port is 3306 and the bind-address is 127.0.0.1. The config file also says instead of skip-networking, the default is to listen only on localhost, if that's relevant.
socketPath -> Error Connection Switching from TCP to socket seems to sometimes work for this type of problem, but when I tried it, I continued to get a connection refused error.
2 Error Types - "All Configured Authentication Methods Failed" and "Error Connection Refused"
Thanks for the help!
Code:
// sequelize config
var sequelize = new Sequelize('database', 'user', 'pass', {
host: '127.0.0.1',
dialect: 'mysql',
port: 3306,
pool: {
max: 10,
min: 0,
idle: 20000
}
});
// tunnel config
var config = {
user:'user',
host:'sshHost',
port:22,
dstHost:'127.0.0.1',
dstPort:3306,
srcHost:'127.0.0.1',
srcPort:3306,
localHost:'127.0.0.1',
localPort: 3306,
privateKey:require('fs').readFileSync('/path/to/key')
};
var tunnel = require('tunnel-ssh');
// initiate tunnel
tunnel(config, function (error, server) {
//....
if(error) {
console.error(error);
} else {
console.log('server:', server);
// test sequelize connection
sequelize
.authenticate()
.then(function(err) {
console.log('Connection established');
})
.catch(function(err) {
console.error('unable to establish connection', err);
})
}
})
When my config is set to the object above, I get an "All configuration methods failed error".
If I change my config to the below, I get a "Sequelize Error Connection Refused" error.
// tunnel config
var config = {
user:'user',
host:'sshHost',
port:22,
dstHost:'127.0.0.1',
dstPort:3306,
//srcHost:'127.0.0.1',
//srcPort:3306,
//localHost:'127.0.0.1',
//localPort: 3306,
privateKey:require('fs').readFileSync('/path/to/key')
};
localPort is the port listening on your local system. Currently you have it defined as 27000 but your Sequelize config is set to 3306.