我的计算机在端口 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 设置时,该 ID 都会发生变化:
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(甚至是自定义名称?)的解决方案。
答案1
在 vanilla UFW 中,这是不可能的,因为接口名称始终处于不可猜测的状态。为了设置这样的功能,应该创建一个手动定义的网络。简而言之,可以使用驱动程序选项在Docker 的bridge
Compose 配置中创建一个定制网络。这将看起来像:
networks:
my_bridge:
driver: bridge
driver_opts:
com.docker.network.bridge.name: my-bridge
从这里,可以将桥接配置添加到撰写文件中的每个服务中:
myimage:
image: myimage:1.0
ports:
- "2580:2580"
networks:
- my_bridge
然后,在下次启动 Compose 系统时,将使用正确的名称创建新的网络:
my-bridge Link encap:Ethernet HWaddr 11:22:33:44:55:66
inet addr:172.18.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:1122:3344:5566/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:11 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:788 (788.0 B) TX bytes:695 (695.0 B)
从那里开始,添加 UFW 规则以允许连接到端口 1234 很简单:
ufw allow in on my-bridge from any to any port 1234
突然间,一切都变得完美了!
答案2
为了整合接受的答案,您还可以使用 docker 命令在 docker-compose 之外创建网络:
sudo docker network create -d bridge -o com.docker.network.bridge.name=my-bridge my_bridge
之后你可以检查网络发出
ip link show
现在,您可以在撰写文件中重新路由默认网络,或者定义任何您喜欢的网络并将其重新映射到已经存在的网络
version: "3"
services:
test:
image: nginx:alpine
ports:
- "80:80"
networks:
default:
external:
name: my_bridge
答案3
为了进一步扩展接受的答案,当使用 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
网络
services:
my_service:
#...
networks:
- my_bridge
networks:
my_bridge:
driver: overlay
- 在主机上启用与网络的通信:
# Docker creates a docker_gwbridge network in swarm mode for interaction with the host
$ ufw allow in on docker_gwbridge from any \
to any port 12345 proto tcp
该服务似乎能够通过172.17.0.1
和向主机发送消息172.18.0.1