每个网络命名空间中的单独 DNS 配置

Ben*_* S. 10 dns namespace network-namespaces

我已经在我的 Linux 系统(内核版本 3.10)上设置了几个网络命名空间,现在我想配置每个网络命名空间以拥有自己的 DNS 设置。

resolv.conf在每个/etc/netns/[namespace]目录中创建了文件,现在我想让我的系统按以下方式工作:

在 bash 命令行中,每当我nsenter --net=/run/netns/[namespace name]使用/etc/netns/[namespace name]/resolv.conf.

如果我像这样运行我的命令:

 "ip netns exec [namespace name] [command]"
Run Code Online (Sandbox Code Playgroud)

然后应用命名空间的 DNS 设置。

但是,在不带“ip netns exec”的情况下运行命令时/etc/resolv.conf,即使运行“netns get cur”表示上下文已设置为所需的网络命名空间,也会从 中获取 DNS 设置。

我尝试mount --bind /etc/netns/[namespace name]/resolv.conf /etc/resolv.conf在适当的网络命名空间的上下文中执行此操作,但这适用于整个系统中的挂载,而不是仅在该网络命名空间的上下文中。

我怀疑使用 mount 命名空间可能会有所帮助,所以我尝试阅读 mount 命名空间的手册页,但是在我致力于它的短时间内无法从中做出任何事情。

有没有一种简单而优雅的方法来实现这个目标?

对解决方案的任何帮助/方向将不胜感激!

iga*_*gal 7

解决方案

您可以使用ip netns execwithbash而不是 using nsenter,即:

ip netns exec [namespace name] bash
Run Code Online (Sandbox Code Playgroud)

这将允许您进入交互式 shell 会话,其中特定于命名空间的网络配置文件会自动绑定安装到它们的默认(全局)位置(不影响其他会话)。

解释

以下内容来自ip netns手册页

对于知道网络命名空间的应用程序,约定是首先在 **/etc/netns/**NAME/ 中查找全局网络配置文件,然后在/etc/ 中。例如,如果您想要一个不同版本的/etc/resolv.conf用于隔离您的 vpn 的网络命名空间,您可以将其命名为/etc/netns/myvpn/resolv.conf

ip netns exec通过创建挂载命名空间并将所有每个网络命名空间的配置文件绑定到 /etc 中的传统位置来自动处理此配置,网络命名空间未知应用程序的文件约定。

请特别注意网络命名空间感知应用程序和网络命名空间未知应用程序之间的区别。

nsenter手册页,在另一方面,似乎没有提到这一点区别(尤其是我搜索字符串“知道”,“RESOLV”,“.conf文件”和‘/ etc’而没有结果发现)。这似乎表明该nsenter实用程序不会对名称空间未知的应用程序执行相同类型的自动处理。

补充评论

除了网络命名空间之外,您可能还想查看用户命名空间装载命名空间。如果您想要进一步隔离 DNS,您可能还需要考虑容器化,例如LXC ContainersDocker,甚至是完整的 VM。

  • `nsenter` 是 `setns` 系统调用的 CLI 工具。因此,它只能做到这一点:加入命名空间。它没有任何关系,就像 `ip netns` 那样,特别是它不会引入额外配置文件位置的复杂性。请注意,您应该始终牢记 UTS 命名空间,因为它隔离了主机名和域名。 (2认同)
  • 我从中学到了很多!最令人惊讶的是,最近有关于`ip` 的内容丰富的手册页。我在很久以前没有“ip”-man 页面的情况下完成了我的作品。 (2认同)

A.B*_*A.B 6

只需看看ip netns exec test ...在您的情况下正在做什么,使用strace.

摘抄:

# strace  -f ip netns exec test sleep 1 2>&1|egrep '/etc/|clone|mount|unshare'|egrep -vw '/etc/ld.so|access'
unshare(CLONE_NEWNS)                    = 0
mount("", "/", 0x55f2f4c2584f, MS_REC|MS_SLAVE, NULL) = 0
umount2("/sys", MNT_DETACH)             = 0
mount("test", "/sys", "sysfs", 0, NULL) = 0
open("/etc/netns/test", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 5
mount("/etc/netns/test/resolv.conf", "/etc/resolv.conf", 0x55f2f4c2584f, MS_BIND, NULL) = 0
Run Code Online (Sandbox Code Playgroud)

所以要重现(部分地,例如/sys这里没有处理)ip netns exec test ...正在做什么:

~# ip netns id

~# head -1 /etc/resolv.conf 
# Generated by NetworkManager
Run Code Online (Sandbox Code Playgroud)

~# nsenter --net=/var/run/netns/test unshare --mount sh -c 'mount --bind /etc/netns/test/resolv.conf /etc/resolv.conf; exec bash'

~# ip netns id
test
~# head -1 /etc/resolv.conf 
# For namespace test
~#
Run Code Online (Sandbox Code Playgroud)

所以没错。nsenter仅靠是不够的。unshare必须使用,更改为新创建的挂载命名空间(基于前一个的副本)并更改它,而不仅仅是逐字使用现有的命名空间,因为尚无适合的现有命名空间。这就是执行与 tell 同名的系统调用的原因strace