为何仅将容器加入traefik_default网络时Traefik才能正常工作?
我最近接手了一台Docker主机,它被用作公开HTTPS入口的反向代理,目的是让多个不同的Web应用能共享同一个HTTPS入口地址。目前的路由规则是这样的:
https://foo.example.org/app1/代理到http://172.18.0.2:3010https://foo.example.org/app2/代理到http://172.18.0.3:4711
负责代理的Traefik是作为容器部署的,它所在的网络是traefik_default,对应的子网是172.18.0.0/16。而Docker的默认网络子网是172.17.0.0/16,主机上的路由表信息如下:
[...]@[...]:~$ route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default _gateway 0.0.0.0 UG 0 0 0 eth0 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-xxxxxxxxx
我发现一个问题:只有把后端Web应用的容器加入到traefik_default网络里,Traefik才能正常完成代理,否则就无法访问后端服务。这背后的原因其实和Docker的网络隔离机制有关:
Docker网络默认是隔离的:Docker的每个自定义网络(比如
traefik_default)和默认网络都是独立的网络空间,它们之间没有自动的通信权限。Docker会为每个自定义网络创建单独的网桥设备(比如上面路由表里的br-xxxxxxxxx),默认网络则对应docker0网桥,这些网桥之间默认没有配置转发规则,所以跨网络的容器无法直接互相访问。Traefik只能访问同网络的容器:Traefik容器处于
traefik_default网络(172.18.0.0/16),如果后端容器在默认的172.17.0.0/16网络里,Traefik所在的网络空间无法直接路由到默认网络的容器IP,自然就没法完成代理请求的转发。而当把后端容器加入traefik_default网络后,它们就进入了同一个网络空间,Traefik可以直接通过容器的IP或者服务名访问到后端应用,代理也就正常工作了。
如果不想把所有后端容器都加到traefik_default网络,也有其他解决方案:比如为Traefik容器添加多个网络(同时连接默认网络和traefik_default),或者手动配置Docker网络之间的连接,但最简洁可靠的方式还是让后端容器和Traefik处于同一个网络,这也是Docker网络设计的常规用法。
备注:内容来源于stack exchange,提问作者Thorsten Schöning

