可以通过unshare命令来观察到这些细节。在终端执行man unshare,将会出现这些Namespace的介绍。 执行下面的命令,进入隔离环境,并将bash作为根进程: unshare --pid --fork --mount-proc /bin/bash 效果如图所示。 试验一下 unshare --mount --fork /bin/bash 创建mount namespace,并在每个不同的环境中,使用不同的挂载目录。 unshare --user -r /bin/bash 用户命名空间,就非常好理解了。 unshare --net --fork /bin/bash net namespace,这个就非常有用了。它可以用来隔离网络设备、IP 地址和端口等信息。
离开一个命名空间:unshare() 最后一个命名空间中的系统调用是 unshare(): int unshare(int flags); unshare() 类似于 clone(),但作用施加于调用者 (我们将忽略 clone(),unshare() 提供命名空间之外的功能)。unshare() 的主要目的是隔离命名空间,但无需创建一个新进程或线程(clone() 所做的)。 / unshare() 系统调用的用途之一是实现 unshare 命令,允许用户在隔离于 shell 的命名空间中执行命令。 unshare 命令的关键部分实现如下: /* Code to initialize 'flags' according to command-line options omitted */ unshare 命令的简单实现(unshare.c)在这儿。
6.unshare 命令 功能:用于在不共享父进程命名空间的情况下运行指定程序。 如果直接运行 unshare -p /bin/bash: /bin/bash 会继承当前进程的 PID(仍在原命名空间),无法成为新 PID 命名空间的 init 进程。 --fork的作用 --fork(或 -f)会让 unshare在创建新命名空间后,先调用 fork() 创建一个子进程,再在该子进程中运行 /bin/bash。 这样: unshare调用 fork(),生成一个子进程。 子进程进入新的 PID 命名空间,并成为该命名空间的 init进程(PID=1)。 添加 --fork: unshare -p --fork /bin/bash #错误演示 注意:如果执行失败,使用exit指令退出子进程,再进行执行。
to create new mount namespace:", err) return } // 创建新的网络命名空间 if err := syscall.Unshare new network namespace:", err) return } // 创建新的进程间通信(IPC)命名空间 if err := syscall.Unshare create new IPC namespace:", err) return } // 创建新的主机名和域名命名空间 if err := syscall.Unshare create new user namespace:", err) return } // 创建新的进程 ID 命名空间 if err := syscall.Unshare 在每个 Unshare 调用中,我们传入对应的 Cloneflags 标志位,以创建对应的命名空间。
CLONE_NEWNS 文件系统 User CLONE_NEWUSER 用户与用户组 namespace api 创建一个namespace一般使用clone()来创建,其API还包括setns()、unshare 执行后使用clone()创建子进程继续执行命令,让原进程结束运行 加入namespace后可以通过引入execve()函数执行用户命令(调用/bin/bash 接收参数,运行起一个shell) unshare () unshare()与clone()很像,不同的是unshare()不需要启动一个新进程 UTS 通过在clone()方法的flags中选择CLONE_NEWUTS参数来实现隔离不同namespace 因此若在Docker容器中运行多个进程,最先启动的进程应该是具有资源管理能力的,init进程还可以对信号进行捕捉,如Docker中接收容器结束信号后结束容器进程回收资源 在PID namespace下unshare
UTS Namespace案例实践 在进行UTS Namespace案例实践之前,我们先来了解个关键指令:「unshare,运行一些与父级不共享某些名称空间的程序。」 root@node3:~# unshare --help Usage: unshare [options] <program> [<argument>...] 1、首先我们使用 unshare 命令来创建一个 UTS Namespace # unshare --uts --fork /bin/bash 创建好 UTS Namespace 后,宿主机shell下 lsns列出namespace信息,会发现最后一条就是我们使用unshare创建了一个uts类型的namespace: 2、回到上步uts命名空间shell下,使用 hostname 命令设置一下主机名
() 最后一个要介绍的系统调用是 unshare(),它的原型如下: int unshare(int flags); unshare() 与 clone() 类似,但它运行在原先的进程上,不需要创建一个新进程 Linux 中自带的 unshare 命令,就是通过 unshare() 系统调用实现的,使用方法如下: $ unshare [options] program [arguments] options v2 or later A simple implementation of the unshare(1) command: unshare namespaces and execute \n"); fprintf(stderr, " -m unshare mount namespace\n"); fprintf(stderr, " -n unshare " -u unshare UTS namespace\n"); fprintf(stderr, " -U unshare user namespace\n"); exit
软件上可分为UnShare Led 和 Share Led,其中假设两个Shared Led分别为Led 1和Led2。 MAIN_LOG("-> UnShare led test 1st! \n"); } thePowerLed1->Relase(); // 当前使用释放,才可被再次使用 MAIN_LOG("\n-> UnShare led test 2nd! /exe -> UnShare led test 1st! Power Led (pin10) ON. Power Led (pin10) OFF. . -> UnShare led test 2nd! Power Led (pin10) ON. -> Share led test 1st! Led 0 (pin20) Start.
user namespace可以通过clone(),unshare()这两个system call创建,通过setns()加入一个已有的user namespace。 clone(),unshare(),setns()这三个API将会影响进程属于哪个user namespace。 unshare()用于给调用这个API的进程创建一个独立的user namespace。 代码如下所示: unshare(CLONE_NEWUSER); 和clone()不同,unshare()的调用使得调用者自己进入了一个全新的user namespace。 unshare(CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWUSER|CLONE_NEWUTS|); 所有其它的namespace被称为non-user namespace。
容器中默认禁用unshare 被禁用的原因在官方文档[9]有所说明,感兴趣的可以阅读了解。 然而,该capability可以通过unshare系统调用获得。 unshare系统调用会将进程分配至新的namespace,如在容器内部使用unshare -U命令可以使用户进入一个新的user namespace,由于Linux capability继承的机制,新的 通过上文的背景知识可以了解到比较矛盾的是,在Docker容器中,因为Seccomp机制的限制,unshare系统调用会被禁止,所以此种方法在普通业务容器中并不适用。 但当处于低版本(1.22版本之前)的Kubernetes集群环境中,在默认配置情况下,非特权用户可以在Pod内部顺利执行unshare系统调用。
带 CLONE_NEWNS 标志的 clone()(在新命名空间中创建新子进程)或 unshare()(将调用方移到新命名空间中)可创建新的挂载命名空间。 当新的装挂载名空间被创建时,它将接收 clone() 或 unshare() 的调用者的命名空间的挂载点列表的拷贝。 在 clone() 或 unshare() 之后,可以在每个命名空间中独立地添加和删除挂载点(通过 mount() 和 umount() )。 然后,在第二个终端上,我们使用 unshare 命令创建一个新的挂载命名空间,在其中运行 shell: sh2# unshare -m --propagation unchanged sh (-m 选项创建一个新的挂载命名空间 不过,util-linux 的 unshare 特性却不这样认为。
namespace 中具有独立的网络协议栈,因此每个Network namespace 中都有一个 lo 网络接口,但是 lo 接口默认状态是 DOWN,需要手动启动起来 root@debian:~# unshare 在第一个shell窗口创建network namespace,并查看其进程号 root@debian:~# unshare -n /bin/bash root@debian:~# echo $$ 1235 其实方式很简单,直接在unshare创建namespace时的对应长选项上指定一个已存在的文件即可(注:不允许在短选项上指定文件名)。 作为持久化文件 root@debian:~# mkdir -p /var/run/netns root@debian:~# touch /var/run/netns/ns1 root@debian:~# unshare var/run/netns/NAME(不存在时会自动创建),使得该network namespace就像是被ip netns创建一样,之后它将受ip netns管理 在第一个shell窗口中执行,使用unshare
(2)unshare() unshare() 系统调用可以将进程从主机命名空间中分离出来,并创建一个新的命名空间,使得容器拥有自己独立的命名空间。 在 Docker 中,unshare() 系统调用被用于创建新的命名空间,并将容器进程与主机进程分离开来,以实现容器的隔离。这个命名空间将成为容器进程的根命名空间,容器进程只能访问该命名空间下的资源。 fmt.Printf("child process exit status: %d\n", status.ExitStatus()) } (3)容器启动 在容器创建完成后,Docker 会使用 unshare package main import ( "fmt" "syscall" ) func main() { // 创建新的 UTS 命名空间 err := syscall.Unshare 在 Docker 中,clone() 系统调用被用于创建新的容器进程,unshare() 系统调用被用于创建新的命名空间,以实现容器的隔离,而 setns() 系统调用被用于将容器进程切换到相应的命名空间中
unshare() unshare() 系统调用可以将进程从主机命名空间中分离出来,并创建一个新的命名空间,使得容器拥有自己独立的命名空间。 在 Docker 中,unshare() 系统调用被用于创建新的命名空间,并将容器进程与主机进程分离开来,以实现容器的隔离。这个命名空间将成为容器进程的根命名空间,容器进程只能访问该命名空间下的资源。 } fmt.Printf("child process exit status: %d\n", status.ExitStatus())}容器启动 在容器创建完成后,Docker 会使用 unshare 示例代码package mainimport ( "fmt" "syscall")func main() { // 创建新的 UTS 命名空间 err := syscall.Unshare 在 Docker 中,clone() 系统调用被用于创建新的容器进程,unshare() 系统调用被用于创建新的命名空间,以实现容器的隔离,而 setns() 系统调用被用于将容器进程切换到相应的命名空间中
int unshare(int flags); ioctl() : ioctl系统调用可用于查询命名空间的信息 int ioctl(int fd , unsigned long request , .. .); ---- 下面我们通过shell 命令 unshare 来看看命名空间7大隔离实现 1.PID Namespace PID Namespace 的作用是用来隔离进程,利用 PID Namespace 我们创建一个命名空间 unshare --mount --fork /bin/bash 挂在一个目录 [root@i-k9pwet2d ~]# mkdir /tmp/mnt [root@i-k9pwet2d [root@i-k9pwet2d ~]# unshare --fork --uts /bin/bash 在命名空间中修改主机名,在主机中不受影响 [root@i-k9pwet2d ~]# hostname 我们继续创建一个Net Namespace [root@i-k9pwet2d ~]# unshare --net --fork /bin/bash 查看网络和端口信息 [root@i-k9pwet2d
unshare Linux 中,unshare 命令行程序可以创建一个 namespace,并且根据参数创建在 namespace 中隔离各种资源,在这里我们可以用使用这个工具简单地创建一个 namespace 为了深刻理解 Linux 中的 namespace,我们可以在 Linux 中执行: unshare --pid /bin/sh --pid 仅隔离进程。 在执行 unshare 命令前,使用 pstree 命令查看进程树: init─┬─2*[init───init───bash] ├─init───init───bash───pstree --pid top 创建一个 namespace,对比执行了 unshare 命令后: $> pstree -lha init ├─init │ └─init │ └─bash │ └─sudo unshare --pid top │ └─top ├─init │ └─init │ └─bash
在演示之前,我们先来认识一个命令行工具 unshare。 unshare 是 util-linux 工具包中的一个工具,CentOS 7 系统默认已经集成了该工具,使用 unshare 命令可以实现创建并访问不同类型的 Namespace。 通过以上结果我们可以得出结论,使用 unshare 命令可以新建 Mount Namespace,并且在新建的 Mount Namespace 内 mount 是和外部完全隔离的。 同样我们通过一个实例来验证下 UTS Namespace 的作用,首先我们使用 unshare 命令来创建一个 UTS Namespace: [root@docker-demo ~]# unshare 同样我们通过一个实例来验证下IPC Namespace的作用,首先我们使用 unshare 命令来创建一个 IPC Namespace: [root@docker-demo ~]# unshare --
unshare Linux 中,unshare 命令行程序可以创建一个 namespace,并且根据参数创建在 namespace 中隔离各种资源,在这里我们可以用使用这个工具简单地创建一个 namespace 为了深刻理解 Linux 中的 namespace,我们可以在 Linux 中执行: unshare --pid /bin/sh --pid 仅隔离进程。 在执行 unshare 命令前,使用 pstree 命令查看进程树: init─┬─2*[init───init───bash] ├─init───init───bash───pstree --pid top 创建一个 namespace,对比执行了 unshare 命令后: $> pstree -lha init ├─init │ └─init │ └─bash │ └─sudo unshare --pid top │ └─top ├─init │ └─init │ └─bash
0x03 进程切换 unshare 命令 描述:/usr/bin/unshare是Linux自带的命令实际通过unshare()系统调用实现的,调用的主要作用就是不启动一个新进程就可以起到隔离效果,简单的说就是跳出原先的 int unshare(int flags); 基础语法: 用法: unshare [options] <program> [<argument>...] 选项: -m, --mount unshare mounts namespace -u, --uts unshare UTS namespace unshare network namespace -p, --pid unshare pid namespace -U, --user unshare user namespace -f, --fork 执行unshare的进程fork一个新的子进程,在子进程里执行unshare传入的参数 --
创建一个user namespace可以使用unshare或fork,当未指定CLONE_NEWUSER时会创建一个与父user namespace相同的namespace;使用setns可以加入一个namespace unshare默认执行/bin/sh创建一个shell交互界面 unshare --fork --pid --mount-proc 这样就启动了一个独立的pid namespace sh-4.2# ping 127.0.0.1 查看相应的进程(已过滤无关内容),可以看到ping进程是unshare的子进程,当unshare退出之后,namespace也会随之被销毁 [root@localhost home mount point有2种方式可以加入同一个peer group:第一种是使用clone或unshare方式创建一个新的mount namespace,这样多个mount namespace下的peer 的propagation类型 [root@host /]# unshare -fmu --propagation unchanged [root@host /]# hostname container