Docker で コンテナに DNS サーバーを指定したときの IPの衝突によって名前解決できなくなる現象の確認


結論

  • dockerの dns オプションを指定した際は、docker networkとの衝突に注意が必要
    • コンテナ内から名前解決できなくなる
  • 以下の2つは等価ではない
    • docker の dns オプションを指定しない(デフォルトを使用する)
    • ホスト側DNSサーバーIPアドレス(例えば 192.168.0.1) を dockerの dns オプションに指定する

条件

  • Windows 10 Home
    • ProではないのでHyper-Vが使えない
    • → Docker for Windows が使えない
  • VirtualBox
  • Docker Machine

docker --version

Docker version 18.03.0-ce, build 0520e24302

古い。。。
TODO: 後で更新

docker-machine --version

docker-machine.exe version 0.14.0, build 89b8332

docker-machine ip

192.168.99.100

ネットワーク

ホスト側のDNSサーバー

192.168.0.1

ipconfig.exe /all

抜粋

イーサネット アダプター VirtualBox Host-Only Network #5:
   接続固有の DNS サフィックス . . . . .:
   説明. . . . . . . . . . . . . . . . .: VirtualBox Host-Only Ethernet Adapter #5
   IPv4 アドレス . . . . . . . . . . . .: 192.168.56.1(優先)
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .:
   DNS サーバー. . . . . . . . . . . . .: fec0:0:0:ffff::1%1
                                          fec0:0:0:ffff::2%1
                                          fec0:0:0:ffff::3%1


イーサネット アダプター VirtualBox Host-Only Network #6:
   接続固有の DNS サフィックス . . . . .:
   説明. . . . . . . . . . . . . . . . .: VirtualBox Host-Only Ethernet Adapter #6
   IPv4 アドレス . . . . . . . . . . . .: 192.168.99.1(優先)
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .:
   DNS サーバー. . . . . . . . . . . . .: fec0:0:0:ffff::1%1
                                          fec0:0:0:ffff::2%1
                                          fec0:0:0:ffff::3%1


イーサネット アダプター ローカル エリア接続:
   接続固有の DNS サフィックス . . . . .:
   IPv4 アドレス . . . . . . . . . . . .: 192.168.0.13(優先)
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: 192.168.0.1
   DHCP サーバー . . . . . . . . . . . .: 192.168.0.1
   DNS サーバー. . . . . . . . . . . . .: 192.168.0.1

検証方法

  • コンテナ内にDNSサーバーを起動
    • ベース: tksugimoto/docker-dns-proxy-logger
    • dnsmasq を使用
    • DNSサーバーはホスト側のDNSサーバーへ転送するだけ
      • 192.168.0.1
    • docker-machine を使用しているため、 作成したDNSサーバーのIPは 192.168.99.100
  • ホスト側からコンテナ内にDNSサーバーにnslookup

検証結果

dns指定無しの場合

docker networkのいずれかとホスト側のDNSサーバーのIPと衝突しててもコンテナ内で 名前解決はできる

nslookup

$ winpty nslookup.exe example.com 192.168.99.100
サーバー:  UnKnown
Address:  192.168.99.100

権限のない回答:
名前:    example.com
Address:  93.184.216.34

192.168.99.100 は問い合わせに使うDNSサーバーのIP(コンテナ内DNSサーバー)

docker network

ホストのDNSサーバーのIP 192.168.0.1my-network-13 (192.168.0.0/20) と衝突している

$ docker network inspect $(docker network ls -q) | grep -E "Subnet|Name" | grep -C5 192.168.0.0
        "Name": "my-network-11",
                    "Subnet": "172.30.0.0/16",
        "Name": "my-network-12",
                    "Subnet": "172.31.0.0/16",
        "Name": "my-network-13",
                    "Subnet": "192.168.0.0/20",
        "Name": "my-network-14",
                    "Subnet": "192.168.16.0/20",
        "Name": "my-network-15",
                    "Subnet": "192.168.32.0/20",
        "Name": "my-network-16",

※ docker networkを大量に作る方法 → docker networkを限界まで作る - Qiita

docker-compose.yml

dns オプションは未指定(デフォルト値が使われる)

version: '3'

services:
  dns-server:
    build:
      context: ./
      args:
        - http_proxy
        - https_proxy
    ports:
      - "192.168.99.100:53:53"
      - "192.168.99.100:53:53/udp"
    restart: always

dns指定ありの場合(docker networkとIPが衝突した場合)

名前解決がタイムアウトする

DNSサーバーへ到達できていないと考えられる

nslookup

$ winpty nslookup.exe example.com 192.168.99.100
DNS request timed out.
    timeout was 2 seconds.
サーバー:  UnKnown
Address:  192.168.99.100

DNS request timed out.
    timeout was 2 seconds.
DNS request timed out.
    timeout was 2 seconds.

192.168.99.100 は問い合わせに使うDNSサーバーのIP(コンテナ内DNSサーバー)

docker network

ホストのDNSサーバーのIP 192.168.0.1my-network-13 (192.168.0.0/20) と衝突している

$ docker network inspect $(docker network ls -q) | grep -E "Subnet|Name" | grep -C5 192.168.0.0
        "Name": "my-network-11",
                    "Subnet": "172.30.0.0/16",
        "Name": "my-network-12",
                    "Subnet": "172.31.0.0/16",
        "Name": "my-network-13",
                    "Subnet": "192.168.0.0/20",
        "Name": "my-network-14",
                    "Subnet": "192.168.16.0/20",
        "Name": "my-network-15",
                    "Subnet": "192.168.32.0/20",
        "Name": "my-network-16",

docker-compose.yml

dns オプションに 192.168.0.1 を指定

version: '3'

services:
  dns-server:
    build:
      context: ./
      args:
        - http_proxy
        - https_proxy
    ports:
      - "192.168.99.100:53:53"
      - "192.168.99.100:53:53/udp"
    dns:
      - 192.168.0.1
    restart: always

dns指定ありの場合(docker networkとIPが衝突してない場合)

一つ前の条件から docker networkが削除削除された状態

docker network prune

名前解決できる

nslookup

$ winpty nslookup.exe example.com 192.168.99.100
サーバー:  UnKnown
Address:  192.168.99.100

権限のない回答:
名前:    example.com
Address:  93.184.216.34

192.168.99.100 は問い合わせに使うDNSサーバーのIP(コンテナ内DNSサーバー)

docker network

my-network-13 (192.168.0.0/20) は削除されたため、 ホストのDNSサーバーのIP 192.168.0.1と衝突している docker networkは存在しない

$ docker network inspect $(docker network ls -q) | grep -E "Subnet|Name" | grep -C5 192.168.0.0        
# (存在しない)

docker-compose.yml

dns オプションに 192.168.0.1 を指定

version: '3'

services:
  dns-server:
    build:
      context: ./
      args:
        - http_proxy
        - https_proxy
    ports:
      - "192.168.99.100:53:53"
      - "192.168.99.100:53:53/udp"
    dns:
      - 192.168.0.1
    restart: always

まとめ

  • dockerの dns オプションを指定した際は、docker networkとの衝突に注意が必要
    • コンテナ内から名前解決できなくなる
  • 以下の2つは等価ではない
    • docker の dns オプションを指定しない(デフォルトを使用する)
    • ホスト側DNSサーバーIPアドレス(例えば 192.168.0.1) を dockerの dns オプションに指定する