DNS не работает в контейнерах docker, когда хост использует dnsmasq и DNS-сервер Google брандмауэр?

симптом: хост-машина имеет правильный доступ к сети, но программы, работающие в контейнерах, не могут разрешить DNS-имена (которые могут показаться "не могут получить доступ к сети", прежде чем исследовать больше).

$ sudo docker run -ti mmoy/ubuntu-netutils /bin/bash
root@082bd4ead733:/# ping www.example.com
... nothing happens (timeout) ... ^C
root@082bd4ead733:/# host www.example.com
... nothing happens (timeout) ... ^C

(докер изображения mmoy / ubuntu-netutils это простое изображение на основе Ubuntu с ping и host включено, удобно здесь, так как сеть сломана, и мы не можем apt install эти средства)

проблема исходит от тот факт, что docker автоматически настроил общедоступный DNS Google в качестве DNS-сервера в контейнере:

root@082bd4ead733:/# cat /etc/resolv.conf 
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 8.8.8.8
nameserver 8.8.4.4

это просто работает во многих конфигурациях, но, очевидно, не работает, когда хост работает в сети, где общедоступные DNS Google фильтруются некоторыми правилами брандмауэра.

причина, по которой это случилось:

  • Docker сначала пытается настроить один и тот же DNS-сервер(ы) на хосте и в контейнере.
  • хост работает dnsmasq, служба кэширования DNS. dnsmasq действует как прокси для DNS-запросов, следовательно, очевидный DNS-сервер в /etc/resolve.conf is nameserver 127.0.1.1, т. е. на localhost.
  • dnsmasq хоста прослушивает только запросы, поступающие от localhost и блокирует запросы, поступающие из контейнера docker.
  • С помощью 127.0.1.1 в docker не работает, docker возвращается к общедоступному DNS Google, который тоже не работает.

может быть несколько причины, по которым DNS нарушается в контейнерах docker. Этот вопрос (и ответы) охватывает случай, когда:

  • используется dnsmasq. Чтобы проверить, так ли это:
    • выполнить ps -e | grep dnsmasq на хосте. Если выходные данные пусты, dnsmasq не выполняется.
    • проверить хост файл resolv.conf, он, вероятно, содержит запись типа nameserver 127.0.1.1. Если он содержит nameserver 127.0.0.53, вы, вероятно, работает systemd-resolved вместо dnsmasq. Если это так, вы не сможете использовать решение пересылки DNS-запросов в dnsmasq (тот, который использует listen-address=172.17.0.1). systemd-resolved hardcodes тот факт, что он слушает только на интерфейсе "lo", поэтому нет простого способа адаптировать это решение. Другие ответы ниже будут работать с systemd-resolved.
  • публичный DNS Google фильтруется. Запустить host www.example.com 8.8.8.8. Если это не удается или тайм-аут, то вы находитесь в этой ситуации.

каковы решения для получения правильной конфигурации DNS в такой конфигурации?

5 ответов


чистым решением является настройка docker + dnsmasq, чтобы DNS-запросы из контейнера docker перенаправлялись демону dnsmasq, работающему на хосте.

для этого нужно настройте dnsmasq для прослушивания сетевого интерфейса, используемого docker, добавив файл /etc/NetworkManager/dnsmasq.d/docker-bridge.conf:

$ cat /etc/NetworkManager/dnsmasq.d/docker-bridge.conf
listen-address=172.17.0.1

затем перезапустите network manager, чтобы учесть файл конфигурации:

sudo service network-manager restart

как только это сделано, вы можете добавить 172.17.0.1, т. е. IP-адрес хоста из docker, в список DNS-серверов. Это можно сделать либо с помощью командной строки:

$ sudo docker run -ti --dns 172.17.0.1 mmoy/ubuntu-netutils bash
root@7805c7d153cc:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.6 ms

... или через файл конфигурации docker /etc/docker/daemon.json (создайте его, если он не существует):

$ cat /etc/docker/daemon.json                      
{
  "dns": [
    "172.17.0.1",
        "8.8.8.8",
        "8.8.4.4"
  ]
}

(это вернется к публичному DNS Google, если dnsmasq не удастся)

вам нужно перезапустить docker, чтобы файл конфигурации был принят во внимание:

sudo service docker restart

тогда вы можете использовать docker как обычно:

$ sudo docker run -ti mmoy/ubuntu-netutils bash
root@344a983908cb:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.3 ms

жестокое и небезопасное решение-избежать контейнеризации сети и использовать одну и ту же сеть на хосте и на контейнере. Это небезопасно, потому что это дает доступ ко всем сетевым ресурсам хоста к контейнеру, но если вам не нужна эта изоляция, это может быть приемлемо.

для этого просто добавьте --network host в командную строку, например

$ sudo docker run -ti --network host mmoy/ubuntu-netutils /bin/bash
root@ubuntu1604:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=55 time=86.5 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=55 time=86.5 ms

поскольку автоматическое обнаружение DNS виновно здесь, вы можете переопределить настройку по умолчанию в конфигурации docker.

во-первых, получите IP-адрес DNS-сервера, который dnsmasq использует, например:

$ sudo kill -USR1 `pidof dnsmasq`
$ sudo tail /var/log/syslog 
[...]
Apr 24 13:20:19 host dnsmasq[2537]: server xx.yy.zz.tt1#53: queries sent 0, retried or failed 0
Apr 24 13:20:19 host dnsmasq[2537]: server xx.yy.zz.tt2#53: queries sent 0, retried or failed 0

IP-адреса соответствуют xx.yy.zz.tt выше заполнители.

вы можете установить DNS в docker run времени :

$ sudo docker run --dns xx.yy.zz.tt1 --dns xx.yy.zz.tt2 -ti mmoy/ubuntu-netutils bash
root@6c5d08df5dfd:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.6 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=54 time=86.6 ms

одним из преимуществ этого решения является то, что нет файла конфигурации, следовательно нет риска забыть о конфигурации и столкнуться с проблемами позже из-за определенной конфигурации: вы получаете эту конфигурацию DNS, если и только если вы вводите .

в качестве альтернативы вы можете установить его постоянно в файле конфигурации Docker,/etc/docker/daemon.json (создайте его на хосте, если он не существует):

$ cat /etc/docker/daemon.json
{
    "dns": ["xx.yy.zz.tt1", "xx.yy.zz.tt2"]
}

вам нужно перезапустить демон docker, чтобы взять на счет:

sudo service docker restart

затем вы можете проверить конфигурация:

$ sudo docker run -ti mmoy/ubuntu-netutils bash
root@56c74d3bd94b:/# cat /etc/resolv.conf 
nameserver xx.yy.zz.tt1
nameserver xx.yy.zz.tt2
root@56c74d3bd94b:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.5 ms

обратите внимание, что это жестко кодирует DNS-IP в ваших файлах конфигурации. Это настоятельно рекомендуется, если ваш компьютер является ноутбуком, который подключается к различным сетям, и может быть проблематичным, если ваш интернет-провайдер изменяет IP-адрес DNS-серверов.


один из способов-это использовать пользовательские сети для вашего контейнера. В этом случае контейнер /etc/resolv.conf будет сервер 127.0.0.11 (a.к. a. Докер!--9-->встроенный DNS-сервер), который может правильно пересылать DNS-запросы на обратный адрес хоста.

$ cat /etc/resolv.conf
nameserver 127.0.0.1
$ docker run --rm alpine cat /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
$ docker network create demo
557079c79ddf6be7d6def935fa0c1c3c8290a0db4649c4679b84f6363e3dd9a0
$ docker run --rm --net demo alpine cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0    

если вы используете docker-compose, он автоматически настроит пользовательскую сеть для ваших услуг (с форматом файла v2+). Заметьте, однако, что while docker-compose запускает контейнеры в пользовательской сети, он по-прежнему строит их в сеть по умолчанию. Чтобы использовать пользовательскую сеть для сборки, вы можете указать на конфигурация (требуется файл формат В3.4+).


С dnsmasq проблема, один из вариантов-отключить его на хосте. Это работает, но отключит кэширование DNS для всех приложений, запущенных на хосте, поэтому очень плохая идея, если хост используется для приложений, отличных от docker.

если вы уверены, что хотите пойти этим путем, удалите dnsmasq, например, в системах на основе Debian, таких как Ubuntu, запустите apt remove dnsmasq.

вы можете проверить это /etc/resolv.conf в контейнере указывает на DNS-сервер, используемый хозяин.