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

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

More than 1 year has passed since last update.

背景

日頃はオンラインで, 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はまだまだ落ち着かないので, しっかり追わないと駄目ですね. これでネットワーク難民時にも色々遊べる. ちゃんちゃん.

参考文献

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