Edited at

オフラインMacでDocker containerからHostOSへ接続する


背景

日頃はオンラインで, Docker containerからHostOSへの接続はHostOSのhostnameで解決していた. 久しぶりにオフラインでDocker containerからHostOSへ接続しようとしたら127.0.0.1が返ってきた. Docker containerのloopbackと競合するので困った.


環境


  • OS: macOS Mojave Version 10.14.3

  • Docker Desktop:

DockerDesktop.png


シンプルな解決策

host.docker.internal を使用するとDocker containerからHostOSへ接続できる.

Networking features in Docker Desktop for Mac


I WANT TO CONNECT FROM A CONTAINER TO A SERVICE ON THE HOST

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.



シンプルでない解決策

loopback interface lo0にaliasを設定し, aliasへ接続する.

$ sudo ifconfig lo0 alias xxx.xxx.xxx.xxx

$ sudo ifconfig lo0 -alias xxx.xxx.xxx.xxx


オフライン時にHostOSのhostnameを解決したら127.0.0.1が返ってくるのは何故?


オンライン時とオフライン時を比較してみる


HostOSへ接続している.terminal.container.online

$ ping HOSTNAME.local

PING HOSTNAME.local (xxx.xxx.xxx.xxx): 56 data bytes
64 bytes from xxx.xxx.xxx.xxx: seq=0 ttl=37 time=0.758 ms
64 bytes from xxx.xxx.xxx.xxx: seq=1 ttl=37 time=1.172 ms



自Containerへ接続している.terminal.container.offline

$ ping HOSTNAME.local

PING HOSTNAME.local (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.058 ms
64 bytes from 127.0.0.1: seq=1 ttl=64 time=0.155 ms



terminal.hostos.online

$ ifconfig

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether xx:xx:xx:xx:xx:xx
inet6 xxxx::xxxx:xxxx:xxxx:xxxx%en0 prefixlen 64 secured scopeid 0x8
inet xxx.xxx.xxx.xxx netmask 0xfffffff0 broadcast xxx.xxx.xxx.xxx
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active


terminal.hostos.offline

$ ifconfig

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
en0: flags=8823<UP,BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500
ether xx:xx:xx:xx:xx:xx

nd6 options=201<PERFORMNUD,DAD>
media: autoselect (<unknown type>)
status: inactive



terminal.hostos.online

$ netstat -rn

Routing tables

Internet:
Destination Gateway Flags Refs Use Netif Expire
default xxx.xxx.xxx.xxx UGSc 123 0 en0
127 127.0.0.1 UCS 0 0 lo0
127.0.0.1 127.0.0.1 UH 11 59676 lo0

他色々



terminal.hostos.offline

$ netstat -rn

Routing tables

Internet:
Destination Gateway Flags Refs Use Netif Expire
127 127.0.0.1 UCS 0 0 lo0
127.0.0.1 127.0.0.1 UH 11 59680 lo0

他色々



  • オンライン


    • IPAddress(xxx.xxx.xxx.xxx)へ接続している

    • en0が生きている

    • Routing tablesにen0がある



  • オフライン


    • 127.0.0.1へ接続している

    • en0が死んでいる

    • Routing tablesにlo0しかない




Multicast DNSを使っていた

そもそもDNSでhostnameを解決しておらず, hostnameコマンドで取得できる名前がHOSTNAME.localだった. .localはMulticast DNSで解決されるのでDNSとはちょっと異なる. ざっくり言うと"ホスト名さえ分かれば通信できるよぁ"ってプロトコル. MacだとBonjourで動いている.


Metricsが分からない

複数ルーティングルールがある場合, どのルーティングルールを適用するか?といった優先度を決めるMetricという値がある. loopback interface lo0とen0のMetricをMacOSで確認しようとしたが見つからない. 敢えていうなら, System Preferences > NetworkのSet Service Order...が該当するがloopback項目がない.


推測してみる

MacOSのルーティングルールのMetricはSystem Preferences > NetworkのSet Service Order..で設定されていて, 暗黙のルールでloopbackは最下位設定になっている. オフライン時はloopback interface lo0のみ有効となる. 併せて, Multicast DNSで解決した場合loopback interface lo0の127.0.0.1となる. 全部, 妄想.


ついでに

docker networkはdefault bridgeユーザー定義ネットワークでDNS設定が異なるらしい. docker containerからHostOSへの接続を詳しく知りたい方はどうぞ.


所感


terminal.container.offline

/srv # ping host.docker.internal 

PING host.docker.internal (???.???.???.???): 56 data bytes
64 bytes from ???.???.???.???: seq=0 ttl=37 time=0.373 ms
64 bytes from ???.???.???.???: seq=1 ttl=37 time=0.893 ms

host.docker.internalだとレスポンスが早いので通信が閉じた感じなのかな? Dockerはまだまだ落ち着かないので, しっかり追わないと駄目ですね. これでネットワーク難民時にも色々遊べる. ちゃんちゃん.


参考文献