💨

docker composeの network で起動順序を設定するシェルスクリプト

2021/12/02に公開

概要

docker compose で DB サーバとバックエンドサーバを同時に起動すると、DB サーバが見つからないというエラーが発生してしまいます。docker compose のdepends onであるコンテナの起動する順番を制御できますが、起動完了までは待ってくれません

そこで、docker compose の公式リファレンスにもあるように、起動順序を制御するスクリプトを作成しました。

解決策

起動順序を制御するスクリプト、docker-compose.yml と wait-for-db-contaner について説明していきます。
docker compose upを実行すると、backend-container の内部の処理は db-container の起動が終わるまで待つようになります。

docker-compose.yml

今回使用する docker-compose.yml は以下のようになります。
Node.js で作られたバックエンドサーバである backend-container と、MySQL で作られた DB サーバの db-container という2つのコンテナを作成します。

いろいろ書いてありますが、重要なのは、以下の 2 つです。

  • db コンテナがあり、backend コンテナが./.envを読み込んでいる
  • 実行時のコマンドは["./wait-for-db-container.sh", "yarn", "start"]である
version: "3.5"
services:
  backend:
    build:
      context: "./"
      dockerfile: "Dockerfile"
    container_name: backend-container
    restart: always
    tty: true
    networks:
      - app-net
    expose:
      - "4000"
    ports:
      - "4000:4000"
    env_file:
      - "./.env"
    depends_on:
      - "db"
    command: ["./wait-for-db-container.sh", "yarn", "start"]
  db:
    image: mysql:5.7.34
    container_name: db-container
    environment:
      MYSQL_DATABASE: "typeorm_db"
      MYSQL_ROOT_PASSWORD: "password"
      TZ: "Asia/Tokyo"
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    expose:
      - "3306"
    ports:
      - "3306:3306"
    volumes:
      - ./initdb.d:/docker-entrypoint-initdb.d
    restart: "always"
    networks:
      - app-net
networks:
  app-net:
    driver: bridge

また、db_container のenv_file で読み込んでいる .env ファイルの中身は以下のようになっています。

PORT=4000

# DB
DB_HOST=db-container
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=password
DB_DATABASE=typeorm_db

wait-for-db-cotainer.sh

docker compose upでコンテナを起動したとき、backend-container は DB サーバの起動を待つシェルスクリプトが実行されます。
具体的には、wait-for-db-container.shが実行されます。

MySQL コマンドから DB サーバでexitを実行するコマンドを送ります。
環境変数は .env ファイルから読み込まれています。
これは、エラーでない結果が返ってくるまで、until文が実行を続けます。

エラーでない正常終了を取得したら、until文が終了し、DB が起動したことを伝えます。
この後、wait-for-db-container.shは実行時の残りの引数を実行します。docker-compose.yml でyarn startを与えているため、バックエンドの Node.js アプリケーションが起動します。

#!/bin/bash

set -e
cmd="$@"

until mysql -u $DB_USERNAME --port $DB_PORT -h $DB_HOST -p$DB_PASSWORD -D $DB_DATABASE -e 'exit' ; do
  2>&1 echo "$DB_HOST is unavailable - sleeping"
  sleep 10
done

>&2 echo "$DB_HOST is up"
exec $cmd

参考

https://docs.docker.jp/compose/startup-order.html

https://qiita.com/Uryy/items/71bcb29858c111adc63a

https://qiita.com/sivertigo/items/9baa73d922a68788402b

Discussion