エラー文

node:events:371 throw er; // Unhandled ’error’ event ^ Error: connect ECONNREFUSED 172.29.0.2:3306 at TCPConnectWrap.afterConnect as oncomplete Emitted ’error’ event on Connection instance at: at Connection._notifyError (/app/node_modules/mysql2/lib/connection.js:225:12) at Connection._handleFatalError (/app/node_modules/mysql2/lib/connection.js:156:10) at Connection._handleNetworkError (/app/node_modules/mysql2/lib/connection.js:169:10) at Socket.emit (node:events:394:28) at emitErrorNT (node:internal/streams/destroy:157:8) at emitErrorCloseNT (node:internal/streams/destroy:122:3) at processTicksAndRejections (node:internal/process/task_queues:83:21) { errno: -111, code: ‘ECONNREFUSED’, syscall: ‘connect’, address: ‘172.29.0.2’, port: 3306, fatal: true }

原因1

データーベース接続先のホスト名がアドレスになっている。

修正前

const connection = mysql.createConnection({
    host: 'localhost:3306',
    user: 'root',
    password: "root",
    database: 'project',
});

修正後

const connection = mysql.createConnection({
    host: '[コンテナ名]',
    user: 'root',
    password: "root",
    database: 'project',
});

コンテナ名は、docker psとコマンドを実行した時にNAMESの行でも確認できる。

原因2

mysqlのデーターベースが起動完了する前にアクセスが発生している

docker-composeのバージョンが2.1以上の場合はhealthcheckを使うことでこの問題を解決できる。

services.db(mysqlのコンテナ)にhealthcheckを追加し、services.back(mysqlに依存している環境)にdepends_onを追加する。

--password==にはmysqlのパスワードを指定すること。.envファイルにパスワードを記載した環境変数を用意しておくのがおすすめ。

services:
  back:
    build:
      context: .
    depends_on:
      db:
        condition: service_healthy
  db:
    build:
      context: ./db
    healthcheck:
      test: "mysql --password=${MYSQL_ROOT_PASSWORD} --execute 'show databases;'"
      interval: 3s
      timeout: 30s
      retries: 10
      start_period: 0s

または、邪道ではあるがservices.back(mysqlに依存しているコンテナ)のentrypointを"/bin/sh -c ‘sleep 10 && node app’“のように設定し、10秒くらい待機することで解決もできる。

services:
  back:
    build:
      context: .
    entrypoint: "/bin/sh -c 'sleep 10 && node app'"