85
Help us understand the problem. What are the problem?

posted at

updated at

Organization

docker-composeでDBの起動完了を待ってからWebアプリを実行する

はじめに

docker-composeで複数のコンテナを管理するとき、ほぼWebアプリとDBを一緒に使います。
大抵はWebアプリ側にdepends_onでDBのコンテナを指定して起動順序を制御しますが、あくまで起動順序だけなのでDBの起動完了前にWebアプリがDBにアクセスしてしまい起動失敗する事があります。

せっかくdocker-composeで1つにまとめて管理しているのに便利さが半減してしまうとモヤモヤしていたら、公式ではWebアプリ側でチェックせよと解説していました。

depends_on/condition

2021/07/21追記
depends_onで指定したサービスのhealthcheckが通ってから起動できるconditionが追加されました。これを使えばチェック用スクリプトを使わずにすみます。詳しくはDocker Compose の depends_on の使い方まとめを参照してください。

GitBucket + MySQLの場合

上述の公式の解説ではPostgreSQLを対象にしているのですが、MySQLをよく使うので書き換えてみました。

ファイル構成はこんな感じです。

files
docker-compose.yml
  + gitbucket/
      + Dockerfile
      + wait.sh

ベースイメージはalpine版なのでapkでmysql-clientをインストールしています。

gitbucket/Dockerfile
FROM java:8-jre-alpine
MAINTAINER shiena
ENV GITBUCKET_HOME /var/gitbucket
VOLUME ["${GITBUCKET_HOME}"]
EXPOSE 8080
RUN apk add --no-cache mysql-client
COPY wait.sh /wait.sh
ENV GITBUCKET_VERSION 4.7.1
ADD https://github.com/gitbucket/gitbucket/releases/download/${GITBUCKET_VERSION}/gitbucket.war /gitbucket.war

depends_on/condition版

  • versionを3にします。
  • dbにhealthcheck/testを追加してチェック用コマンドを追加します。
  • gitbucketのdepends_on/dbをリストから要素に変更してその子要素にcondition: service_healthyを追加します。

これでdbのhealtcheck/testで指定したコマンドが成功するとgitbucketが起動するようになります。

docker-compose.yml
version: '3'
services:
  gitbucket:
    build: gitbucket
    image: gitbucket:4.7.1
    ports:
      - "8080:8080"
    volumes:
      - ./var/gitbucket:/var/gitbucket
    depends_on:
      db:
        condition: service_healthy
    command: sh /wait.sh db gitbucket gitbucket java -jar /gitbucket.war

  db:
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      - MYSQL_RANDOM_ROOT_PASSWORD=1
      - MYSQL_DATABASE=gitbucket
      - MYSQL_USER=gitbucket
      - MYSQL_PASSWORD=gitbucket
      - TZ=Asia/Tokyo
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    healthcheck:
        test: mysqladmin ping -h 127.0.0.1 -u$$MYSQL_USER -p$$MYSQL_PASSWORD

MySQLはmysqladminコマンドでポートチェックできますが、httpやtcpなどは以下のような方法や他のコマンドも利用できます。

  • httpチェックを curl -f http://localhost:8080
  • tcpのチェックをbashで bash -c "echo > /dev/tcp/127.0.0.1/80"
  • tcpのチェックをnetstatで netstat -tnl | awk '$$1 ~ /^tcp/ && $$4 ~ /:80$$/{rc=1}END{exit !rc}'

チェックスクリプト版

今回のメインとなるwait.shは引数からDBのホスト名、ユーザ名、パスワードを受け取って生存チェック後にWebアプリを実行します。

gitbucket/wait.sh
#!/bin/sh

set -e

host="$1"
shift
user="$1"
shift
password="$1"
shift
cmd="$@"

echo "Waiting for mysql"
until mysql -h"$host" -u"$user" -p"$password" &> /dev/null
do
        >&2 echo -n "."
        sleep 1
done

>&2 echo "MySQL is up - executing command"
exec $cmd

最後にdocker-compose.ymlです。
wait.shにDBの情報を渡す必要があるため、commandでGitBucketを起動します。

docker-compose.yml
version: '2'
services:
  gitbucket:
    build: gitbucket
    image: gitbucket:4.7.1
    ports:
      - "8080:8080"
    volumes:
      - ./var/gitbucket:/var/gitbucket
    depends_on:
      - db
    command: sh /wait.sh db gitbucket gitbucket java -jar /gitbucket.war

  db:
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      - MYSQL_RANDOM_ROOT_PASSWORD=1
      - MYSQL_DATABASE=gitbucket
      - MYSQL_USER=gitbucket
      - MYSQL_PASSWORD=gitbucket
      - TZ=Asia/Tokyo
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci

以上、このようなスクリプトを挟む事でDBの起動完了を待ってからWebアプリを起動できるようになります。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
85
Help us understand the problem. What are the problem?