王烨妮,seo 网站太小,能制作网页的软件是,中国建设网站首页【Docker 内核详解 - namespace 资源隔离】系列包含#xff1a;
namespace 资源隔离#xff08;一#xff09;#xff1a;进行 namespace API 操作的 4 种方式namespace 资源隔离#xff08;二#xff09;#xff1a;UTS namespace IPC namespacenamespace 资源隔…【Docker 内核详解 - namespace 资源隔离】系列包含
namespace 资源隔离一进行 namespace API 操作的 4 种方式namespace 资源隔离二UTS namespace IPC namespacenamespace 资源隔离三PID namespacenamespace 资源隔离四Mount namespace Network namespacenamespace 资源隔离五User namespaces namespace 资源隔离二UTS namespace IPC namespace
1.UTS namespace
UTSUNIX Time-sharing SystemUTS namespace 提供了 主机名 和 域名 的隔离这样每个 Docker 容器就可以拥有独立的主机名和域名了在网络上可以被视作一个独立的节点而非宿主机上的一个进程。Docker 中每个镜像基本都以自身所提供的服务名称来命名镜像的 hostname且不会对宿主机产生任何影响其原理就是利用了 UTS namespace。
下面通过代码来感受一下 UTS 隔离的效果首先需要一个程序的骨架。打开编辑器创建 uts.c 文件输入如下代码。
#define _GNU_SOURCE
#include sys/types.h
#include sys/wait.h
#include stdio.h
#include sched.h
#include signal.h
#include unistd.h#define STACK_SIZE (1024 * 1024)static char child_stack[STACK_SIZE];
char* const child_args[] {/bin/bash,NULL
};int child_main(void* args){printf在子进程中!\nexecv(child_args[0], child_args);return 1;
}int main(){printf程序开始\nint child_pid clone(child_main, child_stack STACK_SIZE, SIGCHLD, NULL);waitpid(child_pid, NULL, 0);printf已退出\n;return 0;
}编译并运行上述代码执行如下命令效果如下。
-Wall 是 GCC 编译器的一个编译选项它会开启编译器的所有警告选项。当开启 -Wall 选项后编译器会对代码中可能存在的潜在问题发出警告例如未使用变量、变量未初始化、类型转换等。这样可以让开发者更好地发现潜在的问题并进行修复。
rootlocal:~# gcc -Wall uts.c -o uts.o ./uts.o
程序开始
在子进程中
rootlocal:~# exit
exit
已退出
rootlocal:~#下面将修改代码加入 UTS 隔离。运行代码需要 root 权限以防止普通用户任意修改系统主机名导致 set-user-ID 相关的应用运行出错。
// [...]
int child_main(void* arg) {printf(在子进程中!\n);sethostname(NewNamespace, 12);execv(child_args[0], child_args);return 1;
}int main(){//[...]int child_pid clone(child_main, child_stack STACK_SIZE, CLONE_NEWUTS | SIGCHLD, NULL);//[...]
}再次运行可以看到 hostname 已经变化。
rootlocal:~# gcc -Wall namespace.c -o main.o ./main.o
程序开始
在子进程中
rootNewNamespace:~# exit
exit
已退出
rootlocal:~# -- 回到原来的hostname值得一提的是也许有读者会尝试不加 CLONE_NEWUTS 参数运行上述代码发现主机名同样改变了并且输入 exit 后主机名也恢复了似乎并没有区别。实际上不加 CLONE_NEWUTS 参数进行隔离时由于使用 sethostname 函数所以宿主机的主机名被修改了。而看到 exit 退出后主机名还原是因为 bash 只在刚登录时读取一次 UTS不会实时读取最新的主机名。当重新登录或者使用 uname 命令进行查看时就会发现产生的变化。
2.IPC namespace
进程间通信Inter-Process CommunicationIPC涉及的 IPC 资源包括常见的 信号量、消息队列 和 共享内存。申请 IPC 资源就申请了一个全局唯一的 32 32 32 位 ID所以 IPC namespace 中实际上包含了 系统 IPC 标识符 以及 实现 POSIX 消息队列的文件系统。在同一个 IPC namespace 下的进程彼此可见不同 IPC namespace 下的进程则互相不可见。
IPC namespace 在实现代码上与 UTS namespace 相似只是标识位有所变化需要加上 CLONE_NEWIPC 参数。主要改动如下其他部分不变程序名称改为 ipc.c。
// [...]
int child_pid clone(child_main, child_stack STACK_SIZE, CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD, NULL);
// [...]首先在 shell 中使用 ipcmk -Q 命令创建一个 message queue。
rootlocal:~# ipcmk-Q
Message queue id: 32769通过 ipcs- q 可以查看到已经开启的 message queue序号为 32769 32769 32769。
rootlocal:~# ipcs -q
------ Message Queues ----
key msqid owner perms used-bytes messages
0x4cf5e29f 32769 root 644 0 0然后可以编译运行加入了 IPC namespace 隔离的 ipc.c在新建的子进程中调用的 shell 中执行 ipcs -q 查看 message queue。
rootlocal:~# gcc -wall ipc.c -o ipc.o ./ipc.o
程序开始
在子进程中
rootNewNamespace:~# ipcs -q
------ Message Queues ------
key msqid owner perms used-bytes messages
rootNewNamespace:~# exit
exit
已退出从结果显示中可以发现子进程找不到原先声明的 message queue了已经实现了 IPC 的隔离。
目前使用 IPC namespace 机制的系统不多其中比较有名的有 PostgreSQL。Docker 当前也使用 IPC namespace 实现了容器与宿主机、容器与容器之间的 IPC 隔离。