总结 当处于网络模式桥接时,如何修复桥接 docker0 以便能够从我的容器访问互联网?
几周前发生了一次停电,显然破坏了服务器网络配置,一段时间以来,DHCP 服务器没有为机器分配正确的 IP。我设法通过使用配置网络解决了这个问题netplan
(我不能保证在停电之前就完成了,它由另一个团队管理)。
然而,docker
当网络模式为 时,容器无法访问互联网bridge
。
从主机上,我可以ping google.com
,DNS解析工作正常。其他一切似乎也都正常。但是,当我启动容器(例如:)时,它docker run -it --rm python:3.6.1 /bin/bash
不再ping
起作用。
以下是我检查过的几件事:
ping
容器内不起作用:
ping google.com
只是挂起:
root@85deb9b2ae95:/# ping google.com
^C
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
/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
(和楼主的一样)
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": {}
}
]
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
- 我在输出中没有看到任何奇怪的东西
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
除了 iface enp67s0f1
“配置”(我认为这可能与我使用 netplan 配置网络的方式有关)。
- 内核路由看上去不错:
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
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
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
- 这些是我当前的 docker 网络:
NETWORK ID NAME DRIVER SCOPE
ba15db4d2831 bridge bridge local
938ad254f4d2 host host local
72ca52dfdedb none null local
最后,如果我以主机模式运行容器(例如:)docker run -it --rm --net=host python:3.6.1 /bin/bash
,DNS解析就可以起作用。
它不能像附加--net=host
到我的 docker 命令那样简单,因为该服务器运行一些 CI/CD 管道,这些管道应该能够访问互联网、解析域名等等。
所以基本上,主要问题是当处于网络模式桥接时,如何修复桥接 docker0 以便能够从我的容器访问互联网?
我尝试了几件事,其中包括恢复 docker、重新安装 docker、删除docker0
iface 并强制 docker 再次创建它。
如能得到关于如何解决或排除此故障的任何帮助、反馈或评论,我们将不胜感激!
答案1
较窄的路线:
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
因此,发往 172.17.0.2 和 172.17.0.254 之间的地址的 IP 数据包将通过enp67s0f0
而不是进行路由docker0
。
例如当容器奇怪的费米尝试ping 8.8.8.8
,而其自己的传出数据包可能被处理(除非主机设置rp_filter
为 1安全防御框架协议) 回复数据包返回到主机 192.168.1.32 地址(因为它们经过了 SNAT),然后被iptablesDocker 按照预期设置了规则,以返回 172.17.0.2。
但是这个新的目的地 172.17.0.2 是通过接口enp67s0f0
而不是路由的docker0
,并且丢失了:容器无法通信。
立即修复是删除此地址:
ip address delete 172.17.0.1/24 dev enp67s0f0
当然,完成此操作后的配置也必须进行相应的修改。