Linux Namespace

Linux Namespace

Linux Namespace是一种隔离机制,它将全局系统资源包装起来,使得PID、IPC、Network、Mount、UTS、User、CGroup不再是全局性的,而是属于特定的Namespace。每个Namespace下的资源对于其他Namespace都是不可见的。

一个进程可以属于多个Namespace。

Namespace种类

namespace 名称 系统调用参数 含义 kernel版本
Mount CLONE_NEWNS 隔离一组进程看到的文件系统的挂载点,不同的命名空间可以具有不同的文件系统结构 2.4.19
PID CLONE_NEWPID 隔离进程编号,PID 命名空间的主要好处之一是容器可以在主机之间迁移,同时为容器内的进程保留相同的进程 ID。PID 命名空间还允许每个容器拥有自己的 init (PID 1),即“所有进程的祖先”,管理各种系统初始化任务并在它们终止时回收孤立的子进程。 2.6.14
Network CLONE_NEWNET 隔离网络设备,堆栈,端口等 2.6.29
IPC CLONE_NEWIPC 隔离进程间通信系统 IPC, POSIX 消息队列 2.6.19
UTS CLONE_NEWUTS 隔离节点名和域名 2.6.19
User CLONE_NEWUSER 隔离用户和组ID 3.8
Cgroup CLONE_NEWCGROUP 隔离Cgroup 根目录,可以防止信息泄露而导致cgroup目录路径外部进程可见;隔离后,Cgroup路径名是独立的,容器迁移时,防止cgroup路径名与目标系统上的路径名发生冲突;将cgroup文件系统完全隔离开,可以防止容器进程无法访问主机的cgroup目录 4.6

每种namespace各有自己管理的部分,对于现在 Linux 上的任意进程而言,它一定是每种 namespace 的一个实例 (就是每个进程都得归属于某个ns,ns中可以只有一个进程,也可以由多个进程共有)

隔离cgroup说明:假设一个场景,有一个cgroup目录/cg/1,它归USER ID 9000所有,有一个进程X也归USER ID 9000所有,该进程的命名空间位于cgroup目录/cg/1/2。在没有cgroup命名空间的情况下,因为cgroup目录/cg/1由UID 9000拥有(可写)并且进程X也由UID 9000所有,进程X则既能修改/cg/1的文件,也能修改/cg/1/2的文件。通过cgroup namespace,可以防止进程X修改/cg/1的中的文件,因为它看不到该目录。这样可以防止进程X逃逸其ancestor cgroup的限制。

Linux 提供了以下主要的系统调用用于管理namespace:

  • clone():如果是纯粹只使用clone(),则会创建一个新进程;但如果我们传递一个或多个 CLONE_NEW* 标志参数给clone(),则会根据每个标志创建对应的新namespace 并且将子进程添加为其成员,达到隔离效果。
  • setns():允许进程加入一个已存在的 namespace 中。
  • unshare():允许进程(或线程)取消其执行上下文中,与其他进程(或线程)共享部分的关联,通俗点来说,也就是可以利用此系统调用来让当前的进程(或线程)移动至一个新的namespace中。

隔离IPC

IPC 全称 Inter-Process Communication,是进程间通信的一种方式,IPC有管道、共享内存、信号量、消息队列、信号、套接字。

  1. 查看主机信号量
  2. 主机上创建信号量

ipcmk -S 10

ipcs

  1. 创建一个新的IPC Namespace,然后查看ns中的信号量

    unshare –ipc

隔离UTS

UTS(Unix Timesharing System)命名空间包含了运行内核的名称、版本、底层体系结构类型等信息

unshare –uts
hostname
hostname test
hostname

查看ns中的hostname和主机上的name
分别为testedunode1

隔离User

隔离user namespace

unshare –user

可以通过-r参数,把新的namespace中的root用户映射成宿主机上的用户,例如,把ns中的用户映射为宿主机的root

unshare –user -r root

隔离PID

unshare –pid

观察主机上的进程

观察PID namespace中的进程

隔离Network

  1. 创建netns

    ip netns add ns1

ip netns list

  1. 查看ns1中的网络,通过ip netns exec执行在ns中执行响应命令

ip netns exec ns1 ip addr

  1. 测试网络连通性

    ip netns exec ns1 ping 10.6.8.113

通过veth pair与宿主机、其他ns进行网络通信

  1. 创建veth pair

ip link add veth0 type veth peer name veth1

  1. 将veth0或者veth1移动到ns1中

    ip link set veth1 netns ns1

  2. 配置ip

    ip netns exec ns1 ifconfig veth1 192.168.10.100/24

ifconfig veth0 192.168.10.101/24

  1. 将网卡启动

    ip netns exec ns1 ifconfig veth1 up

ifconfig veth0

  1. 测试

    ip netns exec ns1 ping 192.168.10.101

同理,可将veth peer分别放在两个netns中进行联通

通过bridge中转

实际使用中,不可能每2个不同的ns都进行一次veth pair配置,这时就需要Linux Bridge来做转发,将veth pair中的一个veth peer绑定到ns中,另一端绑定到bridge上。

  1. 创建两个netns,和两对veth pair

    ip netns add ns0
    ip netns add ns1

ip link add veth0 type veth peer name br-veth0
ip link add veth1 type veth peer name br-veth1

  1. 创建bridge,并启动网桥

    brctl addbr br0

ip link set br0 up

  1. 将veth pair中的一端分别加入到ns中,另一端放到bridge上

将veth0放入ns0中,并配置ip

ip link set veth0 netns ns0
ip netns exec ns0 ifconfig veth0 192.168.10.100/24 up
ip netns exec ns0 ip link set lo up

将br-veth0绑定到网桥br0上,并启动br-veth0

brctl addif br0 br-veth0
ip link set br-veth0 up

将veth1放入ns1中,并配置ip,启动lo

ip link set veth1 netns ns1
ip netns exec ns1 ifconfig veth1 192.168.10.101/24 up
ip netns exec ns1 ip link set lo up

将br-veth1绑定到网桥br0上,并启动br-veth1

brctl addif br0 br-veth1
ip link set br-veth1 up

通过brctl show查看网桥

  1. 连通性测试

    ip netns exec ns0 ping 192.168.10.101