はじめに
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をよく使うので書き換えてみました。
ファイル構成はこんな感じです。
docker-compose.yml
+ gitbucket/
+ Dockerfile
+ wait.sh
ベースイメージはalpine版なのでapkでmysql-clientをインストールしています。
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が起動するようになります。
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: 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アプリを実行します。
#!/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を起動します。
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アプリを起動できるようになります。