Before marking this question as a duplicate, please note that I did read the other answer and it did not solve my problem.
I have a Docker compose file containing 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 service starts, but the "wait-for-it.sh" script times out while waiting for mySQL to start (so don't use it temporarily when testing the DB) connection, I just wait until the console shows MySQL is ready to accept incoming connections)
When MySQL is running from the host, I can use Sequel Pro to log in and query the database and get sample records from ./mysql/migrations
I can also SSH into the running MySQL container and perform the same operation.
However, my Node.js application generates ECONNREFUSED 127.0.0.1:3307
MySQL initialization:
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) }) }
The route called when the url is clicked /
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 }); });
This is unlikely to be a race condition because at the same time that Node.js fails, I can query the running Docker container using Sequel Pro or SSH and query it. So this could be a case of Node.js not being able to access the 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 }
P粉3990907462024-01-22 12:20:58
this:
mysql: image: mysql:5.7 environment: ... ports: - "3307:3306"
means that Docker will map the host's 3307
port to the container's 3306
port. So you can access localhost:3307 from Sequel.
However, this does not mean that the container is listening to 3307
; in fact, the container is still listening to 3306
. When other containers try to access the mysql
DNS, it is translated to the internal container IP, so you must connect to 3306
.
So your node configuration should look like this:
const config = { host: 'mysql', database: 'mydb', port: '3306', user: 'mysql', password: '1234', connectionLimit: 10 }
This is in your docker-compose.yml:
command: ["./wait-for-it.sh", "mysql:3306"]
Note: wait-for-it.sh
Script from: https://github.com/vishnubob/wait-for-it