msksgm’s blog

msksgm’s blog

Webエンジニアです.日々の勉強,読書,映画観賞,美術観賞の記録を載せます.

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

概要

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つのコンテナを作成します。

いろいろ書いてありますが、重要なのは、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

参考

docs.docker.jp

qiita.com

qiita.com