2
1

More than 1 year has passed since last update.

docker-composeでDBコンテナに別コンテナからアクセスしたい

Posted at

前提

docker-composeとSQL系のデータベースを使用したことがなかったので、これらの技術を利用して
ハンズオンをしようとしていた際にエラーに直面。調べてもなかなか解決しなかったので議事録を残します。
DB:MySQL
API:Node.js
Node.jsなのでSequelizeで接続を試みています。

環境

docker-compose.yml
version: "3"

services:
  api:
    build: ./
    container_name: todo-api
    environment:
      DB_HOST: db
      DB_USER: todo
      DB_PASS: todo
      DB_DATABASE: todo
      DEBUG: todoapi:server
    tty: true
    ports:
      - 5001:5001
    volumes:
      - ./api:/home/node
    networks:
      - todoapp-network
    command: "npm run dev"
    depends_on:
      - db

  db:
    image: mysql:5.7
    platform: linux/amd64
    container_name: mysql
    restart: always
    environment:
      MYSQL_ROOT_HOST: todo-api
      MYSQL_ROOT_PASSWORD: ${DB_PASS}
      MYSQL_DATABASE: todo
      MYSQL_USER: todo
      MYSQL_PASSWORD: todo
    ports:
      - 3306:3306
    volumes:
      - ./db/docker/data:/var/lib/mysql
    networks:
      - todoapp-network
  
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
    networks:
      - todoapp-network

networks:
  todoapp-network:

Dockerfile
FROM node:18-slim

WORKDIR /home/node
USER node
app.js
const express = require("express");
const app = express();
const { Sequelize } = require("sequelize");
const PORT = 5001;

const sequelize = new Sequelize("todo", "todo", "todo", {
  host: "localhost",
  dialect: "mysql",
});

// expressでサーバー起動
app.listen(PORT, console.log("サーバーが" + PORT + "で起動しました。"));

// 接続の確認
const a = async () => {
  try {
    await sequelize.authenticate();
    console.log("Connection has been established successfully.");
  } catch (error) {
    console.error("Unable to connect to the database:", error);
  }
}

a();

https://sequelize.org/docs/v6/getting-started/#testing-the-connection
公式ドキュメントを確認すると関数aのように記述すると接続の確認ができるとのことでやってみました。

エラー内容

上記の環境でコンテナを立てて

local
$ docker-compose logs -f api

でログを確認したところ(docker-compose.ymlのファイル内のcommandでnpm run devでnodemonが動くようにしてます。)

エラー内容
todo-api  | Unable to connect to the database: ConnectionRefusedError [SequelizeConnectionRefusedError]: connect ECONNREFUSED 127.0.0.1:3306
todo-api  |     at ConnectionManager.connect (/home/node/node_modules/sequelize/lib/dialects/mysql/connection-manager.js:92:17)
todo-api  |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
todo-api  |     at async ConnectionManager._connect (/home/node/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:220:24)
todo-api  |     at async /home/node/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:174:32
todo-api  |     at async ConnectionManager.getConnection (/home/node/node_modules/sequelize/lib/dialects/abstract/connection-manager.js:197:7)
todo-api  |     at async /home/node/node_modules/sequelize/lib/sequelize.js:304:26
todo-api  |     at async Sequelize.authenticate (/home/node/node_modules/sequelize/lib/sequelize.js:456:5)
todo-api  |     at async a (/home/node/app.js:38:5) {
todo-api  |   parent: Error: connect ECONNREFUSED 127.0.0.1:3306
todo-api  |       at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) {
todo-api  |     errno: -111,
todo-api  |     code: 'ECONNREFUSED',
todo-api  |     syscall: 'connect',
todo-api  |     address: '127.0.0.1',
todo-api  |     port: 3306,
todo-api  |     fatal: true
todo-api  |   },
todo-api  |   original: Error: connect ECONNREFUSED 127.0.0.1:3306
todo-api  |       at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) {
todo-api  |     errno: -111,
todo-api  |     code: 'ECONNREFUSED',
todo-api  |     syscall: 'connect',
todo-api  |     address: '127.0.0.1',
todo-api  |     port: 3306,
todo-api  |     fatal: true
todo-api  |   }
todo-api  | }

確認したこと

基礎的な確認

・コンテナが起動し動作しているかの確認
・DBコンテナに入れるか
・DBコンテナに入った後、MySQLにログインできるか
など基礎的なことを確認したのちエラーについて調査。

エラー調査

「Error: connect ECONNREFUSED 127.0.0.1:3306」というエラーの記事はありましたが、
MySQLのversionが8からは認証の仕様が変わっているため
・hostの指定をlocalhostではなく、127.0.0.1にする
などがありましたが、Nodeとの互換性が悪いなどの記事を確認していたので5.7を使用しているため違いそう...

原因

docker-compose側の仕様でhost名はIPアドレスを指定するのではなく、DBコンテナのcontainer_nameを指定する必要がありました。
[他のDockerコンテナからコンテナ内のMySQLに接続する]
https://qiita.com/YuitoSato/items/4a4b46f5670b45739a37
この記事を確認するとSequelizeどうこうというよりも、mysqlのログインでhostを指定する場合、別コンテナにアクセスするにはIPアドレスではなくコンテナ名を指定する必要がある模様。
色々すっ飛ばして勉強するとインフラの肝心な部分の理解ができなくて困った案件でした。。。

app.js
const sequelize = new Sequelize("todo", "todo", "todo", {
  host: "mysql", // <= 私の場合はDBコンテナのcontainer_nameはmysqlだったので変更するだけ
  dialect: "mysql",
});
local
todo-api  | Executing (default): SELECT 1+1 AS result
todo-api  | Connection has been established successfully.

(1行目のログの意味もわかっていないのでまた勉強。DB側の話だと思うが...)

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1