在將此問題標記為重複之前,請注意我確實閱讀了其他答案,但它並沒有解決我的問題。
我有一個包含兩個服務的 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 }
P粉3990907462024-01-22 12:20:58
這個:
mysql: image: mysql:5.7 environment: ... ports: - "3307:3306"
表示Docker會將主機的3307
連接埠對應到容器的3306
連接埠。因此您可以從 Sequel 存取 localhost:3307。
但是,這並不表示容器正在監聽3307
;事實上容器仍在監聽 3306
。當其他容器嘗試存取 mysql
DNS 時,它會轉換為內部容器 IP,因此您必須連接到 3306
。
所以你的節點配置應該如下:
const config = { host: 'mysql', database: 'mydb', port: '3306', user: 'mysql', password: '1234', connectionLimit: 10 }
這在你的 docker-compose.yml 中:
command: ["./wait-for-it.sh", "mysql:3306"]
注意:wait-for-it.sh
腳本來自: https://github.com/vishnubob/wait-for-it