我的计算机在端口 1234 上托管了一个应用程序,除了我的机器之外,任何东西都不能访问该应用程序。但是,我的 Docker 容器(运行 Apache)应该能够访问它。同样,我的 Docker 容器在各种端口上托管了许多资源,这些资源同样只能从我的计算机访问。现在,由于我的系统为该特定网络使用了网桥,这使情况变得更加复杂:
NETWORK ID NAME DRIVER SCOPE
4d4b5e752963 bridge bridge local
c387eb42698a project_default bridge local
6818c0eb94bf host host local
f7e4ed6c05a2 none null local
这个桥(很烦人)总是有一个随机生成的 ID,每次我重新启动我的 Docker Compose 设置时都会改变:
br-c387eb42698a Link encap:Ethernet HWaddr 02:42:29:95:fd:2c
inet addr:172.18.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:29ff:fe95:fd2c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:405753 errors:0 dropped:0 overruns:0 frame:0
TX packets:530699 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:85147217 (85.1 MB) TX bytes:75260996 (75.2 MB)
简而言之,我需要以下内容:
- 任何主机
br-c387eb42698a
(或任何网络名称)都可以访问我本地机器上的端口 1234(方便的是 172.18.0.1) - 我的机器能够访问该子网上任何主机上的任何端口。(默认)
- 世界永远无法从子网或端口 1234访问任何端口。
理想情况下,这里的解决方案将以与 IP 无关的方式工作,这样它不依赖于子网上的网桥172.18.0.0/24
,如果我连接到恰好包含172.18.0.0/24
子网的网络,它也不会中断或允许数据泄漏。
我能想到的最简单的事情是使用接口名称并围绕它设置 UFW 规则,但我不能真正做到这一点,因为我的接口在不断变化。
我怎样才能做到这一点?虽然我更喜欢纯粹ufw
(或iptables
如果有必要)这样做,但我愿意接受需要配置 Docker 以始终为桥接接口分配持久 ID(甚至自定义名称?)的解决方案。
这在普通 UFW 中是不可能的,因为接口名称处于不可猜测的恒定状态。为了设置这样的东西,应该创建一个手动定义的网络。简而言之,可以在 compose config 中使用Docker 的驱动程序选项
bridge
来创建自定义网络。这看起来像:从这里,桥接配置可以添加到撰写文件中的每个服务:
然后,下次启动 Compose 系统时,将使用正确的名称创建新网络:
从那里,添加 UFW 规则以允许连接到端口 1234 是微不足道的:
突然间,一切都很完美!
要集成接受的答案,您还可以使用 docker 命令在 docker-compose 之外创建网络:
之后,您可以检查发布的网络
现在,在您的撰写文件中,您可以重新路由默认网络或定义您喜欢的任何网络,将其重新映射到已经存在的网络
为了进一步扩展接受的答案,当使用 Docker Swarm 并部署堆栈时,
bridge
网络是无效的网络类型。您可能会遇到类似于以下内容的错误:
failed to create service [service_name]: Error response from daemon: The network [network_name] cannot be used with services. Only networks scoped to the swarm can be used, such as those created with the overlay driver.
要允许容器与 swarm 集群中的主机通信:
overlay
网络该服务似乎能够通过
172.17.0.1
和172.18.0.1