解决方案

解决方案

我有一个在网络命名空间中运行的应用程序。这效果很好。

我想在不同的命名空间中多次运行该应用程序。为了方便起见,我想将应用程序的工作目录绑定到命名空间内的 /tmp/nsX 之类的目录。

如果我只是mount --bind /tmp/nsX /var/lib/my-app在命名空间中执行此操作,那么当我退出命名空间时,挂载就会消失。

通过进入/退出命名空间,我的意思是ip netns exec bash

我正在看unsharensenter但我不知道该怎么做。

我想要:

  • 为命名空间配置网络
  • 在命名空间中为我的应用程序的工作目录创建绑定安装。
  • 在命名空间中生成我的应用程序。如果有帮助的话,它有一个“fork”选项。
  • 能够离开和进入命名空间,而不会出现任何东西消失或消失的情况。

如果我需要使用其他一些命名空间类型,那也没有问题。

答案1

为什么会发生这种情况?

  • A网络命名空间不更改安装设置:它处理网络

  • 但一些与网络命名空间相关的安装设置,最突出的是 /sys/class/net/proc/sys/net,如上一个链接中所述,确实依赖于网络命名空间

    这里的行为已经存在差异:/proc/sys/net当已经安装时,在进入新的命名空间时会动态更改,/sys/class/net但不会。这意味着当使用真正的命令时仅有的更改网络命名空间:

    unshare -n -- sh -c 'ls -1d /proc/sys/net/*/conf/* /sys/class/net/*'
    

    人们会看到以前的网络接口已经消失/proc/sys/net/(只留下接口的新实例lo),但在以下位置仍然可见/sys/class/net/:防止与新网络命名空间的接口进行交互,并且仍然允许与以前的网络命名空间的接口进行交互,这可能不是一个好主意。

  • 为了解决这个与网络相关的问题,/sys必须从新的网络命名空间(重新)安装。为了避免影响专用于前一个(初始)网络名称空间的环境,必须在较新的网络名称空间中完成此操作名称空间。这就是为什么ip netns exec这样做:为应用程序准备一个连贯的网络环境,它既进入现有的网络命名空间(通过绑定挂载创建并保持存在ip netns add)和取消共享新的挂载命名空间。

  • 仅当进程引用它时,该挂载命名空间才能保持存在。一旦没有进程离开,挂载命名空间以及在其中完成的任何挂载都会消失(只能从此类进程中看到)。

  • 因此,单独使用unshare -mor ip netns exec(甚至不打算首先处理挂载)不会在调用之间保留绑定挂载。

解决方案

应该进行这样的安装使用前ip netns exec ...,一键完成,而不是在创建和销毁(安装)命名空间的单独步骤中。

/etc/netns

实际上ip netns exec已经在其自己的调用中管理此类绑定挂载,但在特定位置:/etc/netns。每次ip netns exec foo调用时,如果目录和/或文件存在且匹配,它将自动将挂载任何内容绑定/etc/netns/foo/*到其匹配的/etc/*.由于此功能旨在促进在单独的命名空间中运行服务的多个实例,因此应优先将其作为解决方案。

/etc/例如,应用程序应该从 中的特定位置检索其配置,/etc/my-app/并且那里应该有一个 per-netns 不同的文件,该文件的内容将应用程序指向其工作目录,无论它在哪里,例如/var/lib/my-app/nsX(甚至/tmp/nsX)。

该目录/etc/my-app/应该存在,并且可能包含某种模板文件,供脚本使用以准备运行实例,但其内容将隐藏在其他名称空间中,因为它将成为绑定安装的目标。

mkdir -p /etc/netns # it is usually not provided by the distribution

for instance in foo bar baz; do
    mkdir "/etc/netns/$instance"
    cp -a /etc/my-app /etc/netns/$instance/
done

然后使用脚本或手动,应该自定义每个实例(数据的位置、pid 文件的位置等),在其他地方添加相关目录(在/var/或中/run(可能在一些启动工具/配置的帮助下,例如tmp文件.d)。

一旦正确完成此操作,人们应该能够在不同的网络中运行应用程序的多个实例,如下所示:

ip netns exec foo my-app
ip netns exec bar my-app
ip netns exec baz my-app

它们之间不会发生冲突(或者这意味着之前还需要做更多的事情)。

unshare -mip netns exec在一起

如果应用程序无法从包装器接收参数/etc或让包装器执行此操作,并且坚持只使用/var/lib/my-app,则紧随其后的绑定挂载ip netns exec也将起作用:

创建 ipnetns 命名空间:

ip netns add foo
ip netns add bar
ip netns add baz

准备网络配置:

ip -n foo link ....

运行应用程序:

unshare -m sh -c 'mount --bind /tmp/foo /var/lib/my-app; exec ip netns exec foo my-app'
unshare -m sh -c 'mount --bind /tmp/bar /var/lib/my-app; exec ip netns exec bar my-app'
unshare -m sh -c 'mount --bind /tmp/baz /var/lib/my-app; exec ip netns exec baz my-app'

虽然这些绑定挂载稍后仍会消失,但它们将被现在实例化的my-app.

它或多或少地重现了已经内置的功能,ip netns exec并带有额外的中间挂载命名空间。

包装纸

您还可以简单地使用一个包装脚本,该脚本需要一个额外的参数来进行挂载,从而避免这个额外的挂载命名空间:

my-app.wrapper(不进行检查):

#!/bin/sh
mount --bind /tmp/"$1" /var/lib/my-app
shift
exec my-app "$@"

并运行:

ip netns exec foo my-app.wrapper foo

一体化

无论选择哪种方法,都应该将其集成到某些启动脚本中。举些systemd例子实例化特征这是我的一个例子)可以与上述方法之一结合使用,以动态创建并运行同一应用程序的新 netns 实例。

相关内容