场景是这样的:
在Linux机器中的容器内运行应用程序。该应用程序内部运行多个服务,每个服务都有自己的端口号。端口号非常随机。
现在我想在Mac笔记本电脑上访问此应用程序。这台Mac笔记本电脑可以ping Linux机器ip。
我目前正在做的一种方法是将所有端口从docker容器映射到Linux机器,然后我就可以使用Linux机器IP从Mac进行访问。
但是这种方法不能随着更多服务的加入而扩展。我想知道是否有人遇到过同样的问题并且有更好的方法来解决这个问题?我们不在这些Linux机器上运行Kubernetes,因为它们不是服务器。这些机器用于个人发展。
谢谢!
答案 0 :(得分:1)
Docker没有在容器创建后映射端口的功能,也没有修改现有端口映射的功能。
通常的解决方案是将应用程序配置为使用设置端口或端口范围。如果那是不可能的,那么有几个选项可以解决这个问题。
使用docker run --network=host
。容器共享主机网络堆栈,因此可在主机IP上使用。请注意,这会使容器访问主机网络,因此可能会干扰主机服务或将更多主机暴露给容器,而不是正常情况。
为容器创建用户定义的网络,并为其分配网络可以路由到Docker主机的IP范围。然后可以直接寻址在容器中侦听端口的服务。
docker network create \
--subnet=10.1.3.0/24 \
-o com.docker.network.bridge.enable_ip_masquerade=false \
routable
新的docker网络的路由需要添加到您的网络网关,以便他们可以通过您的Docker主机路由流量。在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
Docker有一个macvlan network driver,允许您将主机接口映射到容器,有点像VM中的桥接接口。然后,容器可以在与主机相同的网络上具有接口。
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
请注意,您无法通过此网桥与docker主机IP地址进行通信。您可以将macvlan子接口添加到主机并将主机IP地址移动到其上以允许流量。
一些虚拟机和虚拟网络对于获取有关生成数据的其他MAC地址非常挑剔。例如,AWS EC2将拒绝容器流量。
iptables
可以在容器命名空间中创建iptables NAT规则。要在容器内执行此操作,容器需要NET_ADMIN
功能。某种形式的脚本可以在应用程序端口启动后查找它们,并使用DNAT
规则将流量从静态外部映射端口转发到动态应用程序端口。
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
如果您不想将iptables
功能添加到容器,则可以类似地从docker主机为容器网络命名空间添加NET_ADMIN
规则。 The host needs a little help to use container name spaces
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