身处Docker容器化应用之中获取宿主机IP属于常见操作,然而极易有所差错,众多开发者于搭建微服务之际会碰到该问题,在容器与宿主机需通信的场景里同样会碰上此问题,精准理解Docker网络模型,熟练掌握可靠的IP获取方式,能够切实防止服务连接失败,防止配置出现错误。
为什么容器需要获取宿主机IP
容器内应用若要访问宿主机上运行的服务,如数据库、API接口、监控代理,就必须获取宿主机真实IP,在开发测试环境中,我常看到同事直接使用localhost或127.0.0.1导致连接失败,这是因为容器有自己独立网络命名空间docker 获取宿主机ip,容器内localhost指向自身而非宿主机。

还有一个典型场景,容器应用需要向注册中心上报可被访问的地址。在微服务架构中,服务实例要将外部可访问的IP和端口注册到服务发现组件。若错误上报容器内部IP,会导致服务间调用失败。这种网络连通性问题在项目初始时常被忽视,直到集成测试阶段才会显现。
如何通过环境变量传递宿主机IP
在启动容器的时候,通过环境变量传递宿主机IP,这是最为简单可靠的方式,使用docker run命令的-e参数能够设置环境变量,例如docker run -e HOST_IP=$(hostname -i) myapp,这样一来,容器内应用便能够经由读取HOST_IP环境变量,从而获取宿主机地址。

于Docker Compose之中,可在配置文件内定义环境变量,于services部分添加environment字段,借助extra_hosts或者径直设置变量值,此方式颇为适合在开发环境运用,因IP地址这般相对固定,然而在生产环境里,倘若宿主机IP有变动的可能性,那就得结合动态发现机制了。
使用host网络模式获取IP
要将IP获取问题予以简化,能够让容器去使用宿主机的网络命名空间,于docker run命令里增添--network=host参数,或者在Docker Compose中把network_mode设置成”host”,在这样的模式之下,由于容器直接运用宿主机网络,因此localhost所指向的就是宿主机。

采用这种方法,会导致出现安全隐患,容器失去了网络隔离性,而且一旦多个容器应用都绑定相同端口,就会引发冲突,在生产环境中,如果不具备特殊性能要求或者不运行网络监控类应用,那么我通常不提倡使用host模式。
通过网关地址获取宿主机IP
容器的内部,作为默认路由的网关,一般来讲,就是宿主机在容器网络当中的IP 。去执行ip route show default这个命令linux系统界面,能够对默认路由进行查看,其中gateway字段所拥有的值,就是宿主机的IP 。这样的一种方法,在bridge网络模式的情况之下,是特别有用的。
在Linux系统之中,能够凭借awk快速获取网关地址,方法为ip route | awk ‘/default/ {print $3}’ ,这条命令于基于Alpine的镜像内同样能够正常运行 ,不过不得不注意,但如果容器采用了自定义网络,网关地址可能不是宿主机IP 。

从容器内部访问特殊域名
就 Docker 来讲,它呢提供了特殊域名 host.docker.internal,这个特殊域名是用来指向宿主机的,在容器当中,直接去 ping host.docker.internal,就能够获取到宿主机 IP,这样特性在 Docker for Windows 以及 Docker for Mac 里面是默认给予支持的。
当处于Linux环境时,在启动容器这个行为发生的时候,需要添加--add-host=host.docker.internal:host-gateway这个参数,才能够启用此功能,这种方法跟解析网关地址比起来更加直观,不过要留意版本兼容性,旧版Docker可能不支持。
编程语言中如何获取宿主机IP

存在着回应获取网络信息需求的相应系统调用,还有库函数,为此是不同编程语言提供的,于Go语言当中,通过依赖net.LookupHost(“host.docker.internal”)能够达成域名解析,在Python里面linux下载,可以凭借socket.gethostbyname(“host.docker.internal”)来得到IP。
倘若采用环境变量方式,在所有语言当中,均可借助读取系统环境变量来获取IP,比如在Node.js里,运用process.env.HOST_IP,在Java之中,使用System.getenv(“HOST_IP”),这种方法的优点是,代码与Docker相互解耦docker 获取宿主机ip,有利于单元测试。
在实际的项目当中,你有没有碰到过容器网络连通性这方面的问题呢,欢迎在这个评论区域去分享你的经历以及对应的解决方案,要是感觉这篇文章是有作用,有价值的话,请去点赞并且分享给更多的从事开发工作的人 。
