Docker DBコンテナからの「SQLSTATE[HY000] [2002] Connection refused 」
今日の1.5時間を費やした、クソデカため息案件です。
前提要件
- Docker Engine + Docker Compose を使用
- いち Compose に対し、WebコンテナとDBコンテナを用意
- Webコンテナには Laravel をインストール、DBコンテナには MariaDB をインストール
このエラーが出た時に見るべきところ
-
DB_USER
が作成されているか -
DB_HOST
がコンテナ名になっているかどうか -
DB_PORT
がゲスト側のポートで設定されているか - Laravel の config キャッシュが残っていないか
DB_USER
が作成されているか
1. これはデータベース・クライアント(Sequel Pro など)か何かで確認してください。もしくは、Webが繋がるならば、Adminer等でもOK。
Laravel の .env に設定されたユーザー情報でそもそも入れるかどうかの確認ですね。
MariaDB を利用する場合 MARIADB_DATABASE
や MARIADB_USER
など、コンテナを作成するにあたって必要なオプションがありますので、最低限の設定を満たさない場合には、当然作成されず、エラーになります。
DB_HOST
がコンテナ名になっているかどうか
2. これは良く他文献でも言われているものですね。
よくある誤りは、DB_HOST
に対して localhost
や 127.0.0.1
とかを設定しているのが挙げられますが、ローカルホストでDBコンテナを認識できるのはホスト側(Mac OS / Windows など、Docker Engine が動いているマシンOS)であって、ゲスト側(コンテナの中)の場合にローカルホストを指定すると、自コンテナを認識してしまうことになります。
当然、自コンテナにDBコンテナへのルーティングは定義されてないので繋がらない(Connection refused)になります。
docker-compose.yml
...
database:
container_name: abcd1234 # ここの名前を使う
hostname: abcd.database.local
image: mariadb
...
.env
...
DB_CONNECTION=mysql
DB_HOST=abcd1234 # container_name を入れる
DB_PORT=3306
DB_DATABASE=db
DB_USERNAME=user
DB_PASSWORD=secret
...
慣れていないと陥りがちなスタックポイントなので要注意。
DB_PORT
がゲスト側のポートで設定されているか
3. これもよくあるものだと思います。
例えば、いちComposeネットワークに対して、複数のDBコンテナが立ち上がっているとき、ホストからそれぞれのゲストを認識してアクセスをするためのポート番号は分けて定義するはずです。(Aコンテナは 3306
、Bコンテナは 13306
、など)
この時の定義はあくまでも「ホストからゲストを認識するためのポート」なので、コンテナ間(ゲスト間)を認識するものではありません。
先ほどの例で指定した 13306 -> 3306
のマッピングをしているのであれば、WebコンテナからDBコンテナにアクセスする場合には、内部的に使われている 3306
番を指定しないと、認識がされずエラーになりますので、ここも要注意。
docker-compose.yml
...
ports:
- target: 3306 # ゲスト は 3306 にマッピングする
published: 13306 # ホスト to ゲスト は 13306 から入る
protocol: tcp
mode: host
...
.env
...
DB_CONNECTION=mysql
DB_HOST=abcd1234
DB_PORT=3306 # ゲスト側ではホストのINポートを認識はしないので 3306 で通す
DB_DATABASE=db
DB_USERNAME=user
DB_PASSWORD=secret
...
4. Laravel の config キャッシュが残っていないか
これは逐一やっておいてください。プロビジョニング工程では、致し方なしです。
環境変数をガリガリと変えていく作業や、初めて開発環境を構築する時に発生するものと思いますので、Laravelやキャッシュコントロールが行き渡っている環境での作業では、何は無くとも、都度疑ってみてください。
僕も、以下のコマンドで治った!みたいなこともあったので、お試しあれ。
$ php artisan cache:clear
$ php artisan config:clear
$ php artisan route:clear
$ php artisan view:clear
Discussion