Dockerコンテナ起動した時にDBのテーブルが作成される仕組みの確認

研修でのアプリ作成の開発環境に、これまでに用意いただいて使用していた、あり合わせの Dockerfile 、 docker-compose.yml を使用していました。

コードレビューしていただいた時に「ところで、Dockerコンテナを作成・起動した時に、MySQLのデータベースにテーブルが作成されるのはなんで？」と確認の質問をいただき、さっぱり答えられなかったので、 答えられるよう理解するためのアウトプットです。

# 1. 理解したいこと

- 下記Docker関連のファイルの中で、DBのテーブル（下記の docker/mysql/initdb.d/01_products.sql ）を自動作成してくれている仕組みを理解したい。

### docker-compose.yml

```yaml
version: "3.6"
services:
  web:
    build:
      context: .
      dockerfile: ./docker/nginx/Dockerfile
    depends_on:
      - app
    ports:
      - ${WEB_PORT:-80}:80
    volumes:
      - ./doc_root/public:/var/www/sample-app/public

  app:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile
    environment:
      MYSQL_DATABASE: ${DB_NAME:-sample_app}
      MYSQL_USER: ${DB_USER:-db_user}
      MYSQL_PASSWORD: ${DB_PASS:-secret}
    depends_on:
      - db
    links:
      - db:mysql
    volumes:
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini
      - ./doc_root:/var/www/sample-app

  db:
    build:
      context: .
      dockerfile: ./docker/mysql/Dockerfile
    environment:
      MYSQL_DATABASE: ${DB_NAME:-sample_app}
      MYSQL_USER: ${DB_USER:-db_user}
      MYSQL_PASSWORD: ${DB_PASS:-secret}
      MYSQL_ROOT_PASSWORD: ${DB_PASS:-secret}
    ports:
      - ${DB_PORT:-3306}:3306
    volumes:
      - db-data:/var/lib/mysql
volumes:
  db-data:
    driver: local
```

### docker/mysql/Dockerfile

```docker
FROM mysql:5.6

# timezone environment
ENV TZ=Asia/Tokyo

COPY ./docker/mysql/my.cnf /etc/mysql/conf.d/my.cnf
COPY ./docker/mysql/initdb.d /docker-entrypoint-initdb.d

CMD [ "mysqld", "--character-set-server=utf8", "--collation-server=utf8_unicode_ci" ]
```

### docker/mysql/initdb.d/01_products.sql

```sql
SET CHARACTER_SET_CLIENT = utf8;
SET CHARACTER_SET_CONNECTION = utf8;

CREATE TABLE products (
    id                    INTEGER AUTO_INCREMENT PRIMARY KEY,
    price                 INTEGER NOT NULL,
    image                 VARCHAR(256),
    delete_flag           BOOLEAN NOT NULL DEFAULT FALSE,
    created_at            DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at            DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
```

### docker/mysql/my.cnf

```
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci

[client]
default-character-set=utf8mb4
```

# 2. わからないこと

- 上記Docker関連のファイルの中で、テーブルを自動作成してくれている仕組みがわからない。

### docker/mysql/Dockerfile のテーブル作成に関連すると思う箇所

```docker
COPY ./docker/mysql/initdb.d /docker-entrypoint-initdb.d
```

# 3. 調べたこと



> **Initializing a fresh instance**
> 
> 
> When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions `.sh`, `.sql` and `.sql.gz` that are found in `/docker-entrypoint-initdb.d`. Files will be executed in alphabetical order. You can easily populate your `mysql` services by [mounting a SQL dump into that directory](https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-file-as-a-data-volume) and provide [custom images](https://docs.docker.com/reference/builder/) with contributed data. SQL files will be imported by default to the database specified by the `MYSQL_DATABASE` variable.
> 
> （以下、DeepL翻訳）
> **新しいインスタンスの初期化**
> 
> コンテナが初めて起動されると、指定された名前の新しいデータベースが作成され、提供された設定変数で初期化されます。さらに、`/docker-entrypoint-initdb.d` にある拡張子 `.sh`, `.sql`, `.sql.gz` のファイルがアルファベット順で実行されます。このディレクトリにSQLダンプをマウントすることで、簡単に`mysql`サービスにデータを取り込むことができ、カスタムイメージにデータを提供することができます。SQLファイルはデフォルトで`MYSQL_DATABASE`変数で指定されたデータベースにインポートされます。
> 

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

上記のとおり、**`/docker-entrypoint-initdb.d` にある拡張子 `.sql` を実行するようになっており、** 
```docker
COPY ./docker/mysql/initdb.d /docker-entrypoint-initdb.d
``` 
**でコピーされたファイルを、実行してくれている**ことがわかりました！

## その他、調べたこと
### mysqld
```docker
CMD [ "mysqld", "--character-set-server=utf8", "--collation-server=utf8_unicode_ci" ]
```

> **`mysqld` とは**
> 
> 
> **`mysqld`** は、MySQL サーバーとも呼ばれ、MySQL インストールでのほとんどの作業を実行するメインプログラムです。MySQL サーバーは、データベースおよびテーブルを含む MySQL データディレクトリへのアクセスを管理します。データディレクトリは、ログファイルおよびステータスファイルなど、その他の情報のデフォルトの場所でもあります。
> 

https://dev.mysql.com/doc/refman/5.6/ja/mysqld.html

### Docker コンテナ（dbコンテナ）起動時のログの確認

- ログ（抜粋）

```
2022-02-17 10:08:54+09:00 [Note] [Entrypoint]: Database files initialized
2022-02-17 10:08:54+09:00 [Note] [Entrypoint]: Starting temporary server
2022-02-17 10:08:54+09:00 [Note] [Entrypoint]: Waiting for server startup
2022-02-17 10:08:55+09:00 [Note] [Entrypoint]: Temporary server started.
2022-02-17 10:08:59+09:00 [Note] [Entrypoint]: Creating database sample_app
2022-02-17 10:08:59+09:00 [Note] [Entrypoint]: Creating user db_user
2022-02-17 10:08:59+09:00 [Note] [Entrypoint]: Giving user db_user access to schema sample_app

2022-02-17 10:08:59+09:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/01_products.sql

2022-02-17 10:08:59+09:00 [Note] [Entrypoint]: Stopping temporary server
2022-02-17 10:09:01+09:00 [Note] [Entrypoint]: Temporary server stopped

2022-02-17 10:09:01+09:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
```