我有一个 Linux 进程,它创建一个网络命名空间,但没有在 /run/netns 中注册它。该进程也有自己的 PID 命名空间。网络命名空间没有名称,我只能看到命名空间的 id:
# ip netns list-id
nsid 0
nsid 1
是否可以为网络命名空间分配一个名称,以便我可以使用方便的 ip-netns 命令来显示和管理命名空间?
我找到一篇文章如何访问未命名的网络名称空间但它对我不起作用,因为我的进程有自己的 PID 命名空间,所以我在根命名空间中看不到该进程。
答案1
在命名空间的低级处理中不存在实际名称。这一切都是通过对每个命令执行的常见操作或期望来处理的ip路由2套房。
为现有的匿名网络名称空间分配名称实际上意味着:ip路由2工具相信他们在创建此网络命名空间时进行了常规设置。
那么真正在ip netns add foo
做什么呢?它取消与新的网络命名空间的共享,并且即使没有进程使用它,也要保持该命名空间存在,并安装它。在通常的 *nix 哲学中,命名空间有一个索引节点代表伪文件系统中伪文件的数字国家科学基金。几乎无法对文件执行任何操作(甚至不能读取它),但可以打开它以将其用作名称空间操作的令牌(例如setns(2)
),也可以作为绑定挂载进行挂载。
唉,链接 nsid 不能直接使用:这不是代表其他命名空间的全局值,而是一个当地的(本地唯一但可回收且不是全局唯一)代表一个的ID关联到另一个命名空间。多个值表示:链接到多个其他命名空间,两次相同值表示:两个链接到同一个其他命名空间。
如果你必须从此处开始查找其他命名空间,我邀请你检查我在其他问答中的回答我对此做了一个回答。还有一个方便的地图工具可用:plotnetcfg
它可以映射所有网络名称空间。虽然它确实知道ip路由2方法,它似乎没有单独给出进程 id,而是当它不是由ip路由2。编辑后的示例(需要jq
),运行为根:
# unshare -n -- sleep 999 &
[1] 677451
# plotnetcfg -f json | jq '.namespaces[].name'
""
[...]
"PID 268150 (systemd)"
"PID 345878 (systemd)"
[...]
"PID 677451 (sleep)"
这里""
代表初始命名空间,这两个systemd
来自两个LXC实例,sleep
运行的命令也找到了。
帮助解决两种常见情况:
对于 LXC:
lxc-info -H -p -n containername
对于码头工人:
docker inspect --format '{{.State.Pid}}' containername
一旦您通过任何可用的方法在预期的网络命名空间中找到了进程,您就可以模仿ip路由2工具。他们到底做什么可能取决于他们的确切版本。从strace
我看来,似乎是这样:
mkdir -p /run/netns
然后将其安装在自身之上,以便将其设置为共享传播:
mount --bind --make-shared /run/netns /run/netns
上述操作仅在尚未完成且仅执行一次的情况下执行。要让工具为您执行此操作(并且仅在需要时),只需创建和删除虚拟名称空间:
ip netns add dummy && ip netns delete dummy
现在选择一个名称,例如foo
,创建一个空文件并将其模式更改为 000(这不是必需的,但模仿ip路由2):
touch /run/netns/foo
chmod 0 /run/netns/foo
最后根据给定的 PID 挂载进程的命名空间(例如sleep
之前的:677451):
mount --bind /proc/677451/ns/net /run/netns/foo
就是这样。即使sleep
命令结束,命名空间现在也将继续存在。全部ip路由2工具现在将命名它富。例如,如果有一个韦斯连接到它的接口,ip link
会将链接 nsid 的编号替换为foo
.
如果您想删除此网络命名空间,ip netns del foo
现在就执行此操作(注意:像往常一样,一旦没有资源再使用它,实际的网络命名空间就会真正消失,就像这个 sleep 命令)。
进一步的文档ip路由2沿网络命名空间的特定附加功能我的另一个答案。