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-host
で host-gateway
を使える機能は Docker Engine 20.10.0 ( 2021/12/08 )で導入されていたようです:
- 20.10.0 | Docker Engine release notes | Docker Documentation
- Support host.docker.internal in dockerd on Linux by arkodg · Pull Request #40007 · moby/moby · GitHub
- Support host.docker.internal DNS name to host · Issue #264 · docker/for-linux · GitHub
というように、記事執筆時点で Linux 上では --add-host
と host-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"
参考: