Linux内核中的namespace和cgroups技术实现了各种资源的隔离与控制。
Namespace
Namespace 是将内核的全局资源做封装,使得每个namespace 都有一份独立的资源,因此不同的进程在各自的namespace内对同一种资源的使用互不干扰。
| |
| Namespace 名称 | 作用 | 内核版本 |
|---|---|---|
| Mount(mnt) | 隔离挂载点 | 2.4.19 |
| Process ID(pid) | 隔离进程ID | 2.6.24 |
| Network(net) | 隔离网络设备、端口号等 | 2.6.29 |
| Interprocess Communication (ipc) | 隔离进程间通信 System V IPC 和 POSIX message queues | 2.6.19 |
| UTS Namespace(uts) | 隔离主机名和域名 | 2.6.19 |
| User Namespace(user) | 隔离用户和用户组 | 3.8 |
| Control group(cgroups)Namespace | 隔离cgroups根目录 | 4.6 |
| Time Namespace | 隔离系统时间 | 5.6 |
3.8 的内核开始,/proc/[pid]/ns 目录下会包含进程所属的 namespace 信息. 使用下面的命令可以查看当前进程所属的 namespace 信息:ll /proc/$$/ns ex:
vagrant@ubuntu20-04:~$ ll /proc/$$/ns
total 0
dr-x--x--x 2 vagrant vagrant 0 Aug 23 03:38 ./
dr-xr-xr-x 9 vagrant vagrant 0 Aug 23 03:38 ../
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 net -> 'net:[4026531992]'
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 user -> 'user:[4026531837]'
lrwxrwxrwx 1 vagrant vagrant 0 Aug 23 03:38 uts -> 'uts:[4026531838]'
隔离挂载点(mount)
Mount Namespace 实现了不同进程可以看到不同的挂载信息。
| |
ex: 使用unshare命令新建一个mount namespace
| |
创建一个临时挂载目录
| |
使用tmpfs挂载一个目录
| |
当前窗口查看挂载信息
root@ubuntu20-04:~# mkdir /tmp/tmpfs
root@ubuntu20-04:~# mount -t tmpfs -o size=1024k tmpfs /tmp/tmpfs
root@ubuntu20-04:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 39G 1.3G 38G 4% /
udev 977M 0 977M 0% /dev
tmpfs 994M 0 994M 0% /dev/shm
tmpfs 199M 924K 198M 1% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 199M 0 199M 0% /run/user/1000
tmpfs 994M 0 994M 0% /sys/fs/cgroup
/dev/loop1 56M 56M 0 100% /snap/core18/2128
/dev/loop0 71M 71M 0 100% /snap/lxd/21029
/dev/loop2 33M 33M 0 100% /snap/snapd/12704
tmpfs 1.0M 0 1.0M 0% /tmp/tmpfs
vagrant@ubuntu20-04:~$
新开一个窗口查看挂载信息,看到没有/tmp/tmpfs挂载信息
Last login: Mon Aug 23 03:38:34 2021 from 10.0.2.2
vagrant@ubuntu20-04:~$ df -h
Filesystem Size Used Avail Use% Mounted on
udev 977M 0 977M 0% /dev
tmpfs 199M 932K 198M 1% /run
/dev/sda1 39G 1.3G 38G 4% /
tmpfs 994M 0 994M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 994M 0 994M 0% /sys/fs/cgroup
/dev/loop1 56M 56M 0 100% /snap/core18/2128
/dev/loop0 71M 71M 0 100% /snap/lxd/21029
/dev/loop2 33M 33M 0 100% /snap/snapd/12704
tmpfs 199M 0 199M 0% /run/user/1000
vagrant@ubuntu20-04:~$
隔离进程ID(pid)
用于实现不同PID Namespace内的进程拥有相同的ID.
创建一个pid namespace
| |
查看进程信息,1号进程为bash
root@ubuntu20-04:~#
root@ubuntu20-04:~# sudo unshare --pid --fork --mount-proc /bin/bash
root@ubuntu20-04:~# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 8960 3892 pts/0 S 03:52 0:00 /bin/bash
root 8 0.0 0.1 10616 3440 pts/0 R+ 03:52 0:00 ps aux
root@ubuntu20-04:~#
隔离网络设备、端口号(net)
net namespace实现网络设备的隔离。
查看主机网络信息
root@ubuntu20-04:~#
root@ubuntu20-04:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:14:28:cf:54:43 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
valid_lft 85336sec preferred_lft 85336sec
inet6 fe80::14:28ff:fecf:5443/64 scope link
valid_lft forever preferred_lft forever
root@ubuntu20-04:~#
创建一个net namespace
| |
查看此net namespace下网络信息
root@ubuntu20-04:~#
root@ubuntu20-04:~# sudo unshare --net --fork /bin/bash
root@ubuntu20-04:~# ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
root@ubuntu20-04:~#
隔离主机名(uts)
UTS Namespace主要是用来隔离主机名的,它允许每个UTS Namespace拥有一个独立的主机名。
创建一个 UTS Namespace
| |
创建完namespace后当前终端已经处于一个独立的UTS Namespace中了。 先看下主机名、然后在修改主机名、最后查看主机。
root@ubuntu20-04:~# sudo unshare --uts --fork /bin/bash
root@ubuntu20-04:~# hostname
ubuntu20-04
root@ubuntu20-04:~# hostname -b changehostname
root@ubuntu20-04:~# hostname
changehostname
root@ubuntu20-04:~#
上面输出已经看到成功修改了主机名。 打开新的bash终端查看主机名
Last login: Mon Aug 23 03:43:22 2021 from 10.0.2.2
vagrant@ubuntu20-04:~$ sudo -i
root@ubuntu20-04:~# hostname
ubuntu20-04
root@ubuntu20-04:~#
主机名并未被修改,验证UTS Namespace隔离主机名。
隔离进程间通信(ipc)
IPC Namespace主要是用来隔离进程间通信的。 ex:
| |
使用unshare命令来创建一个IPC Namespace
| |
ipcs -q命令用于查看系统间通信队列列表。ipcmk -Q命令用于创建系统间通信队列。
root@ubuntu20-04:~#
root@ubuntu20-04:~# sudo unshare --ipc --fork /bin/bash
root@ubuntu20-04:~# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
root@ubuntu20-04:~# ipcmk -Q
Message queue id: 0
root@ubuntu20-04:~# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0xf350f2cb 0 root 644 0 0
root@ubuntu20-04:~#
打开新新窗口终端,查看系统通信队列。
Last login: Mon Aug 23 04:07:29 2021 from 10.0.2.2
vagrant@ubuntu20-04:~$ sudo -i
root@ubuntu20-04:~# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
root@ubuntu20-04:~#
结果可以看到,在单独的IPC Namespace内创建的系统通信队列在主机上无法查看,即IPC Namespace实现了系统间通信对列的隔离。
隔离用户和用户组(user)
User Namespace 主要是用来隔离用户和用户组的。
一个比较典型的应用场景就是在主机上以非root用户运行的进程可以在一个单独的User Namespace中映射成root用户。 使用User Namespace可以实现进程在容器内拥有root权限,而在主机上却只是普通用户。
User Namesapce的创建是可以不使用 root 权限的。 下面我们以普通用户的身份创建一个User Namespace,命令如下:
| |
vagrant@ubuntu20-04:~$
vagrant@ubuntu20-04:~$ unshare --user -r /bin/bash
root@ubuntu20-04:~# id
uid=0(root) gid=0(root) groups=0(root)
root@ubuntu20-04:~# reboot
Failed to connect to bus: Operation not permitted
Failed to open initctl fifo: Permission denied
Failed to talk to init daemon.
root@ubuntu20-04:~#
可以看到,在新创建的User Namespace内虽然是root用户,但是并没有权限执行reboot命令。这说明在隔离的User Namespace中,并不能获取到主机的root权限,也就是说User Namespace实现了用户和用户组的隔离。
Cgroups
Cgroups,其名称源自控制组群(control groups)的简写,也是Linux内核的一个功能,用来限制、控制与统计一个进程组的资源(如CPU、内存、磁盘输入输出等)。
| |
cgroups的主要作用
cgroups的主要目的是为不同用户层面的资源管理提供一个统一化的接口。从单个任务的资源控制到操作系统层面的虚拟化,cgroups四大功能:
- 资源限制:
cgroups可以对任务要求的总资源总额进行限制。诸如,设定任务运行时使用的内存上限,一旦超出内核就发OOM killer(Out-Of-Memory killer)。 - 资源统计:
cgoups可以统计系统的资源使用量,比如CPU使用时长、内存用量等。当前云端产品按使用量计费的方式采用的底层实现方式。 - 任务控制:
cgroups可以对任务执行挂起、恢复等操作。 - 优先级分配:通过分配的
CPU时间片数量和磁盘IO带宽,实际上就等同于控制了任务运行的优先级。
cgroups的文件系统接口
cgroups以文件的方式提供应用接口,可以通过mount命令查看cgroups默认的挂载点:
| |
Subsystem(子系统)
| 子系统 | 作用 |
|---|---|
| hugetlb | 限制HugeTLB(内存页)的使用 |
| net_cls | 配合流控限制网络带宽 |
| net_prio | 设置进程的网络流量优先级 |
| freezer | 暂停/恢复cgroup中的任务/进程 |
| pids | 限制任务/进程的数量 |
| rdma | 限制RDMA/IB资源 |
| devices | 设备访问权限控制 |
| cpuset | 分配指定的CPU和内存节点 |
| perf_event | 允许Perf工具基于Cgroup分组做性能检测 |
| cpu | 控制CPU使用率 |
| cpuacct | 统计CPU使用情况 |
| memory | 限制内存的使用上限 |
| blkio | 对块设备的IO进行限制 |
Tip
23333