每个容器在 network namespace 隔离下有单独的协议栈,没有网络接口(eth0)以及没有 veth 连接到 docker0 网桥上:
+-----------------------------------+--------------------------+
| Host | Container 1 |
| | |
| +----------------------------+ | +----------------------+ |
| | Network Protocol Stack | | |Network Protocol Stack| |
| +----------------------------+ | +----------------------+ |
| ↑ ↑ | ↑ |
|.......|...........|...............|.............|............|
| ↓ ↓ | ↓ |
| +------+ +----------+ | +-------+ |
| |.2.112| |172.17.0.1| | | 127 | |
| +------+ +----------+ | +-------+ |
| | eth0 | | docker0 | | | lo | |
| +------+ +----------+ | +-------+ |
| ↑ | |
| | | |
| | | |
+-------|---------------------------+--------------------------+
↓
Physical Network (192.168.2.0/24)
用途:
- 用户自定义配置网络接口、路由之类的
- 运行不依赖网络的进程,例如编译、压测之类的
host 网络和 k8S 的 hostNetwork
理解为网络不单独的 network namespace 而是和宿主机一样的网络即可,它的其他 namespace 还是隔离的例如 mount、pid。
它的应用场景:
- 端口很多应用,或者被动增加端口监听数量的,例如 ftp,直接 host 网络简单粗暴
- 有些应用例如 kafka 在桥接下,会检测到自己监听的信息 (172.17.0.2:9092)和别人进来的应用层层面的信息(例如 192.168.2.112:9092)对不上而有问题,有两种方式解决方式:
- 1. 应用层配置对外宣告链接自己的信息,例如 kafka 配置
KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.2.112:9092
- 2. host 网络粗暴解决,比如桥接就慢的情况下,host 网络就没问题
要注意的一个点是 Docker 的 init 层的一些文件:
- /etc/hostname
- /etc/hosts
- /etc/resolv.conf
默认参数下,不使用额外参数,host 网络的容器启动时候,这三个的单独文件都会从宿主机的内容拷贝生成的:
$ docker inspect t2 | grep -Pi '(hosts|hostname|resolv).*path'
"ResolvConfPath": "/var/lib/docker/containers/30d40445175c3c9e83ba7d7b387eb2e9be7fb3f8a3b37822807c6ff818335536/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/30d40445175c3c9e83ba7d7b387eb2e9be7fb3f8a3b37822807c6ff818335536/hostname",
"HostsPath": "/var/lib/docker/containers/30d40445175c3c9e83ba7d7b387eb2e9be7fb3f8a3b37822807c6ff818335536/hosts",
加参数可以让和宿主机的不一样,例如 --add-host
,还有个问题是因为 init 层是单独的文件,存在两种情况:
- 修改容器内这些文件内容后,容器 restart 后,会回到之前的宿主机一样的配置
- 宿主机修改了自己的文件后,容器内不会同步,需要重启下该容器
host 网络下,java 相关的要注意,java 有些库启动会解析自己的 hostname,无法解析会无法启动,例如 zookeeper,之前也遇到过 springboot 的一个项目在 /etc/hosts
里没有 hostname 的解析记录启动要 15 分钟,加了 hostname 的解析后 3 分钟就启动了。