🌐

Docker 上で curl レスポンスが遅かったのは名前解決が原因だった

2023/09/09に公開

事象

Laravel で作成した WEB システム(メインサイト)と WordPress で作成した WEB システム(サブサイト)を同一サーバ上に配置し、サブディレクトリ形式で動作させるというプロジェクトがあり、Docker を用いてローカル環境構築を行っていました。

試行錯誤の結果、なんとか動作させることはできたのですが、WordPress の記事ページの表示が異常に遅い…
管理画面の表示は問題ないのですが、記事ページの表示がもの非常に遅く、情報量の少ない単純なページの表示ですら平均1分弱掛かる始末でした。。

試行錯誤の経緯

解決に至るまでに試行錯誤した経緯を備忘として記載していますが、読み飛ばして 結論 だけ見ていただいても大丈夫です。

Docker Compose volumes の見直し

「Docker WordPress 遅い」などで検索すると、ボリュームのマウント周りに関する記事が多数ヒットしたため、まずはそこを見直しました。

WordPress プロジェクト全量をバインドマウント対象としていたところを、プロジェクト全量は名前付きボリュームにして同期対象外とし、頻繁に更新する一部ファイルのみバインドマウント対象に変更してみました。
この変更によってほんの数秒は表示速度が改善されたのですが、それでもまだ平均50秒は掛かる状態でした。。

Laravel 側の見直し

デバッグログを仕込み、そもそもどこで時間が掛かっているのか調査したところ、Laravel への API 送信時に毎回16秒程掛かっていることが判明しました。
1ページを表示するために3回 API 送信を行なっていたので、16秒 * 3回 = 48秒 ≒ 50秒 となってしまっているようでした。

Laravel への API 送信部分が問題ということは分かったので、これを改善するために Laravel 側の処理の見直しを図りました。
無駄な DB アクセスはないか、ミドルウェアの設定は適切か、等々確認したのですが、どうもそんなに重い処理はは見当たらず。。

vendor 配下のソースを追ってみたりもしたのですが、結局改善には至りませんでした。

curl のせい…?

事象 で記載した通り、API は curl で送信していました。
では curl 通信をデバッグしてみようということで、--trace-time オプションを付与して確認してみたところ、一番最初の Trying {ip:port}... が返ってくる時点で既に16秒が掛かっていることが分かりました。

今回のプロジェクトでは、Laravel 宛の API を「ホスト名(例: local.test)」で指定して送信していたのですが、試しにこれを「IPアドレス(例: 127.0.0.1)」で指定して送信してみたところ、即座にレスポンスが返ってきました…!

以上のことから、「ホスト名 → IPアドレス」の名前解決部分が原因であると特定しました。

結論

WordPress から Laravel API を curl で叩く際の 「ホスト名 → IPアドレス」の名前解決に時間がかかっている ことが原因だと分かったので、この部分について対策を講じました。

方法は色々あるのですが、今回は docker-compose.yml に extra_hosts を追記するのが一番シンプルだったのでこの方法を選びました。

docker-compose.yml
services:
    web:
        extra_hosts:
            - 'host.docker.internal:host-gateway'
+            - 'local.test:127.0.0.1' # ホスト名:IPアドレス

extra_hostsホスト名:IPアドレス を指定することで、コンテナ内の /etc/hosts にIPアドレスとホスト名のエントリが追加されます。

127.0.0.1	local.test

これによってコンテナ内での「ホスト名 → IPアドレス」の名前解決が一瞬で返ってくるようになり、API の実行も1秒未満で完了し、WordPress の記事ページ表示が重い問題は無事解消されました!


今回のプロジェクトは少し特殊な構成をしていたこともあり、疑わしい部分が多く、原因の特定にだいぶ手こずってしまいました。。
あまり遭遇することはない事象かとは思いますが、少しでも誰かに参考になれば幸いです。

Discussion