docker-composeでAPPコンテナがDBコンテナの起動完了を待ってくれない問題を手軽に解決する

# 概要
先日Dockerに初めて触れた際， DBコンテナより先にアプリケーションコンテナが立ち上がってしまう問題が起きました．
Dockerfileで `depends_on` を指定すると起動順序の制御はできたのですが，コンテナの起動完了までは待ってくれないためアプリケーションコンテナでエラーが発生してしまうというものです．

調べてみると， シェルを書いて解決している記事が多かったのですが， より手軽に解決できるライブラリを発見しました．

## 使用技術
- spring boot (Java)
- MySQL
- Docker

## docker-compose-wait
本記事で紹介するのは `docker-compose-wait` というライブラリです．
https://github.com/ufoscout/docker-compose-wait

とりあえず試したい方．今回作成したサンプルリポジトリです．
https://github.com/YutaSeki36/spring-boot-docker-maven


## 1. ライブラリなしでコンテナをビルドしてみる

まずはライブラリ無しでコンテナをビルドしてみます．
以下の画像のように，DBコンテナが起動した瞬間にアプリケーションコンテナが起動してしまいます．
<img width="1440" alt="スクリーンショット 2019-10-15 23.12.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/f5be6d70-73c3-322f-c8ab-43c9ac2eb89c.png">

アプリケーションコンテナはDBコンテナに依存しているため， DBコンテナの起動が完了していない状態でアプリケーションコンテナが起動してしまうと以下のようにエラーが発生してしまいます．
<img width="1440" alt="スクリーンショット 2019-10-15 23.17.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/b027ff45-b560-1289-6109-6545622ab6c1.png">


この状況を解決するためには，以下のようにシェルを書いて解決する場合が多いです．
https://docs.docker.com/compose/startup-order/

しかし，　`docker-compose-wait` を使うとシェルをほぼ書かずに解決することができます．


## docker-compose-waitを使ってみる

### 1. Dockerfile変更
Dockerfileを以下のようにします．
コメントがある部分でライブラリの追加を行なっています．

```
FROM maven:3.3.9-jdk-8-alpine AS build
COPY ./ /work
WORKDIR /work
RUN mvn clean package

FROM openjdk:8u181-jre-alpine3.8

WORKDIR /home

COPY ./run.sh /usr/local/bin/run.sh
RUN chmod +x /usr/local/bin/run.sh

# waitライブラリの追加
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.6.0/wait /wait 
# ライブラリの権限変更
RUN chmod +x /wait

COPY --from=build /work/target/dtest-0.0.1-SNAPSHOT.jar /home/

CMD /wait && /usr/local/bin/run.sh
```

### 2. docker-composeを変更

Dockerfileを変更したらdocker-composeを修正します．
以下のように，waitさせたいコンテナのenvironmentに起動を待ちたいコンテナのホストを定義します．

```
version: '2'
services:
  dbserver:
    build: ./docker/mysql
    image: demo-db:0.0.1
    restart: always
    environment:
      MYSQL_DATABASE: demo_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: rootpassword
    ports:
      - "3314:3306"
    volumes:
      - ./docker/mysql/initdb.d:/docker-entrypoint-initdb.d
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
      - ./log/mysql:/var/log/mysql

  app:
    build: ./
    image: dtest/boot:0.0.1
    depends_on: # 依存関係をここで指定できるが，順序を指定できるだけで起動を待ってくれたりはしない
      - dbserver
    ports:
      - "8080:8080"
    volumes:
      - .:/app
    environment:
      # waitするホストを指定する．
      # 複数のwait_hostを指定することもできます．(MySQLだけでなくRedisの起動を待ちたい時なども便利です．)
      WAIT_HOSTS: dbserver:3306

volumes:
  mysql-db:
    driver: local
```

### ビルド
以上のファイル修正を行なってから `docker-compose up --build` を実行してみましょう．
先ほどはDBコンテナが起動してからすぐにアプリケーションコンテナが起動してしまいましたが，今度はアプリケーションコンテナがDBコンテナの起動完了を待っている状態になります．

<img width="1295" alt="スクリーンショット 2019-10-15 23.41.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/a789694e-02d7-6655-9fd5-a6baaa718c23.png">


そして無事にDBコンテナの起動が完了してからアプリケーションコンテナの起動が始まりました．
先ほどはエラーでこけてしまいましたが，今回はエラーなくアプリケーションの実行が完了しました．
<img width="1440" alt="スクリーンショット 2019-10-15 23.40.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214145/a6e47791-9b99-9958-1595-1c8e27b405e2.png">


## まとめ

今回は `docker-compose-wait` の紹介でした．
自分自身，このライブラリを使い倒した訳ではないので基本的な使い方のみの紹介になってしまいました．
詳細はリポジトリのREADMEで確認をお願いします．
https://github.com/ufoscout/docker-compose-wait

他記事にて誤字脱字や誤った情報など記載していたらコメントで指摘していただけると幸いです！