DockerでDBの設定が完了するまでアプリケーションのコンテナを立ち上げないようにしようとしたらハマった
はじめに
個人的にDjangoの環境をDockerで一発で整えられるようにしたいので、いろいろ試行錯誤しています。
→GitHubリポジトリ
DockerでDBから何からまとめて管理しようとするときにはいくつかハマる箇所があると思いますが、そのひとつにDockerコンテナを立ち上げたときに、データベースの初期設定が完了してないのにアプリケーションコンテナがデータベースに接続しにいって失敗し、一生再起動し続けるというものがあります。
一見、アプリケーションコンテナ側の設定でdepends_onにデータベースを入れとけば良さそうですが、depends_onは起動順序のみを保証し、コンテナ内部の処理は全く感知してくれないので、自力で起動制御する必要があります。
参考:http://docs.docker.jp/compose/startup-order.html
その対策を行う上でいくつかハマったところがあったのでご紹介します。
環境
- Django
- MariaDB
- nginx(今回は関係ない)
- gunicorn(今回は関係ない)
ハマったこと
- Debianのリポジトリからmysql-clientが消え去っていた
- bashでmysqlコマンドを打つときにダブルクォーテーションをうまく使えなかった
- docker-composeのentrypointで、wait-for-it.shを実行するとき、引数でコマンドを渡そうと思ったらうまく渡らなかった
基本的な戦略
- Djangoコンテナの起動時にshellscriptでMariaDBに対して疎通確認を行う
- まだ繋がらないなら待つ
- 繋がったらDjangoのコマンド実行!
1. Debianのリポジトリからmysql-clientが消え去っていた
文字通りです。最初はDjango用のコンテナにmysql-clientをインストールしてmysqlコマンドで疎通確認をしようとしていました。
RUN apt-get update && apt-get install -y mysql-client
するとこんなエラーが、、、
E: Package 'mysql-client' has no installation candidate
調べてみるとDebianのリポジトリからmysql-clientが消えていました😭
Debianリポジトリ:https://packages.debian.org/stable/database/
代わりにdefault-mysql-clientとmariadb-clientができていたので、mariadb-clientをインストールすることにしました。
RUN apt-get update && apt-get install -y mariadb-client
2. bashでmysqlコマンドを打つときにダブルクォーテーションをうまく使えなかった
Dockerの公式サイトをみると、DBの準備が整うまで待つにはこうするといいよ!と書かれていました。
#!/bin/bash
set -e
host="$1"
shift
cmd="$@"
until psql -h "$host" -U "postgres" -c '\l'; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
exec $cmd
なのでPostgreSQLをMariaDB用に変えて以下のようにしていました。
#!/bin/bash
set -e
. ./mariadb.env #MariaDB用の環境ファイル
host="$1"
shift
cmd="$@"
until mysql -h "$host" -u "$MYSQL_USER" -p "$MYSQL_PASSWORD" -e "show databases;" "$MYSQL_DATABASE" ; do
>&2 echo "MariaDB is unavailable -sleeping"
sleep 1
done
>&2 echo "MariaDB is up -executing command"
exec $cmd
まあこれが普通に間違いなんですが、、、
問題はuntilの行で、実際には以下のように実行されます(変数には適当に入れてます)。
mysql -h sample -u sampleuser -p samplepassword -e "show databases;" sampledatabase
mysqlのコマンドでは、-optionなら引数をクォーテーションで囲う、--optionなら=でつなぐように書くので、これだと正しく実行されません。
参考:https://mariadb.com/kb/en/mysql-command-line-client/
正しくは以下のように実行されなければいけません。
mysql -h "sample" -u "sampleuser" -p "samplepassword" -e "show databases;" sampledatabase
これで小一時間くらいハマり、原因がやっとわかったので、ダブルクォーテーションをエスケープすればいいと考えて、以下のように変えてみました。
~略~
until mysql -h "\"$host\"" -u "\"$MYSQL_USER\"" -p "\"$MYSQL_PASSWORD\"" -e "show databases;" "$MYSQL_DATABASE" ; do
~略~
しかしこれでもうまくいかなかったので(だれか教えてください泣)、結局以下のようにしました。
~略~
until mysql --host="$host" --user="$MYSQL_USER" --password="$MYSQL_PASSWORD" -e "show databases;" "$MYSQL_DATABASE" ; do
~略~
3. docker-composeのentrypointで、wait-for-xxx.shを実行するとき、引数でコマンドを渡そうと思ったらうまく渡らなかった
最初、docker-composeの設定を以下のようにしていました。
version: '3'
services:
django:
~略~
entrypoint: ./wait-for-mariadb.sh mariadb "python manage.py migrate && gunicorn my_docker_django_project.wsgi -b 0.0.0.0:3031"
これで2番目の引数にコマンドが渡って、それをそのまま実行すればいいと思ってました。
shift
cmd="$@"
exec $cmd
するとこんなエラーが😭
django_1 | python manage.py migrate && gunicorn my_docker_django_project.wsgi -b 0.0.0.0:3031
django_1 | usage: manage.py migrate [-h] [--noinput] [--database DATABASE] [--fake]
django_1 | [--fake-initial] [--plan] [--run-syncdb] [--version]
django_1 | [-v {0,1,2,3}] [--settings SETTINGS]
django_1 | [--pythonpath PYTHONPATH] [--traceback] [--no-color]
django_1 | [--force-color] [--skip-checks]
django_1 | [app_label] [migration_name]
django_1 | manage.py migrate: error: unrecognized arguments: my_docker_django_project.wsgi -b 0.0.0.0:3031
どうやら&&以降のgunicornコマンドがpython manage.py migrateの引数だと思われてるようです。。。
migrateしないとアプリケーションサーバは起動してほしくないので、結局以下のようにshellscriptにベタ書きすることにしました。
#!/bin/bash
set -e
. ./mariadb.env
host="$1"
shift
cmd="$@"
until mysql --host="$host" --user="$MYSQL_USER" --password="$MYSQL_PASSWORD" -e "show databases;" "$MYSQL_DATABASE" ; do
>&2 echo "MariaDB is unavailable -sleeping"
sleep 1
done
>&2 echo "MariaDB is up -executing command"
python manage.py migrate && gunicorn my_docker_django_project.wsgi -b 0.0.0.0:3031
exec $cmd
最後に
よかったら定期的にGitHub更新していくので見ていってください:)
https://github.com/keii1111/my_docker_django
参考情報
Author And Source
この問題について(DockerでDBの設定が完了するまでアプリケーションのコンテナを立ち上げないようにしようとしたらハマった), 我々は、より多くの情報をここで見つけました https://qiita.com/keii1111/items/ed9acacaf6ef0a339821著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .