外部主机无法访问宿主机内容器是怎么回事
TL;DR
是因为创建的容器采用的网络类型是 bridge,而宿主机没有启用 ip 转发,所以,外部主机请求没有转发到对应容器。需要两个步骤启用 ip 转发功能。(来自 Docker 官方文档 )
- 配置 Linux 内核允许 ip 转发。
$ sysctl net.ipv4.conf.all.forwarding=1
- 将 iptables FORWARD 规则从 DROP 改为 ACCEPT。
$ sudo iptables -P FORWARD ACCEPT
短话长说
背景
因为测试需要,在一台 centos 7 服务器上用 Docker 部署了一个 nginx 服务。部署好之后,在宿主机上使用 curl 命令可以访问 nginx 服务,但是外部机访问却提示 HTTP ERROR 503,服务不可用。查看了容器中 nginx 的 access 日志,发现也没有访问日志,双方都表示不是自己的责任。那就看看是不是中间商(宿主机)的责任吧。
排查问题
首先想到的是宿主机的防火墙可能没有开放端口,把请求给拦掉了。不过,使用 systemctl status firewalld
查看防火墙并没有开启。那就看看是不是 Docker 自身的网络配置的问题。
首先使用 docker inspect docker-name
查看容器的网络配置信息:
"Networks": {
"root_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"survey-nginx",
"dd6d4af0b1f0"
],
"NetworkID": "9781d8e96e344e662a0397a7b25f82ef6bce7e650b035b46404557438af0b5fb",
"EndpointID": "e62f1ce9da0fb9c0668986cfab01c1edc825f1c95cdfa042a6d5becb005cd15e",
"Gateway": "172.19.0.1",
"IPAddress": "172.19.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:13:00:02"
}
}
可以看到使用的网络类型是 root_default,一个自定义的网络类型,继续使用命令 docker network ls
查看该网络具体的网络类型:
NETWORK ID NAME DRIVER SCOPE
5934ab852fe2 bridge bridge local
057efb45b2a8 host host local
8bb8b2aa1a26 kind bridge local
a99c8640a808 none null local
9781d8e96e34 root_default bridge local
如上所示,自定义网络类型 root_defualt 是网桥,那么网桥为什么会导致数据没有转发呢?我的 Docker 知识比较匮乏,不过可以到官方文档看看有没有相应的描述。(文档传送)
在文档中,看到了这么一段内容:
In terms of Docker, a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network. The Docker bridge driver automatically installs rules in the host machine so that containers on different bridge networks cannot communicate directly with each other.
Bridge networks apply to containers running on the same Docker daemon host. For communication among containers running on different Docker daemon hosts, you can either manage routing at the OS level, or you can use an overlay network.
从文档中,我们可以了解到,Docker 的网桥是软件网桥,它只允许使用了同一个网桥的容器之间互相通信,Docker 会自动在宿主机上创建转发规则,避免不同网桥上的容器相互直接通信。不过,如果是不同宿主机上的容器,需要在系统层面增加路由,或者将网络类型改为 overlay。似乎已经破案了,虽然文档中说的是不同主机间容器的通信,不同主机和当前宿主机的容器间的通信可能也是因为现在这台主机上可能没有开启系统层面的路由。
文档继续往下看,我们找到了开启系统方法,即本文开始的两条命令:
$ sysctl net.ipv4.conf.all.forwarding=1
$ sudo iptables -P FORWARD ACCEPT
因为,宿主机没有开启防火墙,所以只执行了第一条命令,然后通过浏览器访问服务,访问成功。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?