僕は今日もdepends_onと戯れる
Dockerfileとかdocker-compose書いてますかー?
自分はちょこちょこ書きます。
でも、全然イメージサイズとかマルチステージング構成とかは未熟で困ったもんですよ。
お勉強的な意味で書いてる感じです。
その中でちょこちょこあるんですが、docker-composeに書く「depends_on」。
こいつをちゃんと使えてなかった(理解してなかった)。
ここを公式をちゃんとみて、整理していく。
depends_onはあくまで、サービスの起動とシャットダウンの順序を制御しているだけで、コンテナ同士の状態を監視して起動するとか、ネットワーク間の疎通確認をしてくれるわけではないんです。
依存関係って言葉もありましたが、個人的には「依存関係」って言葉がまたややこしい響きなので私は敢えて使いません。(それが正しいとしても、なんか納得いかない)
例えば、docker-composeを大体こんな感じで書いてるはずですが、この場合だと、、
-
起動時は「db(データベース)」 -> 「web(アプリ)」の順
-
停止時は「web(アプリ)」 -> 「db(データベース)」 の順
みたいな感じで、コンテナの起動と停止順序を行っている。
version: '3.8'
services:
web:
build: .
ports:
- 8000:8000
volumes:
- .:/app
depends_on:
- db
db:
image: mysql:5.7.22
restart: always
environment:
MYSQL_DATABASE: develop
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
volumes:
- .db:/var/lib/mysql
ports:
- 3306:3306
ただし、前述に書いたとおり、これはあくまで起動順序だけのお話しである。
このままdocker-compose up
すると、db(データベース)が稼働前に、web(アプリ)が稼働するので、アプリケーション側が異常終了となります。(稀に出来るときがありました。)
というわけで、対処法を何個か見つけました。
シチュエーションは様々だと思うので、その時々で最適解を見つけたいですね。
ぼくのかんがえたさいきょうのたいしょほう
これ以外の解決法もあるかもですが、サっと試せたのは以下になります。
1. tty:true
コンテナの永続化ですね。まぁ、手っ取り早いのかなとは思うけどやや力技感は否めないなぁと思います。
あと、自分はttyつかってもアプリ落ちちゃうことあったから、一部ケースでは対応できないのかも?
ttyについてはとってもわかりやすい記事書いてくれている方がいたのでリンク貼っときます。
一応、こんな感じですね。
version: '3.8'
services:
web:
tty: true ## ここ
build: .
ports:
- 8000:8000
volumes:
- .:/app
depends_on:
- db
db:
image: mysql:5.7.22
restart: always
environment:
MYSQL_DATABASE: develop
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
volumes:
- .db:/var/lib/mysql
ports:
- 3306:3306
2. ライブラリを使う
調べてるうちに見つけて便利そうだなーと思ったやつ。
複数のwait先も指定できるらしいので、複雑な構成だと助かるかも。
# Dockerfileには以下を記載。詳しくは公式見て下さい。
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.9.0/wait /wait
RUN chmod +x /wait
CMD /wait
version: '3.8'
services:
web:
build: .
ports:
- 8000:8000
volumes:
- .:/app
depends_on:
- db
environment: # environmentを追加。
WAIT_HOSTS: db:3306 # wait先を指定する。"WAIT_HOSTS: host:port"
db:
image: mysql:5.7.22
restart: always
environment:
MYSQL_DATABASE: develop
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
volumes:
- .db:/var/lib/mysql
ports:
- 3306:3306
3. シェルを使う
公式も基本はシェルでやって。みたいなこと書いてるので個人的にはよっぽどでなければこれで良いかなと思ってます。(下記は公式のPostgresの例ですね)
#!/bin/sh
# wait-for-postgres.sh
set -e
host="$1"
shift
until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
exec "$@"
netcatをインストールしているイメージであれば以下のような書き方だと汎用的かも。
# !/bin/bash
echo "waiting for mysql server"
while ! nc -z db 3306; do
sleep 1
done
echo "Connection Successfully"
exec "$@"
おしまい〜
Discussion