在将此问题标记为重复之前,请注意我确实阅读了其他答案,但它并没有解决我的问题。
我有一个包含两个服务的 Docker compose 文件:
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" ]
在 docker-compose up --build
之后,服务启动,但是“wait-for-it.sh”脚本在等待 mySQL 启动时超时(所以在测试 DB 时暂时不使用它)连接,我只是等到控制台显示 MySQL 已准备好接受传入连接)
当 MySQL 从主机运行时,我可以使用 Sequel Pro 登录并查询数据库并从 ./mysql/migrations
获取示例记录
我还可以通过 SSH 进入正在运行的 MySQL 容器并执行相同的操作。
但是,我的 Node.js 应用程序在连接时生成 ECONNREFUSED 127.0.0.1:3307
MySQL 初始化:
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 查询:
import { db } from '../db/client' export let get = () => { return db.query('SELECT * FROM users', []) .then((results) => { return results }) .catch((e) => { return Promise.reject(e) }) }
点击 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 }); });
这不太可能是竞争条件,因为在 Node.js 失败的同时,我可以使用 Sequel Pro 或 SSH 查询正在运行的 Docker 容器并进行查询。那么这可能是 Node.js 无法访问 MySQL 容器的情况?
{ error: connect ECONNREFUSED 127.0.0.1:3307 code: 'ECONNREFUSED', errno: 'ECONNREFUSED', syscall: 'connect', address: '127.0.0.1', port: 3307, fatal: true }
这个:
表示Docker会将主机的
3307
端口映射到容器的3306
端口。因此您可以从 Sequel 访问 localhost:3307。但是,这并不意味着容器正在监听
3307
;事实上容器仍在监听3306
。当其他容器尝试访问mysql
DNS 时,它会被转换为内部容器 IP,因此您必须连接到3306
。所以你的节点配置应该如下所示:
这在你的 docker-compose.yml 中:
注意:
wait-for-it.sh
脚本来自: https://github.com/vishnubob/wait-for-it