linux-networking – 不从Docker容器转发的UDP流量 – > Docker主机

前端之家收集整理的这篇文章主要介绍了linux-networking – 不从Docker容器转发的UDP流量 – > Docker主机前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个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实例.

一些配置:

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

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

  1. # /etc/resolv.conf
  2. search example.com
  3. nameserver 10.0.0.10
  4. nameserver 10.0.0.11

如果我用–debug重新启动docker守护程序,我在journalctl -u docker.service中看到以下内容

  1. 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."
  2. 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"
  3. 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来完全避免这个问题,即

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

(添加一行use-vc告诉解析器使用TCP而不是UDP.)

我确实在iptables中注意到一些可疑的规则,但结果证明这是正常的:

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

删除这两个DROP规则后,我继续看到这个问题.

完整iptables:

  1. # iptables -nL -v
  2. Chain INPUT (policy ACCEPT 2518 packets,1158K bytes)
  3. pkts bytes target prot opt in out source destination
  4.  
  5. Chain FORWARD (policy ACCEPT 0 packets,0 bytes)
  6. pkts bytes target prot opt in out source destination
  7. 23348 9674K DOCKER-ISOLATION all -- * * 0.0.0.0/0 0.0.0.0/0
  8. 0 0 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
  9. 0 0 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
  10. 0 0 ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
  11. 0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
  12. 23244 9667K DOCKER all -- * br-1d6a05c10468 0.0.0.0/0 0.0.0.0/0
  13. 23232 9667K ACCEPT all -- * br-1d6a05c10468 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
  14. 104 6230 ACCEPT all -- br-1d6a05c10468 !br-1d6a05c10468 0.0.0.0/0 0.0.0.0/0
  15. 12 700 ACCEPT all -- br-1d6a05c10468 br-1d6a05c10468 0.0.0.0/0 0.0.0.0/0
  16.  
  17. Chain OUTPUT (policy ACCEPT 2531 packets,414K bytes)
  18. pkts bytes target prot opt in out source destination
  19.  
  20. Chain DOCKER (2 references)
  21. pkts bytes target prot opt in out source destination
  22. 0 0 ACCEPT tcp -- !br-1d6a05c10468 br-1d6a05c10468 0.0.0.0/0 172.18.0.2 tcp dpt:443
  23. 0 0 ACCEPT tcp -- !br-1d6a05c10468 br-1d6a05c10468 0.0.0.0/0 172.18.0.2 tcp dpt:80
  24. 0 0 ACCEPT tcp -- !br-1d6a05c10468 br-1d6a05c10468 0.0.0.0/0 172.18.0.3 tcp dpt:389
  25.  
  26. Chain DOCKER-ISOLATION (1 references)
  27. pkts bytes target prot opt in out source destination
  28. 0 0 DROP all -- br-1d6a05c10468 docker0 0.0.0.0/0 0.0.0.0/0
  29. 0 0 DROP all -- docker0 br-1d6a05c10468 0.0.0.0/0 0.0.0.0/0
  30. 23348 9674K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0

桥配置

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

  1. # docker network inspect bridge
  2. [
  3. {
  4. "Name": "bridge","Id": "e159ddd37386cac91e0d011ade99a51f9fe887b8d32d212884beace67483af44","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {
  5. "Driver": "default","Options": null,"Config": [
  6. {
  7. "Subnet": "172.17.0.0/16","Gateway": "172.17.0.1"
  8. }
  9. ]
  10. },"Internal": false,"Containers": {},"Options": {
  11. "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"
  12. },"Labels": {}
  13. }
  14. ]

在日志中:

  1. Aug 04 17:33:32 myhost.example.com systemd[1]: Starting Docker Application Container Engine...
  2. 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"
  3. 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"
  4. 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."
  5. 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"
  6. 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"
  7. 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"
  8. 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"
  9. 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"
  10. 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"
  11. 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"
  12. 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"
  13. 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"
  14. 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"
  15. 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"
  16. 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."
  17. 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"
  18. 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
  19. 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"
  20. Aug 04 17:33:43 myhost.example.com systemd[1]: Started Docker Application Container Engine.

从容器,我可以ping默认网关,但所有名称解析都失败.

我注意到日志中有一个奇怪的东西(更新#2我现在知道这是一个红色的鲱鱼 – 见下面的讨论):

  1. # journalctl -u docker.service |grep insmod > /tmp/log # \n's replaced below
  2. 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
  3. sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-arptables: No such file or directory
  4. sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory
  5. sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directory
  6. modprobe: ERROR: Error running install command for bridge
  7. modprobe: ERROR: could not insert 'bridge': Unknown error 253
  8. insmod /lib/modules/3.10.0-514.26.2.el7.x86_64/kernel/net/llc/llc.ko
  9. insmod /lib/modules/3.10.0-514.26.2.el7.x86_64/kernel/net/802/stp.ko
  10. 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
  11. insmod /lib/modules/3.10.0-514.26.2.el7.x86_64/kernel/net/bridge/br_netfilter.ko,error: exit status 1"

更新#1:这来自:

  1. # tail -2 /etc/modprobe.d/dist.conf
  2. # Disable netfilter on bridges when the bridge module is loaded
  3. 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

也:

  1. # cat /proc/sys/net/bridge/bridge-nf-call-{arp,ip,ip6}tables
  2. 1
  3. 1
  4. 1

但是,即使我这样做了:

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

仍然没有运气.

我花了整整一天时间,所以现在把头发拉出来.任何关于我还能尝试什么的想法或其他问题可能会非常感激.

更新#4

我使用Netcat进行了一些实验,我已经证明,如果从任何容器发送,所有UDP数据包都不会被转发 – >主办.我尝试使用多个端口,包括53,2115和50000.然而,TCP数据包很好.如果我用iptables -F刷新iptables规则,这仍然是正确的.

此外,我可以将UDP数据包从一个容器发送到另一个容器 – 只有来自容器的UDP流量 – >主机未转发.

要设置测试:

在主机上,其IP为10.1.1.10:

  1. # nc -u -l 50000

在容器上:

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

在TCP转储捕获期间,我看到:

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

我试图通过this修复坏的UDP校验和失败.

然而,我注意到,即使在成功传输UDP数据包(主机 – >主机)和容器 – >期间,也会看到错误的UDP校验和.容器.

总之,我现在知道:

>路由很好
> iptables被刷新了
> SELinux很宽松
>所有TCP都可以在所有方向上运行
>所有来自容器的UDP – >容器很好
>来自主机的所有UDP – >主人很好
>来自主机的所有UDP – >容器很好
>但是没有来自容器的UDP数据包 – >主机被转发

解决方法

看来你有一个无法运行的modprobe安装指令.可能是RHEL 7.2或某些手动修复不完整更新的结果.

尝试使用grep -r bridge /etc/modprobe.d /lib/modprobe.d作为初学者,或以其他方式挖掘/etc/modprobe.d或/lib/modprobe.d并尝试查找它定义调用的安装规则的位置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处理已从桥接模块移动到br_netfilter模块.某些版本的内核* .rpm会发生这种情况,而modprobe.d目录的内容则与其他单个软件包一起分发.我在RHEL 7.2上验证了:

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

我没有在我的香草RHEL 7.1上看到这些“破碎”的规则,它们的起源对我来说是神秘的.我试过了:

  1. # modprobe -n -vvv bridge
  2. modprobe: INFO: custom logging function 0x40a130 registered
  3. insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/llc/llc.ko
  4. insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/802/stp.ko
  5. insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/bridge/bridge.ko
  6. modprobe: INFO: context 0xf1c270 released
  7. # echo "install bridge echo example_of_a_modprobe_rule" > /etc/modprobe.d/zzz5.conf
  8. # modprobe -n -vvv bridge
  9. modprobe: INFO: custom logging function 0x40a130 registered
  10. insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/llc/llc.ko
  11. insmod /lib/modules/3.10.0-229.11.1.el7.x86_64/kernel/net/802/stp.ko
  12. install echo example_of_a_modprobe_rule
  13. modprobe: INFO: context 0xeaa270 released
  14. # rm /etc/modprobe.d/zzz5.conf

更新:看起来像xenserver uses a similar modprobe hack.无论您是否实际运行xenserver,全局更改每个人的内核模块行为都是一个令人讨厌的错误.而这个错误已经向我们反击了.

更新2:现在,您发现/etc/modprobe.d/dist.conf导致此问题而不是docker.无论您是否有docker,modprobe bridge将始终返回1并打印错误.通常,dist.conf是RHEL6上module-init-tools包的一部分.此文件不应在RHEL7上使用.它不在我的任何RHEL7系统上,它们运行得很好.在RHEL7中,包是kmod,它不包含dist.conf.我会:

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

如果dist.conf不归包所有,请对其进行备份并删除任何不会给您带来任何明显好处的行(甚至可能完全删除文件).

如果dist.conf由一个软件包拥有,请考虑删除/更新该软件包,因为它在RHEL 7.2兼容性方面明显有问题.

猜你在找的Linux相关文章