UDP-трафик не пересылается из контейнеров Docker -> Docker host

У меня есть контейнер docker, и я не могу запускать поиск DNS из внутренних контейнеров, хотя он отлично работает с хоста docker.

Известно, что код управления конфигурацией, который создает узел Docker, работает со стандартным образом RHEL 7 из marketplace, поэтому известно, что проблема заключается в чем-то внутри образа SOE RHEL 7.

RHEL 7.2 / Docker версии 1.12.6, сборка 88a4867/1.12.6. Контейнером является RHEL 7.3. SELinux во включенном/разрешенном режиме. Хост Docker - это экземпляр Amazon EC2.

Некоторая конфигурация:

# /etc/sysconfig/dockerOPTIONS='--dns=10.0.0.10 --dns=10.0.0.11 --dns-search=example.com'DOCKER_CERT_PATH=/etc/dockerADD_REGISTRY='--add-registry registry.example.com'no_proxy=169.254.169.254,localhost,127.0.0.1,registory.example.comhttp_proxy=http://proxy.example.com:8080https_proxy=http://proxy.example.com:8080ftp_proxy=http://proxy.example.com:8080

Конфигурация преобразователя в контейнере и хосте одинакова:

# /etc/resolv.confsearch example.comnameserver 10.0.0.10nameserver 10.0.0.11

Если я перезапущу демон docker с помощью --debug Я вижу следующее в journalctl -u docker.service:

Aug 08 11:44:23 myhost.example.com dockerd-current[17341]: time="2017-08-08T11:44:23.430769581+10:00" level=debug msg="Name To resolve: http://proxy.example.com."Aug 08 11:44:23 myhost.example.com dockerd-current[17341]: time="2017-08-08T11:44:23.431488213+10:00" level=debug msg="Query http://proxy.example.com.[1] from 172.18.0.6:38189, forwarding to udp:10.162.182.101"Aug 08 11:44:27 myhost.example.com dockerd-current[17341]: time="2017-08-08T11:44:27.431772666+10:00" level=debug msg="Read from DNS server failed, read udp 172.18.0.6:38189->10.162.182.101:53: i/o timeout"

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

Действительно, (обновление #3) оказывается, я могу полностью избежать этой проблемы, просто настроив DNS на использование TCP вместо UDP, т.Е.

# head -1 /etc/sysconfig/dockerOPTIONS="--dns=10.0.0.10 --dns=10.0.0.11 --dns-search=example.com --dns-opt=use-vc"

(Добавление строки use-vc сообщает преобразователю использовать TCP вместо UDP.)

Я действительно заметил некоторые подозрительно выглядящие правила в iptables, но они оказались нормальными:

# iptables -n -L DOCKER-ISOLATION -v --line-numbersChain DOCKER-ISOLATION (1 references)num   pkts bytes target     prot opt in     out     source               destination         1        0     0 DROP       all  --  br-1d6a05c10468 docker0  0.0.0.0/0            0.0.0.0/0           2        0     0 DROP       all  --  docker0 br-1d6a05c10468  0.0.0.0/0            0.0.0.0/0           3    34903   11M RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

После удаления этих двух правил УДАЛЕНИЯ я продолжал видеть проблему.

Полные iptables:

# iptables -nL -vChain INPUT (policy ACCEPT 2518 packets, 1158K bytes) pkts bytes target     prot opt in     out     source               destination         Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target     prot opt in     out     source               destination         23348 9674K DOCKER-ISOLATION  all  --  *      *       0.0.0.0/0            0.0.0.0/0               0     0 DOCKER     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0               0     0 ACCEPT     all  --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED    0     0 ACCEPT     all  --  docker0 !docker0  0.0.0.0/0            0.0.0.0/0               0     0 ACCEPT     all  --  docker0 docker0  0.0.0.0/0            0.0.0.0/0           23244 9667K DOCKER     all  --  *      br-1d6a05c10468  0.0.0.0/0            0.0.0.0/0           23232 9667K ACCEPT     all  --  *      br-1d6a05c10468  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED  104  6230 ACCEPT     all  --  br-1d6a05c10468 !br-1d6a05c10468  0.0.0.0/0            0.0.0.0/0              12   700 ACCEPT     all  --  br-1d6a05c10468 br-1d6a05c10468  0.0.0.0/0            0.0.0.0/0           Chain OUTPUT (policy ACCEPT 2531 packets, 414K bytes) pkts bytes target     prot opt in     out     source               destination         Chain DOCKER (2 references) pkts bytes target     prot opt in     out     source               destination             0     0 ACCEPT     tcp  --  !br-1d6a05c10468 br-1d6a05c10468  0.0.0.0/0            172.18.0.2           tcp dpt:443    0     0 ACCEPT     tcp  --  !br-1d6a05c10468 br-1d6a05c10468  0.0.0.0/0            172.18.0.2           tcp dpt:80    0     0 ACCEPT     tcp  --  !br-1d6a05c10468 br-1d6a05c10468  0.0.0.0/0            172.18.0.3           tcp dpt:389Chain DOCKER-ISOLATION (1 references) pkts bytes target     prot opt in     out     source               destination             0     0 DROP       all  --  br-1d6a05c10468 docker0  0.0.0.0/0            0.0.0.0/0               0     0 DROP       all  --  docker0 br-1d6a05c10468  0.0.0.0/0            0.0.0.0/0           23348 9674K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0           

Конфигурация моста

# ip addr show docker04: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN     link/ether 02:42:a8:73:db:bb brd ff:ff:ff:ff:ff:ff    inet 172.17.0.1/16 scope global docker0       valid_lft forever preferred_lft forever# ip addr show br-1d6a05c104683: br-1d6a05c10468: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP     link/ether 02:42:d5:b6:2d:f5 brd ff:ff:ff:ff:ff:ff    inet 172.18.0.1/16 scope global br-1d6a05c10468       valid_lft forever preferred_lft forever

и

# docker network inspect bridge [    {        "Name": "bridge",        "Id": "e159ddd37386cac91e0d011ade99a51f9fe887b8d32d212884beace67483af44",        "Scope": "local",        "Driver": "bridge",        "EnableIPv6": false,        "IPAM": {            "Driver": "default",            "Options": null,            "Config": [                {                    "Subnet": "172.17.0.0/16",                    "Gateway": "172.17.0.1"                }            ]        },        "Internal": false,        "Containers": {},        "Options": {            "com.docker.network.bridge.default_bridge": "true",            "com.docker.network.bridge.enable_icc": "true",            "com.docker.network.bridge.enable_ip_masquerade": "true",            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",            "com.docker.network.bridge.name": "docker0",            "com.docker.network.driver.mtu": "1500"        },        "Labels": {}    }]

В журналах:

Aug 04 17:33:32 myhost.example.com systemd[1]: Starting Docker Application Container Engine...Aug 04 17:33:33 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:33.056770003+10:00" level=info msg="libcontainerd: new containerd process, pid: 2140"Aug 04 17:33:34 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:34.740346421+10:00" level=info msg="Graph migration to content-addressability took 0.00 seconds"Aug 04 17:33:34 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:34.741164354+10:00" level=info msg="Loading containers: start."Aug 04 17:33:34 myhost.example.com dockerd-current[2131]: .........................time="2017-08-04T17:33:34.903371015+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:35 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:35.325581993+10:00" level=info msg="Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address" Aug 04 17:33:36 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:36+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:37 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:37+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:37 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:37+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:38 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:38+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:39 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:39+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:40 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:40+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:40 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:40+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:42 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:42+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:42 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:42+10:00" level=info msg="Firewalld running: true"Aug 04 17:33:43 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:43.541905145+10:00" level=info msg="Loading containers: done."Aug 04 17:33:43 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:43.541975618+10:00" level=info msg="Daemon has completed initialization"Aug 04 17:33:43 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:43.541998095+10:00" level=info msg="Docker daemon" commit="88a4867/1.12.6" graphdriver=devicemapper version=1.12.6Aug 04 17:33:43 myhost.example.com dockerd-current[2131]: time="2017-08-04T17:33:43.548508756+10:00" level=info msg="API listen on /var/run/docker.sock"Aug 04 17:33:43 myhost.example.com systemd[1]: Started Docker Application Container Engine.

Из контейнера я могу пинговать шлюз по умолчанию, но все разрешения имен завершаются ошибкой.

Я заметил одну странную вещь в журнале (Обновление #2 Теперь я знаю, что это отвлекающий маневр - см. Обсуждение ниже):

# journalctl -u docker.service |grep insmod > /tmp/log # \n's replaced belowJul 26 23:59:02 myhost.example.com dockerd-current[3185]: time="2017-07-26T23:59:02.056295890+10:00" level=warning msg="Running modprobe bridge br_netfilter failed with message: insmod /lib/modules/3.10.0-514.26.2.el7.x86_64/kernel/net/bridge/bridge.ko sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-arptables: No such file or directorysysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directorysysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directorymodprobe: ERROR: Error running install command for bridgemodprobe: ERROR: could not insert 'bridge': Unknown error 253insmod /lib/modules/3.10.0-514.26.2.el7.x86_64/kernel/net/llc/llc.ko insmod /lib/modules/3.10.0-514.26.2.el7.x86_64/kernel/net/802/stp.ko install /sbin/modprobe --ignore-install bridge && /sbin/sysctl -q -w net.bridge.bridge-nf-call-arptables=0 net.bridge.bridge-nf-call-iptables=0 net.bridge.bridge-nf-call-ip6tables=0 insmod /lib/modules/3.10.0-514.26.2.el7.x86_64/kernel/net/bridge/br_netfilter.ko , error: exit status 1"

Обновление #1: и это исходит от:

# tail -2 /etc/modprobe.d/dist.conf# Disable netfilter on bridges when the bridge module is loadedinstall bridge /sbin/modprobe --ignore-install bridge && /sbin/sysctl -q -w net.bridge.bridge-nf-call-arptables=0 net.bridge.bridge-nf-call-iptables=0 net.bridge.bridge-nf-call-ip6tables=0

Также:

# cat /proc/sys/net/bridge/bridge-nf-call-{arp,ip,ip6}tables111

Однако, даже после того, как я сделаю это:

# for i in /proc/sys/net/bridge/bridge-nf-call-{arp,ip,ip6}tables ; do echo 0 > $i ; done 

По-прежнему безуспешно.

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

Обновление #4

>Я провел несколько экспериментов с использованием Netcat и доказал, что все UDP-пакеты не пересылаются, если они отправляются с любого хоста-контейнера. Я попробовал использовать несколько портов, включая 53, 2115 и 50000. Однако TCP-пакеты в порядке. Это по-прежнему верно, если я сброшу правила iptables с помощью iptables -F.

>Кроме того, я могу отправлять UDP-пакеты из одного контейнера в другой - только UDP-трафик с контейнера - хоста не пересылается.

Чтобы настроить тест:

На хосте, который имеет IP 10.1.1.10:

# nc -u -l 50000

На контейнере:

# echo "foo" | nc -w1 -u 10.1.1.10 50000

Во время захвата дампа TCP я вижу:

17:20:36.761214 IP (tos 0x0, ttl 64, id 48146, offset 0, flags [DF], proto UDP (17), length 32)    172.17.0.2.41727 > 10.1.1.10.50000: [bad udp cksum 0x2afa -> 0x992f!] UDP, length 4        0x0000:  4500 0020 bc12 4000 4011 53de ac11 0002  E.....@.@.S.....        0x0010:  0aa5 7424 a2ff c350 000c 2afa 666f 6f0a  ..t$...P..*.foo.        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................17:20:36.761214 IP (tos 0x0, ttl 64, id 48146, offset 0, flags [DF], proto UDP (17), length 32)    172.17.0.2.41727 > 10.1.1.10.50000: [bad udp cksum 0x2afa -> 0x992f!] UDP, length 4        0x0000:  4500 0020 bc12 4000 4011 53de ac11 0002  E.....@.@.S.....        0x0010:  0aa5 7424 a2ff c350 000c 2afa 666f 6f0a  ..t$...P..*.foo.        0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................

Я безуспешно пытался исправить неправильные контрольные суммы UDP с помощью этот.

>>Однако я отметил, что неверные контрольные суммы UDP видны даже во время успешной передачи пакетов UDP (хост - хост) и контейнер - контейнер.

Подводя итог, теперь я знаю:

  • маршрутизация в порядке

  • iptables сбрасывается

  • SELinux является разрешающим

  • все TCP работает во всех направлениях

  • >весь UDP из контейнера - контейнера в порядке

  • >весь UDP от хоста - хоста в порядке

  • >весь UDP из хост- контейнера в порядке

  • но> никакие UDP-пакеты от хоста-контейнера не пересылаются

Я все понял.

У нас в госпредприятии был запущен агент Trend Micro (антивирус), о котором я не знал.

Исправить это было так же просто, как:

# systemctl stop ds_agent.service# pkill ds_agent

На данный момент я не совсем уверен, почему он блокирует UDP из контейнеров или как его остановить.

Похоже, у вас есть modprobe install директива, которая не может работать. Возможно, это результат неполного обновления до RHEL 7.2 или некоторых ручных исправлений.

Попробуй grep -r bridge /etc/modprobe.d /lib/modprobe.d для начала, или как-то иначе покопаться /etc/modprobe.d или /lib/modprobe.d и попытайтесь найти, где это определяет install правило, которое вызывает sysctl -q -w net.bridge.bridge-nf-call-arptables=0 net.bridge.bridge-nf-call-iptables=0 net.bridge.bridge-nf-call-ip6tables=0

Этот sysctl явно находится не в том месте. Это либо излишне, либо должно появиться после br_netfilter, не раньше. Почему? Недавно в /proc/sys/net/bridge обработка была перенесена с bridge модуль к br_netfilter модуль. Это происходит с некоторой версией kernel*.rpm, в то время как содержание modprobe.d каталоги распространяются вместе с другими отдельными пакетами. Я проверил на своем RHEL 7.2:

# modprobe bridge# sysctl -q -w net.bridge.bridge-nf-call-iptables=0sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory# modprobe br_netfilter# sysctl -q -w net.bridge.bridge-nf-call-iptables=0    # ok now

Я не вижу этих "нарушенных" правил на моем ванильном RHEL 7.1 и их происхождение для меня загадочно. Я пытался:

# modprobe -n -vvv bridgemodprobe: INFO: custom logging function 0x40a130 registeredinsmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/llc/llc.koinsmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/802/stp.koinsmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/bridge/bridge.komodprobe: INFO: context 0xf1c270 released# echo "install bridge echo example_of_a_modprobe_rule" > /etc/modprobe.d/zzz5.conf# modprobe -n -vvv bridgemodprobe: INFO: custom logging function 0x40a130 registeredinsmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/llc/llc.koinsmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/802/stp.koinstall echo example_of_a_modprobe_rulemodprobe: INFO: context 0xeaa270 released# rm /etc/modprobe.d/zzz5.conf

Обновление: Выглядит как xenserver использует аналогичный взлом modprobe. Это неприятная ошибка, позволяющая глобально изменять поведение модуля ядра для всех, независимо от того, действительно ли вы запускаете xenserver или нет; и ошибка дала нам отпор.

Обновление 2: Теперь вы обнаружили, что /etc/modprobe.d/dist.conf вызывает эту проблему, а не docker. Независимо от того, есть у вас docker или нет, modprobe bridge всегда будет возвращать значение 1 и выводить ошибку. Обычно dist.conf является частью module-init-tools пакет на RHEL6. Этот файл не должен использоваться на RHEL7. Этого нет ни в одной из моих систем RHEL7, и они работают просто отлично. В RHEL7 пакет представляет собой kmod и он не содержит dist.conf. Я бы:

rpm -qf /etc/modprobe.d/dist.conf  # what package owns this file?

Если dist.conf не принадлежит package, создайте его резервную копию и удалите все строки, которые не дают вам никакой очевидной пользы (возможно, даже удалите файл вообще).

Если dist.conf принадлежит пакету, рассмотрите возможность удаления / обновления этого пакета, поскольку он явно стал глючным с точки зрения совместимости с RHEL 7.2.

У меня были проблемы с распознавателем DNS в наших контейнерах docker. Я перепробовал много разных вещей, и, в конце концов, я просто понял, что мой VPS в Hostgator не был установлен по умолчанию NetworkManager-tui (nmtui), Я только что установил и перезагрузил его.

sudo yum install NetworkManager-tui

И перенастроил свой resolv.conf с DNS по умолчанию в качестве 8.8.8.8.

nano /etc/resolv.conf

@Сироты, обновлено результатами моих экспериментов с netcat. По сути, весь UDP из container → host теряется, но TCP работает нормально, и UDP также работает из container → container и из host → container. И все верно после iptables -F.

Помогает ли это? How do I publish a UDP Port on Docker? - Stack Overflow

Спасибо, но нет, речь идет о переадресации портов - переадресации порта в контейнере, чтобы клиент мог подключиться к нему по адресу на хосте Docker. В моем случае контейнер пытается отправить исходящие UDP-пакеты.

На каком интерфейсе вы запустили tcpdump? Вы должны запустить его в интерфейсе docker0, исходящем интерфейсе вашего хоста и на сервере имен, чтобы увидеть, куда отбрасываются пакеты (вероятно, из-за плохой контрольной суммы UDP). Можете ли вы запустить “iptables -t mangle -A POSTROUTING -o docker0 -p udp -j CHECKSUM --checksum-fill”, чтобы узнать, устраняет ли это вашу проблему? Если ваш хост - виртуальная машина и предыдущая команда не устранила вашу проблему, также сделайте это в исходящем интерфейсе.

Предложенная вами команда “iptables” не оказала никакого эффекта, который я могу наблюдать. Мой хост - это экземпляр Amazon EC2 с одним интерфейсом “eth0”. Если я запускаю `tcpdump -i eth0 порт 53", пакеты не отображаются, что означает, что они были сброшены на мосту. Интуитивно я не могу поверить, что проблема заключается в плохих контрольных суммах UDP, учитывая, что они присутствуют во всех направлениях, но трафик отбрасывается только в направлении контейнер → хост.

Могут ли ваши контейнеры разговаривать по порту 53?
telnet 8.8.8.8 53

Я не могу добраться до порта 53 8.8.8.8 (TCP), потому что 8.8.8.8 заблокирован брандмауэром компании. Однако я могу подключиться к своему локальному DNS-серверу через TCP-порт 53 - см. Мое обновление. Утром я намерен найти способ использовать netcat, чтобы попытаться доказать (во что я сейчас верю), что проблема на самом деле заключается в том, что эти контейнеры просто не пересылают исходящий UDP-трафик.