docker 容器无法在桥接网络模式下访问互联网

ber*_*ert 6 networking linux dns docker

TL;DR 如何修复网桥 docker0,以便在网络模式桥接时能够从我的容器访问互联网?


几周前发生的一次停电显然破坏了服务器网络配置,并且有一段时间,DHCP 服务器没有为计算机分配正确的 IP。我设法通过配置网络来解决这个问题netplan(我不能保证在停电之前完成,它是由另一个团队管理的)。

然而,docker当网络模式为 时,容器无法访问互联网bridge

从主机上,我可以ping google.com并且 DNS 解析工作正常。其他一切似乎也都有效。但是,当我启动一个容器(例如:)时 docker run -it --rm python:3.6.1 /bin/bashping不再起作用了。

所以这是我检查过的几件事:

  1. ping在容器内不起作用:

ping google.com只是挂起:

root@85deb9b2ae95:/# ping google.com
^C
Run Code Online (Sandbox Code Playgroud)

ping 8.8.8.8丢失所有包裹:

root@85deb9b2ae95:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
^C--- 8.8.8.8 ping statistics ---
9 packets transmitted, 0 packets received, 100% packet loss
Run Code Online (Sandbox Code Playgroud)
  1. /etc/resolv.conf在 docker 容器中看起来没问题:
root@85deb9b2ae95:/# cat /etc/resolv.conf 
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 8.8.8.8
nameserver 1.1.1.1
Run Code Online (Sandbox Code Playgroud)

(和楼主的一模一样)

  1. docker network inspect bridge对我来说看起来不错:
my_user@my_host:~$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "ba15db4d28312e1e7147704d4b04ed12d5acf3ffc03d5308a61e88171ff21b59",
        "Created": "2022-09-30T12:04:54.442845526Z",
        "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,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "85deb9b2ae951810887faf6a89b1980bd4ae35d6a61a1639982a3a6558f8100f": {
                "Name": "strange_fermi",
                "EndpointID": "181fede143c82cee3aff9feec8bfff10daf9fbcbd1e70a69bd99ee51f28ed5e4",
                "MacAddress": "xx:xx:xx:xx:xx:xx",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "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": {}
    }
]
Run Code Online (Sandbox Code Playgroud)
  1. ifconfig对我来说看起来不错(这是RUNNING因为容器正在运行):
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 xx::xx:xx:xx:xx  prefixlen 64  scopeid 0x20<link>
        ether xx:xx:xx:xx:xx:xx  txqueuelen 0  (Ethernet)
        RX packets 660  bytes 36996 (36.9 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 263  bytes 26836 (26.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
Run Code Online (Sandbox Code Playgroud)
  1. 我在输出中没有看到任何奇怪的东西networkctl
alberto_perdomo@builder02:~$ networkctl
IDX LINK        TYPE     OPERATIONAL SETUP      
  1 lo          loopback carrier     unmanaged  
  2 enp67s0f0   ether    routable    configured 
  3 enp67s0f1   ether    no-carrier  configuring
  4 wlp70s0     wlan     no-carrier  unmanaged  
 60 docker0     bridge   routable    unmanaged
Run Code Online (Sandbox Code Playgroud)

除了 iface enp67s0f1“配置”(我认为这可能与我使用 netplan 配置网络的方式有关)。

  1. 内核路线看起来不错:
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         192.168.1.1     0.0.0.0         UG    0      0        0 enp67s0f0
172.17.0.0      0.0.0.0         255.255.255.0   U     0      0        0 enp67s0f0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 enp67s0f0
Run Code Online (Sandbox Code Playgroud)
  1. ip route看起来不错:
default via 192.168.1.1 dev enp67s0f0 proto static 
172.17.0.0/24 dev enp67s0f0 proto kernel scope link src 172.17.0.1 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
192.168.1.0/24 dev enp67s0f0 proto kernel scope link src 192.168.1.32
Run Code Online (Sandbox Code Playgroud)
  1. iptables我觉得还不错:
my_user@my_host:~$ sudo iptables --list --table nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        anywhere            

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere
Run Code Online (Sandbox Code Playgroud)
  1. 这些是我当前的 Docker 网络:
NETWORK ID     NAME      DRIVER    SCOPE
ba15db4d2831   bridge    bridge    local
938ad254f4d2   host      host      local
72ca52dfdedb   none      null      local
Run Code Online (Sandbox Code Playgroud)

最后,如果我在主机模式下运行容器(例如:) docker run -it --rm --net=host python:3.6.1 /bin/bash,DNS 解析将起作用。

它不可能像附加--net=host到我的 docker 命令那么简单,因为该服务器运行一些 CI/CD 管道,这些管道应该能够访问互联网、解析域名等等。

所以基本上,主要问题是如何修复网桥 docker0 以便在网络模式桥接时能够从我的容器访问互联网?

我已经尝试了几种方法,其中包括恢复 docker、重新安装 docker、删除 ifacedocker0并强制 docker 再次创建它。

任何有关如何解决或排除此问题的帮助、反馈或评论将不胜感激!

A.B*_*A.B 7

较窄的路线:

172.17.0.0/24 dev enp67s0f0 proto kernel scope link src 172.17.0.1 
Run Code Online (Sandbox Code Playgroud)

优先于路线:

172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
Run Code Online (Sandbox Code Playgroud)

因此,发送至 172.17.0.2 和 172.17.0.254 之间地址的 IP 数据包将通过enp67s0f0而不是进行路由docker0

例如,当容器odd_fermi尝试时ping 8.8.8.8,虽然它自己的传出数据包可能已被处理(除非主机将SRPFrp_filter设置为 1 ),但发送到主机的 192.168.1.32 地址(因为它们经过 SNAT 处理)的回复数据包随后将被 de-SNAT -按照Docker 设置的iptables规则进行编辑,返回 172.17.0.2。

但是这个新的目的地 172.17.0.2 是通过接口路由的,enp67s0f0而不是docker0丢失:容器无法通信。

立即修复是删除此地址:

ip address delete 172.17.0.1/24 dev enp67s0f0
Run Code Online (Sandbox Code Playgroud)

当然,完成此操作的配置也必须进行相应的修改。