Docker コンテナ内からホストのポートにアクセスする方法まとめ

Docker

Docker コンテナの中からホストのポートで動いているサービスにアクセスする方法についてのまとめです。

ホスト側からコンテナのポートにアクセスしたいときはシンプルにポートフォワーディングをして localhost:ポート にアクセスすればよいですが、逆の、コンテナの中からホストのポートにアクセスしたいときには別の方法をとる必要があります。 ここではその方法をまとめています。

確認時の環境

macOS

$ sw_vers
ProductName:  macOS
ProductVersion: 12.6
BuildVersion: 21G115

Docker

  • Docker 20.10.17
  • Docker Compose v2.10.2
  • Docker Desktop 4.12.0

Docker コンテナ内からホストのポートにアクセスする方法

Mac / Windows の場合

Docker for Mac / Windows の場合は、特殊な名前 host.docker.internal がホストを指すものとしてデフォルトで提供されているのでこれを使えば OK です。 特に準備などは必要ありません。

私の手元の Mac 環境では、次のようにしてこの挙動を確認できました。

(1/2) ホストのポート 8000 でウェブサーバーを起動:

# Python 3 が入っている場合
python3 -m http.server 8000
# Node.js が入っている場合
npm -g install http-server
http-server --port=8000
# どちらも入っていない場合
docker run --rm -p 8000:8000 python:latest python -m http.server 8000

(2/2) コンテナを起動して host.docker.internal:8000 にアクセス:

docker run --rm -it alpine
# 以下コンテナ内で実行
apk update && apk add curl
curl http://host.docker.internal:8000

ウェブサーバーからのレスポンスが返ってきます。

Linux の場合

(こちらは前提として Docker for Linux を使っていない場合を想定しています)

Docker for Mac / Windows とは違ってデフォルトでは host.docker.internal は使えないので、オプションを使う必要があります。 といっても方法はかんたんで、コンテナ起動時にオプション --add-host で特殊な文字列 host-gateway を使ってホストをポイントする DNS レコードを追加するだけです。

たとえば次のように --add-host=host.docker.internal:host-gateway とすると host.docker.internal/etc/hosts に追加されます。

docker run -it --add-host=host.docker.internal:host-gateway alpine cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
192.168.65.2  host.docker.internal
172.17.0.2  a2a1fa4fa7be

ポイントは下から 2 行目の次の行です。

192.168.65.2  host.docker.internal

私の環境では 192.168.65.2 は動的に割り当てられた値でしたが、 dockerd のオプション --host-gateway-ip を使えば値の指定もできるようです(動作確認していません)。

このようにして起動したコンテナでは(見かけ上 Docker for Mac / Windows と同様に) host.docker.internal:ポート でホストのポートにアクセスすることができます。

なお、 --add-host=host.docker.internal:host-gateway: の右側の host-gateway は特殊な意味を持つのでこの文字列にする必要がありますが左側の host.docker.internal はあくまでもサンプルであり自由に変更が可能です。 たとえば次のようにすると myhost:ポート でホストのポートにアクセスできます。

docker run -it --add-host=myhost:host-gateway [イメージ]

こちらも私の環境では次のようにして確認できました。

(1/2) ホストのポート 8000 でウェブサーバーを起動:

docker run --rm -p 8000:8000 python:latest python -m http.server 8000

(2/2) コンテナを起動して host.docker.internal:8000 にアクセス:

docker run --rm -it --add-host=host.docker.internal:host-gateway alpine
# 以下コンテナ内で実行
apk update && apk add curl
curl http://host.docker.internal:8000

ちなみに、この --add-hosthost-gateway を使える機能は Docker Engine 20.10.0 ( 2021/12/08 )で導入されていたようです:

というように、記事執筆時点で Linux 上では --add-hosthost-gateway を使う必要がありますが、これは頻出のパターンなので「 Docker Client の設定の切り替えで host.docker.internal をデフォルトで使えるようにしよう」という議論も進められているようです:

Docker Compose の場合

Docker Compose の場合は --add-host に相当する extra_hosts というオプションが使えるのでこれを使えば OK です。

次のようにすると host.docker.internal:ポート でホストの各ポートにアクセスできるようになります。

extra_hosts:
  - "host.docker.internal:host-gateway"

参考:

その他参考


アバター
後藤隼人 ( ごとうはやと )

Python や PHP を使ってソフトウェア開発やウェブ制作をしています。詳しくはこちら