对于容器来说,可以与host共享网络名字空间,也可以用单独的网络名字空间。这个可以通过container的配置文件来指定。
如果需要用单独的网络名字空间,可以指定容器的网络类型为veth:
lxc.network.type = veth
如果要跟host共享网络名字空间,那么可以指定容器的网络类型为none
lxc.network.type = none
在host上面,作为root用户,是有权限访问所有网络名字空间的数据的,但是大部分程序默认只是访问host所在的网络名字空间。如果我们想访问容器的网络名字空间的数据,那该怎么做呢?
下面讲一下ip netns的用法。
[router] / # ip netns help Usage: ip netns list ip netns add NAME ip netns set NAME NETNSID ip [-all] netns delete [NAME] ip netns identify [PID] ip netns pids NAME ip [-all] netns exec [NAME] cmd ... ip netns monitor [router] / #
如果我们在host上面创建运行了多个容器,那么就应该会创建多个网络名字空间,用ip netns list应该可以列出来,但是在linux 4.4的host系统上面,我们发现这个命令显示不出任何信息。
实际上ip netns只能看到/var/run/netns里面的内容,但是对于lxc container来说,创建容器时,不会将网络名字空间加到这个目录。如果要使用ip netns,需要我们手动加入。
举例来说,比方说我们现在有个进程(pid=16674)运行在某个容器中,可以通过该进程的proc目录获取该进程所在的网络名字空间:
[router] /proc/16674/ns # ls -la dr-x--x--x 2 root root 0 Mar 30 20:37 . dr-xr-xr-x 8 root root 0 Mar 30 04:11 .. lrwxrwxrwx 1 root root 0 Mar 30 20:37 ipc -> ipc:[4026532966] lrwxrwxrwx 1 root root 0 Mar 30 20:37 mnt -> mnt:[4026532964] lrwxrwxrwx 1 root root 0 Mar 30 20:37 net -> net:[4026532969] lrwxrwxrwx 1 root root 0 Mar 30 20:37 pid -> pid:[4026532967] lrwxrwxrwx 1 root root 0 Mar 30 20:37 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Mar 30 20:37 uts -> uts:[4026532965]
我们可以创建一个软链接如下:
[router] /proc/16674/ns # ln -s /proc/16674/ns/net /var/run/netns/ns1
再执行ip netns list就可以看到这个网络名字空间了:
[router] /proc/16674/ns # ip netns list ns1 (id: 2)
那么下面我们就可以用ip netns访问某个网络名字空间的数据。下面我们在容器的网络名字空间里执行iptables可以显示该网络名字空间里面的规则:
[router] /proc/16674/ns # ip netns exec ns1 iptables -nvL Chain INPUT (policy ACCEPT 96591 packets, 7177K bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 95210 packets, 7046K bytes) pkts bytes target prot opt in out source destination
可以看到里面的chain都是空的,跟host里面的规则完全不同。
至于这种机制是如何实现的,我们可以简单了解下。我们先看看下面的系统接口:
- clone():创建新的进程
- setns():允许指定进程加入特定的namespace
- unshare():将指定进程移除指定的namespace
可以看看setns这个API,他可以将某个进程加入到特定的namespace。那么我们知道linux支持如下几种namespace:
Namespace | 变量 | 隔离资源 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
如果我们想让一个进程在某个网络名字空间里运行,我们可以创建一个空的父进程,通过setns来指定这个进程的网络名字空间,然后在父进程里fork出子进程来运行所要执行的程序,默认情况下,子进程会继承父进程的名字空间。那么这样就能让程序在指定的名字空间里面执行了。
原文地址:https://www.cnblogs.com/utopia007/p/12603352.html