dockerのmariadbコンテナ、接続可能になっていればマイグレーションも全て終わっている

公式 mariadb イメージのページ https://hub.docker.com/_/mariadb の

> No connections until MySQL init completes

の項によれば、もろもろ終わるまでの間は接続を受け付けないから docker-compose とかで同時に複数コンテナを立ち上げて利用したい場合は気をつけて、とのことです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/27471/55ece22b-4af1-4385-e94b-165769830e6e.png)

では実際に mariadb コンテナの挙動を見てみます。

```console
$ mkdir /tmp/mariadb
$ cd /tmp/mariadb
$ vim docker-compose.yml
```
```yml:docker-compose.yml
version: '2'
services:
  mariadb:
    image: mariadb:latest
    environment:
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
      - MYSQL_RANDOM_ROOT_PASSWORD=yes
    volumes:
      - ./migrations:/docker-entrypoint-initdb.d
```

マイグレーションのフリをしてスリープするだけの SQL を置いておきます。

```console
$ mkdir migrations
$ vim migrations/00-sleep.sql
```
```sql:00-sleep.sql
select sleep(3);
```

なんとなく複数ある場合を想定してコピーしておきます。

```console
$ cp migrations/00-sleep.sql migrations/01-sleep.sql
```

おもむろに立ち上げます。

```console
$ docker-compose up
```

そうするとログがこのように流れます。

```console
mariadb_1  | Initializing database
mariadb_1  |
(略)
mariadb_1  |
mariadb_1  | Database initialized
mariadb_1  | MySQL init process in progress...
(略)
mariadb_1  | 2018-12-27  6:24:38 0 [Note] mysqld: ready for connections.
(略)
mariadb_1  |
mariadb_1  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/00-sleep.sql
mariadb_1  | sleep(3)
mariadb_1  | 0
mariadb_1  |
mariadb_1  |
mariadb_1  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/01-sleep.sql
mariadb_1  | sleep(3)
mariadb_1  | 0
mariadb_1  |
mariadb_1  |
mariadb_1  | 2018-12-27  6:24:47 0 [Note] mysqld (initiated by: unknown): Normal shutdown
(略)
mariadb_1  | 2018-12-27  6:24:48 0 [Note] mysqld: Shutdown complete
mariadb_1  |
mariadb_1  |
mariadb_1  | MySQL init process done. Ready for start up.
mariadb_1  |
(略)
mariadb_1  | 2018-12-27  6:24:49 0 [Note] mysqld: ready for connections.
mariadb_1  | Version: '10.3.11-MariaDB-1:10.3.11+maria~bionic'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
```

これを見るに、どうやら

1. 起動して初期化処理が走り
2. ready for connections となり
3. マイグレーションが走り
4. 一度 shutdown して
5. また起動して ready for connections となる

ようでした。

ということは、他のコンテナから mariadb を利用したい場合、たとえば [dockerize](https://github.com/jwilder/dockerize) の wait 等で mariadb コンテナの 3306 ポートが開くまでを待つだけでは不完全で、最新のマイグレーション SQL まで本当に適用完了したのかをチェックしながら待たなければならないではないか？そうでないと、上記の流れのとおりマイグレーション前やマイグレーション真っ最中にも ready for connections になっているのだから、そのタイミングで他のコンテナの自動テスト等が走り始めてしまったらマズイのではないか？と、思っていました。

いったん落とします。

```console
$ docker-compose down
```

では実際にどのタイミングで外部からの接続を受け付けてくれるのか？ docker-compose.yml を編集して、 wait というコンテナを追加します。

```conosle
$ vim docker-compose.yml
```

```yml:docker-compose.yml
version: '2'
services:
  mariadb:
    image: mariadb:latest
    environment:
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
      - MYSQL_RANDOM_ROOT_PASSWORD=yes
    volumes:
      - ./migrations:/docker-entrypoint-initdb.d
  # ↓ 追加
  wait:
    image: jwilder/dockerize:latest
    depends_on:
      - mariadb
    command: dockerize -wait tcp://mariadb:3306 -timeout 30s echo GOAL!
```


command 行を抜き出して書くと ↓ で、ここでは dockerize の wait で mariadb のポートが開くのを待って、開いたら GOAL と表示することにしました。

```sh
dockerize -wait tcp://mariadb:3306 -timeout 30s echo GOAL!
```

それでは立ち上げます。

```console
$ docker-compose up
```

```console
mariadb_1  | Initializing database
wait_1     | 2018/12/27 07:09:19 Waiting for: tcp://mariadb:3306
wait_1     | 2018/12/27 07:09:19 Problem with dial: dial tcp 172.26.0.2:3306: getsockopt: connection refused. Sleeping 1s
(略)
mariadb_1  |
mariadb_1  | Database initialized
mariadb_1  | MySQL init process in progress...
(略)
mariadb_1  | 2018-12-27  7:09:22 0 [Note] mysqld: ready for connections.
(略)
mariadb_1  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/00-sleep.sql
wait_1     | 2018/12/27 07:09:25 Problem with dial: dial tcp 172.26.0.2:3306: getsockopt: connection refused. Sleeping 1s
wait_1     | 2018/12/27 07:09:26 Problem with dial: dial tcp 172.26.0.2:3306: getsockopt: connection refused. Sleeping 1s
wait_1     | 2018/12/27 07:09:27 Problem with dial: dial tcp 172.26.0.2:3306: getsockopt: connection refused. Sleeping 1s
mariadb_1  | sleep(3)
mariadb_1  | 0
mariadb_1  |
mariadb_1  |
mariadb_1  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/01-sleep.sql
wait_1     | 2018/12/27 07:09:28 Problem with dial: dial tcp 172.26.0.2:3306: getsockopt: connection refused. Sleeping 1s
wait_1     | 2018/12/27 07:09:29 Problem with dial: dial tcp 172.26.0.2:3306: getsockopt: connection refused. Sleeping 1s
wait_1     | 2018/12/27 07:09:30 Problem with dial: dial tcp 172.26.0.2:3306: getsockopt: connection refused. Sleeping 1s
mariadb_1  | sleep(3)
mariadb_1  | 0
mariadb_1  |
mariadb_1  |
mariadb_1  | 2018-12-27  7:09:30 0 [Note] mysqld (initiated by: unknown): Normal shutdown
(略)
mariadb_1  | 2018-12-27  7:09:31 0 [Note] mysqld: Shutdown complete
mariadb_1  |
mariadb_1  |
mariadb_1  | MySQL init process done. Ready for start up.
mariadb_1  |
(略)
mariadb_1  | 2018-12-27  7:09:32 0 [Note] mysqld: ready for connections.
mariadb_1  | Version: '10.3.11-MariaDB-1:10.3.11+maria~bionic'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
wait_1     | 2018/12/27 07:09:32 Connected to tcp://mariadb:3306
wait_1     | GOAL!
wait_1     | 2018/12/27 07:09:32 Command finished successfully.
```

これによって、なんとありがたいことに、

1. 起動して初期化処理が走り
2. ready for connections となり（しかし外部からはまだつながらない状態である）
3. マイグレーションが走り
4. 一度 shutdown して
5. また起動して ready for connections となる（ここでやっと外部からつながって GOAL! と表示された）

というタイミングだったことがわかりました。

つまり何も難しいことを考えなくとも、とにかく接続が可能になっていればマイグレーションも全部終わった状態ですということでした。わかりやすい。