docker 网络之host模式底层实现

众所周知,docker有4种网络模式:桥接、host、容器、none,默认使用桥接。今天主要介绍一下host模式。

host模式,本质是容器与物理主机在网络空间是同一个namesapce。docker在创建容器后会在默认路径/var/run/docker/netns/ 生成一个文件,创建一个容器并且指定网络是为--net=host,具体如下可知:

docker 网络之host模式底层实现_第1张图片

我们通过上图可知,蓝色中实际为文件inode id,三者是完全相同的。其中进程1的net namespace代表就是物理主机net namespace,由此可知容器和物理主机是处在相同net namespace中

我们都知道,在linux下面创建一个文件,都会对应一个inode节点,每个文件对应的inode都是不一样的,那么docker是通过什么技术实现的呢是不同文件映射到同一个inode上呢?这里先公布答案:通过系统调用函数mount,具体流程图:

  

docker 网络之host模式底层实现_第2张图片

具体代码:docker/libnetwork/osl/namespace_linux.go

func reexecCreateNamespace() {
	if len(os.Args) < 2 {
		logrus.Fatal("no namespace path provided")
	}
	if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
		logrus.Fatal(err)
	}
}

func mountNetworkNamespace(basePath string, lnPath string) error {
	return syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, "")
}

其中basePath为当前进程下面ns/net,lnPath为/var/run/docker/ns/default(这个default文件要先创建出来),然后在执行系统调用mount,进行bind操作。通过上面一系列操作可知,最终是通过mount操作,将default文件mount到ns/net所指向的inode节点,也就是说将容器net namespace指向物理主机net namespace(即在相同namespace)。

总结:从这部分逻辑可知,我们最后还是调用系统调用,那么我们是不是也可以通过C语言方式实现这个功能呢?答案是肯定。

你可能感兴趣的:(Docker&K8S&虚拟化,docker网络模型,docker,host模式,mount函数)