のっぴきならぬ事情でDockerコンテナ内からホストへlocalhost
でアクセスする必要なときに役立ちそうなのでメモ。
Dockerコンテナ内からホストへアクセスするには
こちらの記事が参考になりました。--add-host
オプションを利用すればなんとかなりそうです。
Dockerのコンテナの中からホストOS上のプロセスと通信する方法 – Qiita
https://qiita.com/Iju/items/badde64d530e6bade382
localhost
じゃなくて良いのなら
host.docker.internal
というDNS名が用意されているので、それを利用すればよさそうです。
ドキュメントによるとMac/Windowsで利用できそうです。
Networking features in Docker Desktop for Windows | Docker Documentation
https://docs.docker.com/docker-for-windows/networking/
The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Windows.
(Google翻訳)ホストのIPアドレスは変更されています(ネットワークアクセスがない場合はなし)。18.03以降では、ホストが使用する内部IPアドレスに解決される特別なDNS名host.docker.internalに接続することをお勧めします。 開発目的のためであり、Docker Desktop for Windows以外の実稼働環境では機能しません。
Networking features in Docker Desktop for Mac | Docker Documentation
https://docs.docker.com/docker-for-mac/networking/
The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Mac.
(Google翻訳)ホストのIPアドレスは変更されています(ネットワークアクセスがない場合はなし)。 18.03以降では、ホストが使用する内部IPアドレスに解決される特別なDNS名host.docker.internalに接続することをお勧めします。 これは開発用であり、Docker Desktop for Mac以外の運用環境では動作しません。
試してみる
準備
まずホストでHTTPサービスを80ポートで立ち上げます。
> python -m http.server 80 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ... # Dockerコンテナを起動するのでもOK > docker run -it --rm -p 80:80 python \ python -m http.server 80
確認
立ち上げたサービスに対してDockerコンテナ内からcurl
でアクセスしてみます。
利用するDockerイメージはなんでもよいです。curl
がインストールされていなかったら先にインストールします。
> docker run -it --rm alpine \ sh -c 'apk add curl;curl http://localhost:80' (略) OK: 7 MiB in 18 packages curl: (7) Failed to connect to localhost port 80: Connection refused
はい。
コンテナ内でlocalhost
に対してアクセスすると当然ながらコンテナ内へのアクセスとなり、エラーとなります。
--add-host
を足してみる
--add-host
を利用するとコンテナ内の/etc/hosts
ファイルに設定を追加できるそうです。
Dockerで/etc/hostsファイルが操作出来ない対策 – Qiita
https://qiita.com/jagaximo/items/6b71a03518bbd53d4de6
> docker run -it --rm 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 172.17.0.3 9f215da7195e
なので、localhost
に対してホストのIPアドレスをみにいくように設定を追加してみます。
# ホストのプライベートIPアドレスを確認 > ipconfig getifaddr en0 > docker run -it --rm \ --add-host=localhost:<ホストのプライベートIPアドレス> \ 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 <ホストのプライベートIPアドレス> localhost 172.17.0.3 6aff7879fc0a
追加できることが確認できたらcurl
でアクセスしてみます。
> docker run -it --rm \ --add-host=localhost:<ホストのプライベートIPアドレス> \ alpine \ sh -c 'apk add curl;curl -D - -s -o /dev/null http://localhost:80' (略) OK: 7 MiB in 18 packages HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/3.8.1 Date: Wed, 12 Feb 2020 02:43:26 GMT Content-type: text/html; charset=utf-8 Content-Length: 987
やったぜ。
使う機会があるかはわかりませんが、できることは確認できました。
参考
Dockerのコンテナの中からホストOS上のプロセスと通信する方法 – Qiita
https://qiita.com/Iju/items/badde64d530e6bade382
Networking features in Docker Desktop for Windows | Docker Documentation
https://docs.docker.com/docker-for-windows/networking/
Networking features in Docker Desktop for Mac | Docker Documentation
https://docs.docker.com/docker-for-mac/networking/
Dockerで/etc/hostsファイルが操作出来ない対策 – Qiita
https://qiita.com/jagaximo/items/6b71a03518bbd53d4de6
Pythonの標準ライブラリでさくっとAPIサーバとWebサーバを立ち上げる – Qiita
https://cloudpack.media/44251
cURLコマンドでレスポンスヘッダのみを取得する – Qiita
https://qiita.com/yousan/items/fcc15e1046939c465ab7
macOS で自分のプライベート IP アドレスを見つける方法 – yu8mada
https://yu8mada.com/2018/07/14/how-to-find-my-private-ip-address-in-macos/