リモート開発メインのソフトウェア開発企業のエンジニアブログです

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サーバにアクセスできるようにする

Moba Pro

方法①

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.ymlextra_hostshost-gatewayを設定してみます。

docker-compose.yml
services:
  対象サービス:
    extra_hosts:
    - "host.docker.internal:host-gateway"

コンテナを再構築します。
しかし、これではWSL内のコンテナからWSL内で起動したAPIサーバには接続できませんでした。
Connection Refusedエラーになります。

内容を調査します

docker-compose.ymlextra_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のネットワークに問題があるのではないかと結構な時間を費やしてしまいました。実際には、単に接続したいサーバが起動していない(方法①)。接続元で接続先のサーバアドレスを正しく設定していないことでした(方法②)。問題に直面したとき、その解決策はいつもシンプルであることが多いと感じます。そのシンプルな解決策に効率よくたどり着くためには多くの経験と学びが必要だと改めて実感いたしました。

← 前の投稿

Flutter の物理シミュレーションを理解する: ① Simulation の基本と FrictionSimulation

次の投稿 →

生成 AI にシステム構成図を描かせる

コメントを残す