【Docker】【MySQL】コンテナ初回起動時にスクリプトを実行させる
はじめに
【Docker】MySQLを簡単に構築
でMySQL
環境まで構築しました。
これだけでも使い出すのには十分だけど、コンテナを作成するたびにテーブルを作り直す必要があったり、テストデータのinsertもあって…わりかし面倒。
こういったところも、コンテナ起動と同時に実行し、楽したい。
詳細は公式ドキュメントを参照
目的
- 初回コンテナ起動時に、任意のSQLまたはシェルスクリプトが実行できること
環境
【Docker】MySQLを簡単に構築
で作った環境を流用しています。
docker-compose.ymlファイル 修正
概要
内容としては簡単で、コンテナ内の/docker-entrypoint-initdb.d
に配置するだけで、.sh
や.sql
を実行してくれます。
ディレクトリ構成
mysql
∟ conf
∟ my.cnf
∟ script
∟ initShell.sh # ★ 作成
∟ initDb.sql # ★ 作成
∟ .env
∟ docker-compose.yml
yamlファイル修正
version: '3'
services:
db:
image: mysql:8
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${ROOT_PASS}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASS}
TZ: ${TZ}
ports:
- ${DB_PORT}:3306
volumes:
- db-store:/var/lib/mysql
- ./conf/my.cnf:/etc/mysql/conf.d/my.cnf
# ★ ローカルのscriptディレクトリにマウントします
- ./script:/docker-entrypoint-initdb.d
volumes:
db-store:
実行スクリプト
今回script
ディレクトリに配置したのは、下記のような感じの物。
.shファイル
echo "### initialize start ####"
mkdir /tmp/test
touch /tmp/test/aaaa
echo "### initialize end ####"
.sqlファイル
create table sample1(
id int auto_increment,
col1 text,
col2 text,
primary key (id)
) ;
insert into sample1(col1, col2)values('aaa', '1111');
insert into sample1(col1, col2)values('bbb', '2222');
insert into sample1(col1, col2)values('ccc', '3333');
insert into sample1(col1, col2)values('ddd', '4444');
実行スクリプト作成での補足
-
docker-entrypoint-initdb.d
内に複数のスクリプトが存在する場合、名前順で実行 - 実行タイミングは、
/var/lib/mysql
がない場合に実行される(後述に記載) -
.sql
ファイルは、yamlの環境変数MYSQL_DATABASE
で指定したユーザへインポート -
.sh
はmysqlユーザで実行(root権限で実行できないため、任意のパッケージをインストールしたい場合は、下記のようにDockerfileを作成してインストールする)
root権限が必要な操作について(.sh)
docker-entrypoint-initdb.d
内のスクリプトは、mysql
ユーザの権限で実行されるため、パッケージのインストールをやりたい場合は、Dockerfileを作成して実行。
【個人的な所感】
DBコンテナとして利用する想定のため、root権限が必要なshellを自動で実行させるという想定がなかなか思い浮かばない。
あるとしたら、調査しやすいようにviとかコマンドのインストールぐらいかなと
Dockerfile
FROM mysql:8
RUN echo "##### command install ##########"
RUN apt-get update
RUN apt-get install -y vim
# CMD ["/startup.sh"] ★ CMDは上書きしてはならない
★ 公式配布のimageはもともと、CMDでmysqld
を実行しているが、上記のようにするとそれを上書きしてしまう。
最後に複数コマンドを実行させたい場合など、.sh
ファイルにまとめて記載しその中でMySQLを起動するmysqld
を改めて呼べばいいやと考えたが、シェルファイル経由で呼び出すと権限周りでうまくコンテナが起動しなくなる…
docker-comose.yml
services:
db:
build:
context: . # ★Dockerfileへのパス指定
dockerfile: Dockerfile # ★Dockerfileへのパス指定
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${ROOT_PASS}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASS}
TZ: ${TZ}
ports:
- ${DB_PORT}:3306
volumes:
- db-store:/var/lib/mysql
- ./conf/my.cnf:/etc/mysql/conf.d/my.cnf
- ./script:/docker-entrypoint-initdb.d
volumes:
db-store:
コンテナの起動と確認
実行
docker-compose up -d
確認
ログ確認
[Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running~
の行で実行されていることが確認できます。
mysql | 2022-02-13 11:52:14+09:00 [Note] [Entrypoint]: Giving user user access to schema hoge-db
mysql |
mysql | 2022-02-13 11:52:14+09:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/initDB.sql
mysql |
mysql |
mysql | 2022-02-13 11:52:14+09:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/initShell.sh
mysql | ### initialize start ####
mysql | ### initialize end ####
mysql |
mysql | 2022-02-13 11:52:14+09:00 [Note] [Entrypoint]: Stopping temporary server
mysql | 2022-02-13T02:52:14.791132Z 14 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 8.0.28).
mysql | 2022-02-13T02:52:16.878878Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.28) MySQL Community Server - GPL.
mysql | 2022-02-13 11:52:17+09:00 [Note] [Entrypoint]: Temporary server stopped
mysql |
mysql | 2022-02-13 11:52:17+09:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
また、.sh
ファイルに記載したecho
の内容が出力されていることも確認できました。
DB確認
テーブルが作成できデータも追加されていることが確認できました。
スクリプトファイルの起動は、本当にコンテナ起動時なのか?
タイトルでは、コンテナの初回起動時と記載したが…正確には/var/lib/mysql
のDBファイル有無で判定している模様。
なので、tmpfs:
へマウントしている場合や、マウントしていたvolumeを消した場合はコンテナを消していなくても毎回実行してくれる。
Discussion
yamlファイル修正
★ ローカルのscriptディレクトリにマウントします
の部分ですが
./script:ではなく、./conf/script:のような気がしますがいかがでしょうか?
コメントありがとうございます!
ディレクトリ構成のインデントが少しずれていたので、修正しました。
script
ディレクトリは、docker-compose.yml
と同階層にあることを想定してyamlファイルを作成していますので、./script:
の表記のままで正しいです。そうでしたか!失礼いたしました。
とても参考になりました、ありがとうございます。