🙌

MySQLコンテナの初回起動時にテーブルを作成してCSVデータをインポートする

2022/12/17に公開

やること

表題の通り、MySQLコンテナの初回起動時にテーブルを作成し、初期データをCSVからインポートします。

ディレクトリ構成

ルートディレクトリでdocker-compose up -dすればMySQLコンテナが立ち上がり、初期データがインポートされます。

.
├── docker-compose.yml
├── .env
└── docker
    └── mysql
         ├── Dockerfile
         ├── my.cnf
         └── initdb.d
	      ├── 0_create_db.sql
	      ├── 1_create_table.sql
	      ├── 2_import_inital_data.sql
	      └── initial-data
	           └── data.csv     

コンテナの基本設定

docker-compose.yml
./docker-compose.yml
version: '3'
services:
  mysql:
    container_name: mysql8
    build:
      context: ./docker/mysql
    volumes:
      - db-store:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=${DB_DATABASE}
      - MYSQL_USER=${DB_USERNAME}
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
      - TZ=${APP_TZ:-Asia/Tokyo}
    ports:
      - ${DOCKER_DB_PORT:-3306}:3306

volumes:
  db-store:
./.env
DOCKER_DB_PORT=3306
DB_DATABASE=test_db
DB_USERNAME=dev_user
DB_PASSWORD=password
APP_TZ=Asia/Tokyo

CSVデータのインポートを許可する

LOAD DATA INFILEを使うとCSVデータをインポートすることができます。
ただし、MySQL8.0ではデフォルトでCSVのインポートは禁止されており、サーバ側[mysqld]とクライアント側[mysql]の両方で明示的に許可する必要があります。参照

./docker/mysql/my.cnf
[mysql]
local-infile=1 

[mysqld]
local-infile=1 

ここで、クライアント側のオプショングループは、クライアント[client]ではなく、コマンドラインクライアント[mysql]であることに注意が必要です。参照

MySQLコンテナの初回起動時にSQLを実行する

MySQLコンテナの初回起動時に/docker-entrypoint-initdb.dに配置したSQLが実行されます。参照
SQLファイルが複数ある場合、名前順に実行されますので、数字をプレフィックスとして付けておくと良いかもしれません。
2回目以降のコンテナ起動ではvolumeを削除しないとSQLが実行されませんのでご注意ください。参照

./docker/mysql/Dockerfile
FROM mysql:8
 
# MySQL設定ファイルをコピー
COPY my.cnf /etc/mysql/conf.d/my.cnf
# データ初期化用SQLファイルコピー
COPY ./initdb.d /docker-entrypoint-initdb.d

EXPOSE 3306
初期データをインポートするSQLサンプル
./docker/mysql/initdb.d/0_create_db.sql
DROP SCHEMA IF EXISTS test_db;
CREATE SCHEMA test_db;
USE test_db;
./docker/mysql/initdb.d/1_create_table.sql
CREATE TABLE `employees` (
  `emp_no` int(11) NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
    PRIMARY KEY (emp_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC
./docker/mysql/initdb.d/2_import_inital_data.sql
load data local infile 
"/docker-entrypoint-initdb.d/intial-data/data.csv "  // コンテナ側のpathを指定
into table employees fields terminated by ',' optionally enclosed by '"' 
ignore 1 lines; // 2行目からインポート

Discussion