如何配置 Docker 以使用我的 ens34 网络接口(而不是 eth0)?

How do I configure Docker to work with my ens34 network interface (instead of eth0)?

有谁知道 docker 是如何决定哪个 NIC 可以与 docker0 网络一起工作的?我有一个有两个接口(eth0 和 ens34)的节点,但是,只有通过 eth0 的请求被转发到容器。

配置好我的 VM 并安装 Docker 后,我开始了一个非常愚蠢的测试:我创建了一个 centos 虚拟机,在上面安装了 netcat 并提交了映像。然后我启动了一个监听端口 8080 的守护进程容器。我使用:

docker -it -p 8080:8080 --name nc-server nc-server nc -vv -l 8080

所以我尝试从同一网络中的另一个节点连接到侦听端口 8080 的容器(与接口 ens34 的 IP 地址相同)。没用。

而当我从另一台机器向 eth0 的 IP 地址发送请求时,我看到容器中有一些反应(通信正常)。我是 "tailing" 它的输出:

docker logs -ft nc-server

我对这个实验的结论:eth0(主网卡)和docker0之间存在某种神秘的关系,发送到ens34(10.)接口的请求永远不会被转发到 veth / docker0 接口,只有通过 eth0 (9.*) 的请求。这是为什么?

此外,我知道如果我使用 --net=host 我可以让一切正常工作,但我不想使用它......不知何故感觉不对,这是使用的标准做法吗Docker 容器中的 HOST 模式?有什么注意事项吗?

--

更新: 我在禁用 iptables 后设法让它工作:

service iptables stop

但是,我还是不明白发生了什么。以下信息应该与了解正在发生的事情相关:

ifconfig

[root@mydockervm2 myuser]# ifconfig | grep -A 1 flags
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
--
ens34: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.1.21.18  netmask 255.255.255.0  broadcast 10.1.21.255
--
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 9.32.145.99  netmask 255.255.255.0  broadcast 9.32.148.255
--
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
--
veth8dbab2f: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::3815:67ff:fe9b:88e9  prefixlen 64  scopeid 0x20<link>
--
virbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255

网络统计

[root@mydockervm2 myuser]# netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         9.32.145.1      0.0.0.0         UG        0 0          0 eth0
9.32.145.0      0.0.0.0         255.255.255.0   U         0 0          0 eth0
10.1.21.0       0.0.0.0         255.255.255.0   U         0 0          0 ens34
169.254.0.0     0.0.0.0         255.255.0.0     U         0 0          0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U         0 0          0 ens34
172.17.0.0      0.0.0.0         255.255.0.0     U         0 0          0 docker0
192.168.122.0   0.0.0.0         255.255.255.0   U         0 0          0 virbr0

过滤器

[root@mydockervm2 myuser]# iptables -t filter -vS
-P INPUT ACCEPT -c 169 106311
-P FORWARD ACCEPT -c 0 0
-P OUTPUT ACCEPT -c 110 13426
-N DOCKER
-N DOCKER-ISOLATION
-A FORWARD -c 0 0 -j DOCKER-ISOLATION
-A FORWARD -o docker0 -c 0 0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -c 0 0 -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -c 0 0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -c 0 0 -j ACCEPT
-A FORWARD -m physdev --physdev-is-bridged -c 0 0 -j ACCEPT
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -c 0 0 -j ACCEPT
-A DOCKER-ISOLATION -c 0 0 -j RETURN

nat

[root@mydockervm2 myuser]# iptables -t nat -vS
-P PREROUTING ACCEPT -c 28 4818
-P INPUT ACCEPT -c 28 4818
-P OUTPUT ACCEPT -c 8 572
-P POSTROUTING ACCEPT -c 8 572
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -c 2 98 -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -c 0 0 -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -c 0 0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8080 -c 0 0 -j MASQUERADE
-A DOCKER -i docker0 -c 0 0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -c 0 0 -j DNAT --to-destination 172.17.0.2:8080

想法?

首先,排除显而易见的问题并确保其他网络上的主机知道如何路由到您的机器以到达容器网络。为此,检查

netstat -nr

在源主机上并确保你的 docker 子网以你的 docker 主机作为网关列出,或者处理上游流量的默认路由器知道你的主机。

如果流量正在路由但被阻止,那么您将进入转发状态 iptables。对于转发,以下应显示 1:

cat /proc/sys/net/ipv4/ip_forward

确保您的本地主机使用相同的 netstat 命令显示通往容器网络的网桥路由,docker0 接口和您的 docker 子网应该有一行作为目的地:

netstat -nr

对于iptables,检查是否有接口特定的nat或过滤规则需要调整:

iptables -t filter -vS
iptables -t nat -vS

如果您的转发规则默认为 DROP 而不是 ACCEPT,您可能需要添加一些日志记录,或者如果您认为流量是可信的(例如主机位于另一个防火墙后面),则只需将默认设置更改为接受流量。 =16=]

综上所述,直接在主机上公布端口是容器的一种相当普遍的做法。对于私有的东西,您可以在其内部网络上设置多个容器,这些容器可以相互通信,但不能与其他容器通信,并且您只在主机上公开真正向世界其他地方开放的端口 -p 标记到 运行(或 docker-compose 中的端口选项)。