WSL内で起動したコンテナから、同じくWSL内で起動したAPIサーバにアクセスする方法
概要
業務でローカルテスト環境を構築している際に、コンテナからAPIサーバにアクセスできずに困った経験がありました。この問題を解決するために試行錯誤しましたが、最終的に効果的な解決策が分かりましたので記事にしたいと思います。
環境
Golang 1.21.6 (コンテナアプリ)
Node.js 20.15.0 (APIサーバ)
Docker Desktop for windows 26.1.4
WSL 2.2.4.0
Windows11 23H2
問題
WSL内で起動したコンテナから、同じくWSL内で起動したAPIサーバにConnection Refusedエラーでアクセスできない
対応方法
①WindowsでAPIサーバを起動し、WSL内のコンテナからアクセスする
②WSL内のコンテナからWSL内で起動したAPIサーバにアクセスできるようにする
方法①
WSL内のコンテナからWindowsで起動したAPIサーバにアクセスする
こちらはすんなりとうまく行きました。
まず、Docker Desktopではhost.docker.internal
を指定すると、デフォルトでホスト側のIPアドレスに名前解決してくれます。
そしてコンテナで起動するアプリのコードにはhost.docker.internal:ポート番号
の指定がありました。
そのためWindows側でAPIサーバを起動することで、WSL内で起動したコンテナからアクセスできました。
方法②
WSL内のコンテナからWSL内で起動したAPIサーバにアクセスできるようにする
こちらが実現したかったことです。
前述の通り、host.docker.interna:ポート番号
を指定するとデフォルトでWindows側にアクセスしてしまいます。
WSLにはUbuntuを入れてますのでホストがLinuxだった場合の記事を参考にdocker-compose.yml
のextra_hosts
にhost-gateway
を設定してみます。
docker-compose.yml
services:
対象サービス:
extra_hosts:
- "host.docker.internal:host-gateway"
コンテナを再構築します。
しかし、これではWSL内のコンテナからWSL内で起動したAPIサーバには接続できませんでした。
Connection Refusedエラーになります。
内容を調査します
docker-compose.yml
のextra_hosts
を設定するとコンテナの/etc/hosts
にエントリーされるようです。
その内容を確認したところWindows側のIPアドレスが設定されてました。
/etc/hosts
192.168.65.254 host.docker.internal
host-gatewayなのでホストと認識されているWindows側のIPアドレスが割り振られるのは当たり前ですね。
Linuxをホストとする設定というのはWSLには当てはまらいようです。
次にWSLのIPアドレスを設定してみます。
docker-compose.yml
services:
対象サービス:
extra_hosts:
- "host.docker.internal:wslのIPアドレス"
IPアドレスは以下のコマンドで取得できます。
#WSLで実行
ip a show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:15:5d:d8:51:4b brd ff:ff:ff:ff:ff:ff
inet 172.28.227.204/20 brd 172.28.239.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::215:5dff:fed8:514b/64 scope link
valid_lft forever preferred_lft forever
コンテナを再構築しコンテナ内の/etc/hosts
を確認したところエントリーを確認できました。
/etc/hosts
host.docker.interna:172.28.227.204
これでWSL内のコンテナからWSL内で起動したAPIサーバに接続できました。
余談
WSL内で起動したコンテナにWindowsからアクセスするには、Windows側でlocalhost:ポート番号
を指定することで実現できます。これはWSLの機能でlocalhost
をWSLのIPアドレスに変換してくれるためです。
なお、前述の通り、WSL内のコンテナからhost.docker.internal:ポート番号
でWindows側にアクセスするためにはDocker Desktopの機能を使います。それぞれ始点になるツールの機能を使うと良いですね。
まとめ
解決できてしまえば簡単な問題でしたが、WSLやWindows、Dockerのネットワークに問題があるのではないかと結構な時間を費やしてしまいました。実際には、単に接続したいサーバが起動していない(方法①)。接続元で接続先のサーバアドレスを正しく設定していないことでした(方法②)。問題に直面したとき、その解決策はいつもシンプルであることが多いと感じます。そのシンプルな解決策に効率よくたどり着くためには多くの経験と学びが必要だと改めて実感いたしました。
コメントを残す