🏄‍♂️

僕は今日もdepends_onと戯れる

2021/10/03に公開

Dockerfileとかdocker-compose書いてますかー?

自分はちょこちょこ書きます。
でも、全然イメージサイズとかマルチステージング構成とかは未熟で困ったもんですよ。
お勉強的な意味で書いてる感じです。

その中でちょこちょこあるんですが、docker-composeに書く「depends_on」。
こいつをちゃんと使えてなかった(理解してなかった)。
ここを公式をちゃんとみて、整理していく。

https://docs.docker.com/compose/startup-order/

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についてはとってもわかりやすい記事書いてくれている方がいたのでリンク貼っときます。
https://zenn.dev/hohner/articles/43a0da20181d34

一応、こんな感じですね。

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先も指定できるらしいので、複雑な構成だと助かるかも。

https://github.com/ufoscout/docker-compose-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 "$@"

https://docs.docker.com/compose/startup-order/

netcatをインストールしているイメージであれば以下のような書き方だと汎用的かも。

# !/bin/bash
echo "waiting for mysql server"

while ! nc -z db 3306; do
  sleep 1
done

echo "Connection Successfully"

exec "$@"

おしまい〜

GitHubで編集を提案

Discussion