[Docker] docker composeで構築したMySQLに接続する3つの方法

2023/05/20に公開

docker composeで構築したMySQLに接続する方法をまとめておこうと思います!

なお、本記事ではdockerについての詳しい説明はあまり行なっておりませんのでご了承下さい。

docker composeで構築したデータベース

下記のdocker-compose.ymlを用意して、docker compose up -dコマンドでDockerコンテナを作成します。

docker-compose.yml
version: '3.9'

services:
  database:
    image: mysql:8.0.33
    container_name: mysql-container
    ports:
      - '3006:3306'
    environment:
      MYSQL_DATABASE: employees
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - ./database/initialize:/docker-entrypoint-initdb.d
      - ./database/config/my.cnf:/etc/mysql/conf.d/my.cnf

ポイント

  • コンテナ名をmysql-containerにしていること
  • Dockerのポートフォワード機能を利用して、ホストマシン(私の場合はローカルMac)のポート3006とDockerコンテナ内のポート3306を結びつけ、ホストマシンのポート3006へのアクセスをDockerコンテナ内のポート3306に転送するようにしていること
    • 私のローカルマシンで既にMySQLがポート3306を使っている関係で、ホストマシンのポートに3306を指定すると競合エラーが発生したため、ポート番号を3306以外にしています。
  • environment: にMySQLデータベースに関する情報を定義していること
  • volumes:でMySQLコンテナに対するカスタム設定を定義していること(データ初期化、文字化け対策)

コンテナ内のMySQLのデータベースを初期化しています。

./database/initialize/init.sql
// テーブル作成
CREATE TABLE IF NOT EXISTS EMPLOYEE (
  EMPLOYEE_ID VARCHAR(10) NOT NULL PRIMARY KEY,
  EMPLOYEE_NAME VARCHAR(256) NOT NULL,
  GENDER VARCHAR(256) NOT NULL,
  CREATE_AT TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  UPDATE_AT TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
// データ登録
INSERT INTO EMPLOYEE (EMPLOYEE_ID, EMPLOYEE_NAME, GENDER) VALUES ('dummy', 'ダミー', 'FEMALE');

日本語が文字化けしないようにカスタム設定を追加します。

my.cnf
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

[client]
default-character-set=utf8

さて、DockerコンテナにMySQLを構築できましたので、接続方法を見ていきます。

MySQLクライアントを使用する方法

ホストマシン(私の場合はローカルMac)に、MySQLクライアントがインストールされていることが前提になります。

ターミナルで下記コマンドを実行したときにバージョン情報が表示されていればMySQLクライアントがインストールされています。

% mysql --version
mysql  Ver 8.0.33 for macos12.6 on arm64 (Homebrew)

もし、下記のような表示になる場合はMySQLクライアントがインストールされていないか、もしくはシステムのパスが正しく設定されていないので、確認するようにして下さい。

mysql: command not found

さて、MySQLクライアントがインストールされている前提で進めます。

Dockerコンテナに構築したMySQLに、MySQLクライアントを利用して接続するためには下記のコマンドを実行します。

mysql -u user -p -h 127.0.0.1 --port 3006 -D employees

コマンドを叩くとEnter password: が出るのでpasswordを入力すると接続できます。

ポイント① ポートに --port 3006 を指定していること

ここはDockerのポートフォワード機能を利用するためにdocker-compose.ymlで定義したports: - '3006:3306'のホストマシン側のポート番号から来ています。

ポイント② ホストに -h 127.0.0.1 を指定していること

  • -h localhostを指定するとERROR 1045 (28000): Access denied for user 'user'@'localhost' (using password: YES)が発生します。
  • これはMySQLにおけるlocalhostはネットワーク経由ではなく、ホストマシンのOSが管理しているファイルシステム上のUNIXソケットを通じて接続することを意味しており、Dockerコンテナ内からはホストマシンのリソースに直接アクセスできないため失敗します。
  • 一方127.0.0.1はネットワーク(具体的にはTCP/IP)を通じて接続を試みます。Dockerのポートフォワードは正常に作用し、ホストマシンの特定ポートからDockerコンテナ内のMySQLサーバーへの接続を可能にします。

docker execコマンドを使用する方法

docker exec -it mysql-container mysql -u user -p -D employees

docker execはDockerのコマンドの1つで、実行中のDockerコンテナ内でコマンドを実行するために使用されます。-itは2つの略語オプション(-i-t)を一緒に使ったものですが、そういうものなんだなという理解でいったん良い気がします。

ポイント① コンテナ名mysql-containerを指定していること

docker-compose.ymlで定義したcontainer_name: mysql-containerから来ています。コンテナ名ではなく、コンテナID(644cfa84b130)を指定することもできます。

% docker ps 
CONTAINER ID   IMAGE          COMMAND                   CREATED          STATUS          PORTS                               NAMES
644cfa84b130   mysql:8.0.33   "docker-entrypoint.s…"   56 minutes ago   Up 56 minutes   33060/tcp, 0.0.0.0:3006->3306/tcp   mysql-container

ポイント② ホストやポートを指定していないこと

ここでは、MySQLクライアントと違い、ホストやポートを指定していません。
docker execは実行中のDockerコンテナ内でコマンドを実行するために利用することを説明しました。この『Dockerコンテナ内』というのがミソです。

ホスト名(-hオプション)やポート番号(--portオプション)を指定しない場合、mysqlコマンドはデフォルトでlocalhost(つまり、コマンドが実行されている同じシステム=ここではDockerコンテナ)のデフォルトのMySQLポート(通常は3306)に接続しようとします。

つまり、docker execを使ってDockerコンテナ内で実行している場合、localhostはそのコンテナ自体を指し、ポートはMySQLのデフォルトポート(3306)に自動的に接続してくれるため、ホスト名やポート番号を明示的に指定する必要はありません。

データベースのクライアントツールを使用する方法

『Dbeaver』を利用した接続方法をご紹介しますが、その他のデータベースクライアントツールでも同様の設定かと思います。

  • 新しい接続を作成する -> 新しい接続タイプを選択する で「MySQL」を選択します。

  • MySQL接続設定でdocker-compose.ymlに定義したデータベース情報を入力します。(portは3006にすること)

  • 正常に接続されて、テーブルを参照できています。

参考

https://hub.docker.com/_/mysql

Discussion