Namespace是Linux内核引入的隔离功能。
| Namespace类型 | Flag标识符 | Flag值 | 作用 |
|---|---|---|---|
| Mount | CLONE_NEWNS |
0x00020000 |
隔离文件系统 |
| Cgroup | CLONE_NEWCGROUP |
0x02000000 |
|
| UTS | CLONE_NEWUTS |
0x04000000 |
隔离nodename和domainname |
| IPC | CLONE_NEWIPC |
0x08000000 |
隔离System V IPC和POSIX message queue |
| User | CLONE_NEWUSER |
0x10000000 |
隔离UID和GID |
| PID | CLONE_NEWPID |
0x20000000 |
隔离PID |
| Network | CLONE_NEWNET |
0x40000000 |
隔离网络设备、IP地址、端口号 |
| Time | CLONE_NEWTIME |
0x00000080 |
隔离时间 |
以Go语言为例:
package main
import (
"log"
"os"
"os/exec"
"syscall"
)
func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER | syscall.CLONE_NEWNET,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil { log.Fatal(err) }
os.Exit(0)
}$ go run main.go
sh-5.2$ id
uid=65534(nobody) gid=65534(nogroup) 组=65534(nogroup)
sh-5.2$ ifconfigLinux提供了Cgroups,用于限制指定若干进程的资源限额(例如CPU、内存、存储、网络等)。一个Cgroups由若干进程与Subsystem实例构成。
| Subsystem名称 | 作用 |
|---|---|
blkio |
管理块设备I/O访问控制 |
cpu |
管理CPU调度策略 |
cpuacct |
统计CPU占用 |
cpuset |
管理多核CPU限额 |
devices |
管理设备访问 |
freezer |
管理进程的挂起与恢复 |
memory |
管理内存限额 |
net_cls |
分类网络包 |
net_prio |
管理网络包优先级 |
ns |
管理Namespace |
使用lssubsys -a查看Linux内核支持的所有Subsystem。该命令行工具可安装自apt install cgroup-bin或nix-shell -p libcgroup。
$ lssubsys -a
cpu
cpuacct
blkio
devices
freezer
net_cls
perf_event
net_prio
hugetlb
pids
rdma
misc
debug下面的例子展示了如何创建一个层级结构(Hierarchy)及其Cgroup根节点。挂载点中的文件表示了该节点的各项配置:
$ mkdir cgroup
$ sudo mount -t cgroup -o none,name=cgroup_folder cgroup_folder ./cgroup
$ tree ./cgroup
cgroup/
├── cgroup.clone_children
├── cgroup.procs
├── cgroup.sane_behavior
├── notify_on_release
├── release_agent
└── taskscgroup.clone_children:由Subsystemcpuset读取,若为1则子Cgroup会继承父Cgroup的配置,若为0则不继承。cgroup.procs:当前Cgroup中所有进程组ID。Cgroup根节点本身就是最高级Cgroup,包含了当前系统中的所有进程PID。notify_on_release:当前Cgroup退出时是否要执行release_agent,1为执行,0为不执行。release_agent:当前Cgroup退出时执行的程序路径task:当前Cgroup中所有进程的PID
要创建子Cgroup,只需新建文件夹即可,Linux会自动在新目录下创建相关文件:
$ sudo mkdir cgroup/subgroup_1
$ tree cgroup/
cgroup/
├── cgroup.clone_children
├── cgroup.procs
├── cgroup.sane_behavior
├── notify_on_release
├── release_agent
├── subgroup_1
│ ├── cgroup.clone_children
│ ├── cgroup.procs
│ ├── notify_on_release
│ └── tasks
└── tasks将进程的PID追加到Cgroup的tasks文件,即可在Cgroup中添加进程。删除进程同理。
$ bash
$ echo $$
175234
$ sudo sh -c "echo $$ >> cgroup/subgroup_1/tasks"
$ cat /proc/$$/cgroup
1:name=cgroup_folder:/subgroup_1
0::/user.slice/user-1000.slice/session-2.scope
$ mount | grep "memory"
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)我们使用Go语言实现Cgroup对内存的限制: