はじめに
最近,研究の一環でWebアプリを作ることになりました.ところが経験不足が故にかなり詰まった箇所があったので,この記事が同じようにこれから頑張ろうという方の参考になれば幸いです.
TL; DR
- Djangoのエラー
django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on 'mysql:3306' (111)")
- MySQLは正常に起動
- 対処方法
-
healthcheck
の導入
-
環境
今回,Webアプリのために使用したフレームワークはDjango
+ Vue.js
で,DBにMySQL
を使用しています.また,この実行のために,Docker Composeを使用しています.
version: '3'
services:
vuejs:
~~~
depends_on:
- mysql
networks:
- app_net
django:
container_name: django
build:
context: ./django
dockerfile: Dockerfile.django
ports:
- 127.0.0.1:18000:8000
tty: true
volumes:
- ./django/src:/app
command: python manage.py runserver 0.0.0.0:8000
depends_on:
- mysql
networks:
- app_net
mysql:
image: mysql:8.3
~~~
networks:
- app_net
networks:
app_net:
name: app_net
driver: bridge
症状
今回遭遇した症状を箇条書きで示します.
-
docker compose up
を実行しても,Djangoが無事に動作する時としない時がある- エラーメッセージは
django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on 'mysql:3306' (111)")
- エラーメッセージは
- 上記のエラーメッセージで検索すると以下の2点に異常があるらしい
- DjangoのDB設定
- MySQLの起動
DjangoのDB設定にも,MySQLの起動・設定にも異常がないことを確認したものの改善せず……
結論
色々と試したのですが,それらは他の記事様にお任せするとして,今回の症状への対処法は,Docker Composeのhealthcheck
を使用する,というものでした.
今回の症状は,直接的には,MySQLが立ち上がる前にDjangoが起動してしまったことが原因のようです.浅薄な理解でdepends_on
を使えば良いと考えていたために,かなり時間を取られてしまいました.
あくまでdepends_on
は「コンテナ」の起動順序を指定するのみで,コンテナ内の「プロセス」までは管理してくれないようです.
今回の環境のログファイルを確認すると以下の順序になっていました.
上記の図のように,Djangoが起動してMySQLとの接続を求めたときにはMySQLが立ち上がっておらず,これが原因でした.
そこで,コンテナ内のプロセスが起動したことを確認してから次のコンテナを起動するようにしたいのですが,これを提供する機能がhealthcheck
というものです.実際にhealthcheck
を追加したdocker-compose.yml
ファイルを以下に示しておきます.
version: '3'
services:
vuejs:
~~~
depends_on:
mysql:
condition: service_healthy
networks:
- app_net
django:
container_name: django
build:
context: ./django
dockerfile: Dockerfile.django
ports:
- 127.0.0.1:18000:8000
tty: true
volumes:
- ./django/src:/app
command: python manage.py runserver 0.0.0.0:8000
depends_on:
mysql:
condition: service_healthy
networks:
- app_net
mysql:
image: mysql:8.3
~~~
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 1s
timeout: 3s
retries: 30
networks:
- app_net
networks:
app_net:
name: app_net
driver: bridge
以上のように設定を行うことで,無事に起動が確認できました.
最後に
調べ方が悪かったのか,あるいは,Webアプリ開発者のコミュニティの中では当たり前のことなのか,先述のエラーメッセージに対して確認すべきと指定されている項目の中に,本記事のような記述は見当たらなかったため紹介しました.
初学者の助けになれば幸いです.
参考