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つのコンテナを作成します。
いろいろ書いてありますが、重要なのは、以下の 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
参考
Discussion