Linux-Networking

未從 Docker 容器轉發的 UDP 流量 -> Docker 主機

  • March 20, 2021

我有一個 docker 容器,我無法從容器內部執行 DNS 查找,儘管它在 docker 主機上執行良好。

眾所周知,建構 Docker 主機的配置管理程式碼可以在市場上的標準 RHEL 7 映像上執行,因此已知問題出在 SOE RHEL 7 映像內部。

RHEL 7.2 / Docker 版本 1.12.6,建構 88a4867/1.12.6。容器是 RHEL 7.3。SELinux 處於啟用/許可模式。Docker 主機是一個 Amazon EC2 實例。

一些配置:

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

容器和主機中的解析器配置相同:

# /etc/resolv.conf
search example.com
nameserver 10.0.0.10
nameserver 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/docker
OPTIONS="--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-numbers
Chain 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           

刪除這兩個 DROP 規則後,我繼續看到問題。

完整的iptables:

# iptables -nL -v
Chain 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:389

Chain 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 docker0
4: 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-1d6a05c10468
3: 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.6
Aug 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.

從容器中,我可以 ping 預設網關,但所有名稱解析都失敗。

我注意到日誌中有一件奇怪的事情(更新 #2我現在知道這是一條紅鯡魚 - 請參閱下面的討論):

# journalctl -u docker.service |grep insmod > /tmp/log # \n's replaced below
Jul 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 directory
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directory
modprobe: ERROR: Error running install command for bridge
modprobe: ERROR: could not insert 'bridge': Unknown error 253
insmod /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 loaded
install 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}tables
1
1
1

但是,即使在我這樣做之後:

# 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 數據包被轉發

我想到了。

我們有一個趨勢科技(反病毒)代理在我不知道的 SOE 中執行。

修復它很簡單:

# systemctl stop ds_agent.service
# pkill ds_agent

目前還不確定為什麼它會阻止來自容器的 UDP 或如何阻止它。

看來您的 modprobeinstall指令無法正常工作。這可能是 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=0
sysctl: 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 bridge
modprobe: INFO: custom logging function 0x40a130 registered
insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/llc/llc.ko
insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/802/stp.ko
insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/bridge/bridge.ko
modprobe: INFO: context 0xf1c270 released
# echo "install bridge echo example_of_a_modprobe_rule" > /etc/modprobe.d/zzz5.conf
# modprobe -n -vvv bridge
modprobe: INFO: custom logging function 0x40a130 registered
insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/llc/llc.ko
insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/802/stp.ko
install echo example_of_a_modprobe_rule
modprobe: INFO: context 0xeaa270 released
# rm /etc/modprobe.d/zzz5.conf

**更新:**看起來xenserver 使用了類似的 modprobe hack。無論您是否實際執行 xenserver,全域更改每個人的核心模組行為都是一個令人討厭的錯誤;並且這個錯誤已經向我們發起了反擊。

**更新 2:**現在,您發現/etc/modprobe.d/dist.conf導致此問題的原因不是 docker。不管你有沒有 docker, modprobe bridge總是會返回 1 並列印錯誤。通常 dist.conf 是module-init-toolsRHEL6 上軟體包的一部分。該文件不應該在 RHEL7 上使用。它不在我的任何 RHEL7 系統上,它們執行得很好。在 RHEL7 中,該軟體包是kmod並且它不包含 dist.conf。我會:

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

如果 dist.conf 不屬於包,請備份它並刪除任何不會給您帶來任何明顯好處的行(甚至可能完全刪除該文件)。

如果 dist.conf 屬於某個包,請考慮刪除/更新該包,因為它在 RHEL 7.2 兼容性方面明顯存在缺陷。

引用自:https://serverfault.com/questions/866830