結論
スキーマやレコード作成を記述したSQLファイルと、そのSQLを実行するシェルファイルを用意し、Dockerfileでコピー、もしくはdocker-compose.ymlのvolumeマウントで用意したファイルをMySQLコンテナの/docker-entrypoint-initdb.d/
に設置することで初回コンテナ起動時にシェルファイルが実行され、スキーマ、レコード作成を行うことができる。
docker-composeによる例
Dockerfile
FROM mysql:8.0.34
# SQLファイルをコピー(docker-compose.ymlでマウントする場合は不要)
# COPY /database/*.sql /database/
# # テストデータベース作成用のスクリプトをコピー(docker-compose.ymlでマウントする場合は不要)
# COPY /docker-entrypoint-initdb.d/init_db.sh /docker-entrypoint-initdb.d/
# # このフォルダにファイルをコピーして実行権限を付与しておけば初回コンテナ作成時に自動実行してくれる(docker-compose.ymlでマウントする場合は不要)
# RUN chmod +x /docker-entrypoint-initdb.d/init_db.sh
CMD ["mysqld", "--default-time-zone=Asia/Tokyo"]
docker-compose.yml
version: '3'
services:
rdb:
build: ./
platform: linux/x86_64
environment:
LANG: C.UTF-8
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: user
MYSQL_PASSWORD: user
TZ: 'Asia/Tokyo'
ports:
- "3306:3306"
volumes:
- sample-mysql-data:/var/lib/mysql
# DockerfileでCOPYする場合は以下の二行は不要
- ./database/:/database/
- ./docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d/
volumes:
sample-mysql-data:
init.sh
mysql -h localhost -u root -proot < /database/create_schema.sql
mysql -h localhost -u root -proot < /database/create_row.sql
create_schema.sql
CREATE SCHEMA IF NOT EXISTS `sample_db` DEFAULT CHARACTER SET utf8 ;
USE `sample_db`;
CREATE TABLE IF NOT EXISTS `sample_tbl` (
`id` CHAR(36) NOT NULL,
`text` VARCHAR(50) NOT NULL,
`created_at` DATETIME NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
create_row.sql
USE `sample_db`;
INSERT INTO `sample_tbl` (`id`, `text`, `created_at`) VALUES ('t78648f5-740f-4cb0-bf40-7213c58a8c91', 'text1', '2023-09-30 00:00:00');
INSERT INTO `sample_tbl` (`id`, `text`, `created_at`) VALUES ('t78648f5-740f-4cb0-bf40-7213c58a8c92', 'text2', '2023-09-30 00:00:00');
INSERT INTO `sample_tbl` (`id`, `text`, `created_at`) VALUES ('t78648f5-740f-4cb0-bf40-7213c58a8c93', 'text3', '2023-09-30 00:00:00');
INSERT INTO `sample_tbl` (`id`, `text`, `created_at`) VALUES ('t78648f5-740f-4cb0-bf40-7213c58a8c94', 'text4', '2023-09-30 00:00:00');
INSERT INTO `sample_tbl` (`id`, `text`, `created_at`) VALUES ('t78648f5-740f-4cb0-bf40-7213c58a8c95', 'text5', '2023-09-30 00:00:00');
ハマったこと
以下のケースに該当する場合はSQLファイルを更新して、コンテナを作り直してもスキーマなどが更新されません。
- Dockerfileでコピーのみを行ない、マウントしていない場合はその都度イメージ作り直さなければならない。
- ボリュームを作成し、/var/lib/mysqlをボリュームマウントしている場合はボリュームを削除しなければならない。
- docker-compose.ymlでSQLファイルやスキーマファイルをマウントにより共有している場合はホストで実行権限を付与しておかなければならない。
最後に
上記のことから開発環境で利用する場合は作成したデータが消えないようにボリュームを作成してマウントし、スキーマの変更があった場合は直接コンテナにアタッチしてMySQLにログインし、変更を反映することがいいように思いました。
また、自動テストで利用する場合はボリュームを作成せずにコンテナを作り直しただけでスキーマが反映されるようにすることがいいように思いました。