从主机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_ADMIN
function。 某些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_ADMIN
function添加到容器,则可以类似地从容器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