Docker 容器网络命名空间不可见


本文将探讨 Docker 容器中网络命名空间文件的一个问题。我们将研究为什么网络命名空间文件对 ip netns ls 命令不可见。

在继续之前,让我们先简要概述一下 Docker、容器和网络命名空间。

容器化

容器化类似于虚拟化,其中应用程序及其所有依赖项和库都打包到一个容器中;它可以在任何计算环境中运行。当操作系统内核以及所有必要的库和依赖项都包含在容器中时,任何处理该应用程序的人员都可以仅使用该容器来处理它,而不是在虚拟机上设置适当的计算环境。容器没有客户机操作系统,并在主机上运行。因此,它们根据需要共享相关的库和资源。

由于特定于容器的二进制文件和库在主机内核上运行,因此应用程序的处理和执行速度非常快。

容器在几分之一秒内启动,并且容器比虚拟机更轻量级且速度更快。

Docker

Docker 是一个软件平台,可实现应用程序的快速开发、测试和部署。Docker 将软件组织成称为容器的标准化单元,其中包含软件运行所需的一切,例如库、系统工具、代码和运行时。Docker 允许您将应用程序快速部署和扩展到任何环境,同时确信您的代码将运行。

网络命名空间

Linux 网络命名空间是内核的一项功能,允许我们虚拟化和隔离网络环境。例如,使用网络命名空间,您可以创建独立的网络接口和路由表,这些接口和路由表与系统其余部分隔离。

Linux 中的命名空间分为六种类型:pid、net、uts、mnt、ipc 和 user。

示例

如果您运行命令“lsns”,它将显示系统中所有现有的命名空间,如下所示。

$ lsns

输出

 NS TYPE NPROCS PID USER COMMAND
4026531836 pid 2 7358 sachin -bash
4026531837 user 2 7358 sachin -bash
4026531838 uts 2 7358 sachin -bash
4026531839 ipc 2 7358 sachin -bash
4026531840 mnt 2 7358 sachin -bash
4026532185 net 2 7358 sachin -bash

不可见的 Docker 网络命名空间

当我们创建 Docker 容器时,守护进程将为容器进程生成命名空间伪文件。然后,这些文件将放置在 /proc/pid/ns 目录中,其中 pid 是容器的进程 ID。考虑以下场景

pi@TTP:sudo docker run --rm -d ubuntu:latest sleep infinity
c5503724a3ab4339e9246f0ef4cddf475e1f4f98964df834bfacaf5ff1
70fb03
pi@TTP:docker inspect --format '{{.State.Pid}}' c5503724a3ab
1946

查看 /proc/1946/ns 目录,我们可以看到所有不同类型的命名空间都已创建。

pi@TTP:sudo ls -la /proc/1946/ns
total 0
dr-x--x--x 2 root root 0 Oct 6 17:25 .
dr-xr-xr-x 9 root root 0 Oct 6 17:25 ..
lrwxrwxrwx 1 root root 0 Oct 6 17:28 ipc -> ipc:[4026532177]
lrwxrwxrwx 1 root root 0 Oct 6 17:25 mnt -> mnt:[4026532175]
lrwxrwxrwx 1 root root 0 Oct 6 17:25 net -> net:[4026532180]
lrwxrwxrwx 1 root root 0 Oct 6 17:28 pid -> pid:[4026532178]
lrwxrwxrwx 1 root root 0 Oct 6 17:28 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Oct 6 17:28 uts -> uts:[4026532176]

在命名空间伪文件列表中可以看到此进程的 net 文件的存在。我们可以预期在列出所有网络命名空间时 net 文件会出现,因为它对应于 Linux 网络命名空间。但是,很明显情况并非如此。例如,现在运行 ip netns ls 会产生 0 个结果。

pi@TTP:ip netns ls
pi@TTP:

缺少文件引用

我们必须了解 ip netns ls 命令在 /var/run/netns 目录中搜索网络命名空间文件。但是,在创建网络命名空间文件后,Docker 守护进程不会在 /var/run/netns 目录中创建对它的引用。因此,ip netns ls 无法解析网络命名空间文件。

pi@TTP:mkdir -p /var/run/netns
pi@TTP:touch /var/run/netns/c5503724a3ab

要绑定挂载 net 文件,请使用 mount -o bind 命令 -

pi@TTP:mount -o bind /proc/1946/ns/net
/var/run/netns/c5503724a3ab

再次运行相同的 ip netns ls 命令将按预期显示网络命名空间。

pi@TTP:ip netns ls
c5503724a3ab (id: 1)

在建立到网络命名空间文件的文件引用后,我们可以使用 ip netns exec 执行任何 ip 命令。例如,我们可以使用 ip addr list 命令检查网络命名空间中的接口 -

pi@TTP:ip netns exec c5503724a3ab ip addr list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu
1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:3/64 scope link
       valid_lft forever preferred_lft forever

结论

我们在本教程的开始简要概述了 Linux 命名空间、Docker 和容器。然后,我们演示了 docker run 创建的网络命名空间文件在运行 ip netns ls 时不会出现的问题。我们后来发现,这是因为在 /var/run/netns 中没有创建文件引用,而 ip netns ls 命令在该目录中查找任何网络命名空间。

最后,我们在文章中给出了一个简单的解决方法:将文件绑定挂载到 /var/run/netns,以便可以使用 ip netns ls 找到它。

更新于:2022年11月21日

576 次浏览

开启您的 职业生涯

通过完成课程获得认证

开始学习
广告