我尝试完成以下事情: 从 服务 B 我想致电 服务 A
工作:
不起作用(curl没有反馈,没有错误):
所以我确实尝试对此进行调试,但是curl和traefik不显示日志,这就是问题所在。 CURL 刚刚挂起。
sub.example.org 的 nslookup => ok
sub.example.org 的 ping => ok
sub.example.org 的curl => 挂起而不输出:连接到ip
鉴于 DNS 和
ping
正常工作,这很可能是防火墙问题。 DNS 可能不会解析为 docker 分配的容器的私有 ip,而是解析为主机 ip。防火墙必须允许从 docker 桥接网络到端口 443 上的主机 IP 的流量。但是在映射容器端口 (443:443
) 时,docker 只会将防火墙配置为允许从外部桥接网络到私有容器 ip 的流量 在桥接网络中 - 这不足以支持所需的用例。那么,让我们再次了解防火墙并修复它! :)
允许从
Service B
ip/network 到主机 ip 的 https 流量,例如使用 ufw
:
sudo ufw allow from <service-B-ip or traefik-subnet> to <host-ip> port 443
您可以使用
docker network inspect <network-name> | grep Subnet
找到 docker 桥接网络的子网,例如172.18.0.0/16
。假设主机 IP 为 10.0.0.4
,这将允许桥接网络上的所有服务与 443 (traefik) 进行通信:
sudo ufw allow from 172.18.0.0/16 to 10.0.0.4 port 443
另请确保已启用
ufw
:sudo ufw enable
。
防火墙测试请求的去向(网络接口、目标 IP、端口)以及请求来自何处(网络接口、IP)以及其他一些内容。因此,让我们检查一下需要哪些规则来允许用例中所需的流量,然后检查防火墙是否进行了相应配置。
运行
docker network ls
,您将找到一个 bridge 类型的网络,其中包含您的网络的一些 id,例如cd0af4596aee
。你还可以检查ifconfig
,会发现这个网络接口是在你创建网络后由docker创建的(br-cd0af4596aee
)。
将容器的端口映射到主机端口时(例如 traefik 的
443:443
),docker 设置一些防火墙规则。 Docker 通过在基于 Linux 的系统上操作 iptables
来实现这一点,让我们看看 docker 做了什么:
$ sudo iptables -L -v -n | grep 443
pkts bytes target prot opt in out source destination
13 780 ACCEPT tcp -- !br-cd0af4596aee br-cd0af4596aee 0.0.0.0/0 172.18.0.4 tcp dpt:443
该规则允许任何源,但只能通过不是网络桥接接口 (
!br-cd0af4596aee
) 的接口,并且只能访问私有 IP 172.18.0.4
。但是我们想要允许的流量源自网络br-cd0af4596aee
,并以 DNS 解析的主机 ip 为目标(这可能不是 docker 分配的容器的私有 ip)。
理解了这一点,您现在可能了解解决方案是什么样的:我们需要允许从网络本身到主机 IP 的流量。因为处理网络接口很麻烦,我们还可以添加一条规则,只允许所有
in
和 out
接口,但仅允许特定的 ip/网络。为此,我们可以使用 ufw
,它在大多数 ubuntu 发行版上都可用。 ufw
是 iptables
的前端,比 iptables
更容易使用。请注意,iptables 中的 docker 规则先于 ufw
规则存在 - 有效地使 docker 绕过尝试阻止特定流量的 ufw 规则。 请参阅此处了解更多信息。
假设
172.18.0.0/16
是网络的IP范围,10.0.0.4
是主机IP:
# sudo ufw allow from <service-B-ip or network-of-the-service> to <host-ip> port 443
sudo ufw allow from 172.18.0.0/16 to 10.0.0.4 port 443
再次检查
iptables
:
$ sudo iptables -L -v -n | grep 443
13 780 ACCEPT tcp -- !br-cd0af4596aee br-cd0af4596aee 0.0.0.0/0 172.18.0.4 tcp dpt:443
1 60 ACCEPT tcp -- * * 172.18.0.0/16 0.0.0.0/0 tcp dpt:443
0 0 ACCEPT udp -- * * 172.18.0.0/16 0.0.0.0/0 udp dpt:443
这应该可以解决问题。
DNS:默认情况下,容器可以访问互联网(即防火墙允许容器与外部主机通信),因此 DNS 解析工作正常。 DNS 只是一个请求,说 “该域的 ip 是什么?”.
ping:Ping 使用互联网控制消息协议 (ICMP)。让我们检查一下
iptables
:
$ iptables -L -v -n | grep icmp
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 3
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 11
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 12
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 3
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 11
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 12
3 252 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmptype 8
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
防火墙配置为允许 icmp(AFAIK 在启用时由
ufw
完成;如果 ufw
被禁用,REJECT
规则也将被删除)。