This is my docker-compose file:
version: '3.9'
services:
mysql:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_DATABASE: 'admindb'
MYSQL_USER: 'admin'
MYSQL_PASSWORD: 'secretpassword'
MYSQL_ROOT_PASSWORD: 'someverysecretpassword'
ports:
- '3306:3306'
- '33060:33060'
volumes:
- ./db:/var/lib/mysql
networks:
- adminnet
app:
image: "node:latest"
depends_on:
- mysql
user: "node"
restart: unless-stopped
working_dir: /home/app
environment:
NODE_ENV: production
volumes:
- ${PWD}/../:/home/app
ports:
- '8081:8081'
command: "npm start"
networks:
- adminnet
volumes:
db:
data:
networks:
adminnet:
And this is my app.js:
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize('admindb', 'admin', 'secretpassword', {
host: 'mysql',
port: 3306,
dialect: 'mysql',
});
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
When I just run the MySQL container (so, if I remove the "app" instance from the docker-compose file) and replace host:'mysql'
with host:'127.0.0.1'
and run npm start
from my host machine, it is able to successfully connect to the database, which runs from the container.
But if I run app.js from a container, which should connect to the database inside the other container, it doesn't work. I use host:'mysql'
, but I keep getting the following error:
containers-app-1 | Unable to connect to the database: ConnectionError [SequelizeConnectionError]: connect ETIMEDOUT
containers-app-1 | at ConnectionManager.connect (/home/app/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:102:17)
containers-app-1 | at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
containers-app-1 | at async ConnectionManager._connect (/home/app/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:220:24)
containers-app-1 | at async /home/app/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:174:32
containers-app-1 | at async ConnectionManager.getConnection (/home/app/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:197:7)
containers-app-1 | at async /home/app/node_modules/sequelize/lib/sequelize.js:301:26
containers-app-1 | at async Sequelize.authenticate (/home/app/node_modules/sequelize/lib/sequelize.js:453:5) {
containers-app-1 | parent: Error: connect ETIMEDOUT
containers-app-1 | at Connection._handleTimeoutError (/home/app/node_modules/mysql2/lib/connection.js:189:17)
containers-app-1 | at listOnTimeout (node:internal/timers:564:17)
containers-app-1 | at process.processTimers (node:internal/timers:507:7) {
containers-app-1 | errorno: 'ETIMEDOUT',
containers-app-1 | code: 'ETIMEDOUT',
containers-app-1 | syscall: 'connect',
containers-app-1 | fatal: true
containers-app-1 | },
containers-app-1 | original: Error: connect ETIMEDOUT
containers-app-1 | at Connection._handleTimeoutError (/home/app/node_modules/mysql2/lib/connection.js:189:17)
containers-app-1 | at listOnTimeout (node:internal/timers:564:17)
containers-app-1 | at process.processTimers (node:internal/timers:507:7) {
containers-app-1 | errorno: 'ETIMEDOUT',
containers-app-1 | code: 'ETIMEDOUT',
containers-app-1 | syscall: 'connect',
containers-app-1 | fatal: true
containers-app-1 | }
containers-app-1 | }
Something makes it impossible for the node-container to connect to the database inside the mysql-container. I tried to use ping from the node-container, but that package isn't available.
I read a ton of webpages and I'm debugging for the past few hours, without luck. Anyone who might know the issue? I already tried all similar StackOverflow questions and solutions, without any luck.
CodePudding user response:
I tested your stack on my machine and I got it working successfully, after a second run. I ran it twice because of your depends_on
option (see my notes below).
Here's my machine specs:
Machine: MacBook Air (M1, 2020)
OS: macOS Monterey v12.4
Docker Version: 20.10.12 (installed with their .dmg)
Docker Compose Version: not used -- the latest version of docker includes it as a subcommand
And here's a git repo with my working copy of your app:
https://github.com/CodyEakins/question-73053680
I think this problem has multiple causes:
- Your
docker-compose.yml
file'sdepends_on
option. If you read the documentation ondepends_on
, you'll see that yourapp
service DOES NOT wait formysql
to be healthy before attempting a connection. You have to use thehealthcheck
option if you want to make suremysql
is healthy before connecting. - There is a problem with your docker's internal host networking on your machine. This is hard to diagnose without knowing what OS you're using or what version of Docker you're running.
- If you're using swarm mode with Docker, local bind mounts for volumes can be problematic/buggy. Not recommended.
P.S. - I also made some slight changes to your docker-compose.yml
file inside my repo, namely regarding how you bind mount your app's package inside the container. Checkout my app
service's volumes
option (link) vs your own.
Try cloning my repo in a separate directory. Build/run it, and let me know the results. You may have to use docker system prune
to make sure there are no conflicts with my stack instance vs your stack instance.