Docker-MySQLでデータベースを最初から格納してコンテナを展開する方法

Docker-MySQLでデータベースを最初から格納してコンテナを展開する方法

Docker-MySQL:データベースをコピーしてコンテナ展開する方法

やりたかったことは『サイトの移動』です。

既存システムのDockerコンテナ化を目指したため、そもそも作成したデータベースがあります。
システム自体はLaravelで構築しているので【 php artisan migrate 】でテーブル作成してくれますが、既に登録しているデータのseederを作るのは正直しんどい。
なので、コピーできないかと試行錯誤していました。

正直色々な書き方があるのだと思います。Dockerfileで展開している人もいますが、私はdocker-composeを利用した作成方法を記載します。

Docker-MySQLでデータベースコピーする際の注意点

完成するまでの試行錯誤の中で、今になって思えば『コードはあっていたのに動かない』時がありました。
こればかりは知らないと出来ない事なので、注意点としてまとめます。

  1. /docker-entrypoint-initdb.d 内の実行順はファイル名順
  2. volumes: で明示したDirectoryは docker-entrypoint-initdb.dから見えない時がある。

以降、詳細を備忘録として記載します。

1. /docker-entrypoint-initdb.d 内の実行順はファイル名順

私がハマってしまった理由がこの実行順ルールを知らなかった事です。

よく考えれば疑問を持たなきゃいけない内容でしたが、そこまで頭が回らなかった…。
解らな過ぎてテンパってたんでしょうね。

image作成時に読込むdocker-entrypoint-initdb.dの登録

docker-entrypoint-initdb.d に登録した内容はイメージ作成時に1度だけ組み込まれる内容となります。
DockerfileのRUNと同じです。

docker-compose.yml に以下の様に記載する事で、任意のディレクトリをdocker-entrypoint-initdb.dとしてマウントできます。

上ではホストOS内の ./docker/mysql/entrypoint/というディレクトリをdocker-entrypoint-initdb.dとしています。

docker-entrypoint-initdb.d内ファイルの読込ルール

docker-entrypoint-initdb.dに記載したコードは以下のルールで読み込まれます。

  1. 拡張子【.sql】【.sh】【.sql.gz】のファイルを対象に読込実行
  2. 読込む順はファイル名のソート順
  3. 【.sql】はコンテナからmysqlにrootログインした状態で、そのままの文を実行
  4. 【.sh】はコンテナ上で(mysqlにログインしていない状態で)そのままの文を実行
  5. 【.sql.gz】は圧縮を解凍し、中身の .sql や .sh を実行

/docker-entrypoint-initdb.d としてマウントしたDirectoryの中身はファイル名でソートされた順に実行される。

これを早くに知っていれば…。

 私が最初に構成したファイル名(エラー原因の考察)

ファイル名:create_user.sql でユーザーを作成し
ファイル名:create_database.sql で必要なデータベースを作成し
ファイル名:copy_database.sh でデータベースをコピーする

こんな設計をしました。

この場合、ファイル名で並び替えると最初に【copy_database.sh】が走る事になります。
収納するデータベースが無いのに…。

ルールを考慮し変更したファイル名(エラー原因の修正)

ファイル名:01_create_user.sql でユーザーを作成し
ファイル名:02_create_database.sql で必要なデータベースを作成し
ファイル名:03_copy_database.sh でデータベースをコピーする

このように先頭に番号を振るだけで意図した実行順にする事が出来ます。

いやぁ~ここまでしんどかった…。

2. volumes: で明示したDirectoryは docker-entrypoint-initdb.dから見えない時がある

私がハマっていたもう一個の理由がこれです。

Dockerfileで書いてみたり、docker-composeで書いてみたりと行ったり来たりしたので頭がグチャグチャしたのでしょう。

実際に記載していた docker-compose.yml

意図した事はホストOSの./docker/mysql/backup_sql/ を コンテナ内 Backup_SQL としてマウントする事。
実際にこれを書いてmysqlコンテナに入り ls でフォルダ構成を確認するとちゃんとマウントされます。

DBが作成されなかった【03_copy_database.sh】の書き方(エラー原因の考察)

■Workspaseのイメージ

Laravel-Docker
├── docker/
│  └── mysql/
│      ├── data/
│      ├── entrypoint/
│      │  ├── 01_create_user.sql.sql
│      │  ├── 02_create_database.sql.sql
│      │  └── 03_copy_database.sh
│      ├── backup_sql
│      │  ├── Backup_database01.sql_
│      │  └── Backup_database02.sql_
│      ├── .env
│      └── my.cnf

├── docker-compose.yml
└── Laravel # 配信するLaravelコンテンツ

Backup_database01.sql は ./docker/mysql/backup_sql/内に保存しています。

ファイル名と保存場所を変えたらコピー実行を完了(エラー原因の修正)

色々試した中で、上手くいったのが docker-entrypoint-initdb.dとしてマウントするディレクトリ内にコピーしたいバックアップSQLを格納する事でした。

ただ、拡張子【.sql】は自動で読み込まれてしまうため、拡張子を【.sql_】と変更し読み込まれない様にします。

■Workspaseのイメージ

Laravel-Docker
├── docker/
│  └── mysql/
│      ├── data/
│      ├── entrypoint/
│      │  ├── 01_create_user.sql.sql
│      │  ├── 02_create_database.sql.sql
│      │  ├── 03_copy_database.sh
│      │  ├── Backup_database01.sql_
│      │  └── Backup_database02.sql_
│      ├── .env
│      └── my.cnf

├── docker-compose.yml
└── Laravel # 配信するLaravelコンテンツ

■03_copy_database.sh

逆算して浮かんだ原因は docker-entrypoint-initdb.dから見えるディレクトリ

根本原因は別にあるかもしれません。
しかし、同じCommandでも出来なかったと考えると原因はスクリプトではなく【Backup_database01.sql】が読込めたか否かなのだと思います。

となると、コンテナ作成時に読込む volumes: にも順番があり、それに準じていないため見えなかったのかもしれないと考えています。
まぁ、docker-entrypoint-initdb.dとしてマウントするディレクトリの中に収めてしまえば解決するのだから態々別にして不安定にする必要はないでしょう。

ユーザー作成とデータベース作成の .sql データをメモ

自分の備忘録でもあるので、ついでにメモします。

データベースに対する権限設定もしたかったため、最終的には 01_create_user.sql.sql と 02_create_database.sql は合成しました。

■ユーザー作成 & データベース作成 & 権限設定

この後にshellを走らせます。

まとめ

真面目に長かった…。

ググるとshellのスクリプトを 【docker-run 】と書き始めてる人がいたり【RUN 】で始めてる人がいたり【mysql -u name -p】を記載しないでメモしてる人がいたり。読み込む場所によって書き方が変わるからしょうがないのだろうけど、勉強し始めの私からすると混乱のもとでした。

迷走したなぁ~。

まぁ、実装出来て理解も進んだから良しとするか。