Help us understand the problem. What is going on with this article?

Dockerコンテナ内からホストへ`localhost` でアクセスしてみる

のっぴきならぬ事情で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://qiita.com/kai_kou/items/6cf5930330b85fa583b0

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/

kai_kou
2004年からWeb系のシステムエンジニアとして開発、運用、マネジメントを経験。現在はアイレット(クラウドパック)に所属。 べ、別にいいね貰えたからってモチベーションが上がって記事とコードの品質があがるわけじゃないんだからね///
https://twitter.com/k_aik_ou
cloudpack
Amazon Web Services (AWS) の導入設計、環境構築、運用・保守をサポートするマネジドホスティングサービス
https://cloudpack.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away