从主机ip访问具有随机端口的docker容器

情景是这样的:

有一个应用程序在Linux机器的容器中运行。 这个应用程序有几个服务在里面运行,每个服务都有自己的端口号。 端口号是相当随机的。

现在我想在Mac笔记本电脑上访问这个应用程序。 这台Mac笔记本电脑能够ping Linux机器ip。

目前我正在做的一个方法是将所有端口从Docker容器映射到Linux机器,然后我可以使用Linux机器IP从Mac进行访问。

但是这种方法不能随着更多的服务join进行扩展。 我想知道是否有人遇到同样的问题,并有更好的方法来处理这个问题? 我们不在这些Linux机器上运行Kubernetes,因为它们不是服务器。 这些机器是为了个人发展。

谢谢!

Docker不具备在创build容器后映射端口或修改现有端口映射的function。

通常的解决scheme是将您的应用程序configuration为使用设置的端口或端口范围。 如果这是不可能的,那么有几个select来解决这个问题。

主机networking

使用docker run --network=host 。 容器共享主机networking堆栈,以便在主机IP上可用。 请注意,因为这给了容器对主机networking的访问权限,所以可能会干扰主机服务,或者将主机的更多主机暴露给容器。

可路由,用户定义的networking。

为您的容器创build一个用户定义的networking,并为其分配一个networking可以路由到Docker主机的IP范围。 在容器中监听端口的服务可以直接寻址。

 docker network create \ --subnet=10.1.3.0/24 \ -o com.docker.network.bridge.enable_ip_masquerade=false \ routable 

新dockernetworking的路由将需要添加到您的网关,以便他们可以通过您的Docker主机路由stream量。 在Linux上这将是这样的:

 ip route add 10.1.3.0/24 via $DOCKER_HOST_IP 

那么你应该可以正常的传输数据

 docker run --net=routable --rm -it alpine ping $DOCKER_HOST_GATEWAY_IP 

Macvlan桥梁

Docker有一个macvlannetworking驱动程序 ,允许你将一个主机接口映射到一个容器,就像虚拟机中的一个桥接接口。 然后,容器可以在与主机相同的networking上有一个接口。

 docker network create -d macvlan \ --subnet=10.1.2.0/24 \ -o macvlan_mode=bridge \ -o parent=enp3s0 macvlan docker run --net=macvlan --ip=10.1.2.128 --rm -it alpine ping 10.1.2.1 

请注意,您无法通过此网桥与泊坞窗主机IP地址进行通信。 您可以将MACvlan子接口添加到主机,并将主机IP地址移动到主机上以允许通信。

一些虚拟机和虚拟networking有一些额外的MAC地址,他们不知道如何生成数据。 例如,AWS EC2将拒绝容器stream量。

容器iptables

可以在容器命名空间中创buildiptables NAT规则。 为了在一个容器内完成这个工作,容器需要NET_ADMINfunction。 某些forms的脚本可以在启动后查找应用程序端口,并使用DNAT规则将stream量从静态外部映射端口转发到dynamic应用程序端口。

 docker run -p 5000:5000 --cap-add=NET_ADMIN debian:9 # port=$(ss -lntpH | awk '/"app-bin"/ { split($4,a,":"); print a[length(a)]; exit}') # iptables -t nat -A -p tcp -m tcp --dport 5000 -j DNAT --to-destination 127.0.0.1:$port 

如果您不想将NET_ADMINfunction添加到容器,则可以类似地从容器networking名称空间的泊坞窗主机中添加iptables规则。 主机需要一点帮助来使用容器名称空间

 pid=$(docker inspect -f '{{.State.Pid}}' ${container_id}) mkdir -p /var/run/netns/ ln -sfT /proc/$pid/ns/net /var/run/netns/$container_id ip netns exec "${container_id}" iptables -t nat -vnL