【问题标题】:Why Docker containers can't communicate with each other?为什么 Docker 容器不能相互通信?
【发布时间】:2015-11-01 10:54:22
【问题描述】:

我创建了一个小的project 来测试Docker 集群。基本上,cluster.sh 脚本会启动三个相同的容器,并使用pipework 在主机上配置一个网桥(bridge1),并为每个容器添加一个网卡(eth1)。

如果我登录其中一个容器,我可以arping其他容器:

# 172.17.99.1
root@d01eb56fce52:/# arping 172.17.99.2
ARPING 172.17.99.2
42 bytes from aa:b3:98:92:0b:08 (172.17.99.2): index=0 time=1.001 sec
42 bytes from aa:b3:98:92:0b:08 (172.17.99.2): index=1 time=1.001 sec
42 bytes from aa:b3:98:92:0b:08 (172.17.99.2): index=2 time=1.001 sec
42 bytes from aa:b3:98:92:0b:08 (172.17.99.2): index=3 time=1.001 sec
^C
--- 172.17.99.2 statistics ---
5 packets transmitted, 4 packets received,  20% unanswered (0 extra)

看来数据包可以通过bridge1

但问题是我不能 ping 其他容器,我也不能通过任何工具发送任何 IP 数据包,例如 telnetnetcat

相比之下,网桥docker0 和网卡eth0 在所有容器中都能正常工作。

这是我的路由表

# 172.17.99.1
root@d01eb56fce52:/# ip route
default via 172.17.42.1 dev eth0 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.17 
172.17.99.0/24 dev eth1  proto kernel  scope link  src 172.17.99.1

和桥接配置

# host
$ brctl show
bridge name bridge id       STP enabled interfaces
bridge1     8000.8a6b21e27ae6   no      veth1pl25432
                                        veth1pl25587
                                        veth1pl25753
docker0     8000.56847afe9799   no      veth7c87801
                                        veth953a086
                                        vethe575fe2

# host
$ brctl showmacs bridge1
port no mac addr        is local?   ageing timer
  1 8a:6b:21:e2:7a:e6   yes        0.00
  2 8a:a3:b8:90:f3:52   yes        0.00
  3 f6:0c:c4:3d:f5:b2   yes        0.00

# host
$ ifconfig
bridge1   Link encap:Ethernet  HWaddr 8a:6b:21:e2:7a:e6  
          inet6 addr: fe80::48e9:e3ff:fedb:a1b6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:163 errors:0 dropped:0 overruns:0 frame:0
          TX packets:68 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:8844 (8.8 KB)  TX bytes:12833 (12.8 KB)

# I'm showing only one veth here for simplicity
veth1pl25432 Link encap:Ethernet  HWaddr 8a:6b:21:e2:7a:e6  
          inet6 addr: fe80::886b:21ff:fee2:7ae6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:155 errors:0 dropped:0 overruns:0 frame:0
          TX packets:162 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:12366 (12.3 KB)  TX bytes:23180 (23.1 KB)

...

和IP FORWARD链

# host
$ sudo iptables -x -v --line-numbers -L FORWARD
Chain FORWARD (policy ACCEPT 10675 packets, 640500 bytes)
num      pkts      bytes target     prot opt in     out     source               destination         
1       15018 22400195 DOCKER     all  --  any    docker0  anywhere             anywhere            
2       15007 22399271 ACCEPT     all  --  any    docker0  anywhere             anywhere             ctstate RELATED,ESTABLISHED
3        8160   445331 ACCEPT     all  --  docker0 !docker0  anywhere             anywhere            
4          11      924 ACCEPT     all  --  docker0 docker0  anywhere             anywhere            
5          56     4704 ACCEPT     all  --  bridge1 bridge1  anywhere             anywhere            

注意规则 5 的 pkts 计数不为 0,这意味着 ping 已正确路由(路由后执行 FORWARD 链对吗?),但不知何故没有到达目的地。

我不知道为什么 docker0bridge1 行为不同。有什么建议吗?

更新 1

这是从另一个容器 ping 时目标容器上的 tcpdump 输出。

$ tcpdump -i eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
22:11:17.754261 IP 192.168.1.65 > 172.17.99.1: ICMP echo request, id 26443, seq 1, length 6

注意源IP是192.168.1.65,也就是主机的eth0,所以网桥上好像有一些SNAT。

最后,打印出nat IP 表揭示了问题的原因:

$ sudo iptables -L -t nat
...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        anywhere
...

因为我的容器的eth0 的IP 在172.17.0.0/16,所以发送的数据包的源IP 发生了变化。这就是为什么ping 的回复无法回到源头的原因。

结论

解决方法是将容器的eth0 的IP 更改为与默认docker0 不同的网络。

【问题讨论】:

  • 我正在尝试 ping 从一个容器到另一个容器,而不是从主机到容器。因此,我没有为主机上的bridge1 分配 IP。
  • 你应该看看这篇文章“从一个容器向另一个容器发送信号”blog.dixo.net/2015/02/…
  • 好吧,事实证明关键是在同一网络中将 IP 实际分配给 bridge1。我认为这是不必要的,但它解决了问题。如果有人知道为什么,请告诉我。
  • 这里有一个类似的问题,superuser.com/q/916368/201625
  • 我已经解决了这个问题。请查看更新。

标签: linux routing docker ip containers


【解决方案1】:

从有问题的Update 1复制

这是从另一个容器 ping 时目标容器上的 tcpdump 输出。

$ tcpdump -i eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
22:11:17.754261 IP 192.168.1.65 > 172.17.99.1: ICMP echo request, id 26443, seq 1, length 6

注意源IP是192.168.1.65,也就是主机的eth0,所以网桥上好像有一些SNAT。

最后,打印出nat IP 表揭示了问题的原因:

$ sudo iptables -L -t nat
...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        anywhere
...

因为我容器的eth0 的IP 在172.17.0.0/16,所以发送的数据包的源IP 发生了变化。这就是为什么来自ping 的回复无法回到源头的原因。

结论

解决方法是将容器的eth0的IP更改为与默认docker0不同的网络。

【讨论】:

    猜你喜欢
    • 2019-10-09
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 2017-12-04
    相关资源
    最近更新 更多