docker 原理之 namespace (上)
1. namespace 资源隔离
namespace 是内核实现的一种资源隔离技术,docker 使用 namespace 实现了资源隔离。
Liunx 内核提供 6 种 namespace 隔离的系统调用,如下表所示:
| namespace | 系统调用参数 | 隔离内容 |
|---|---|---|
| UTS | CLONE_NEWUTS | 主机名与域名 |
| IPC | CLONE_NEWIPC | 信号量,消息队列和共享内存 |
| PID | CONE_NEWPID | 进程编号 |
| Network | CLONE_NEWNET | 网络设备,网络栈,端口等 |
| Mount | CLONE_NEWNS | 挂载点(文件系统) |
| User | CLONE_NEWUSER | 用户和用户组 |
Liunx 提供了对 namespace API 调用的三种方式,通过这几种方式可以调用系统调用参数实现对应 namespace 资源的隔离。这三种方式分别是:
- clone(): clone 在创建新进程的同时创建 namespace。
- setns(): setns 加入一个已经存在的 namespace。
- unshare(): unshare 在原先进程上进行 namespace 隔离。
有了系统调用参数和调用 namespace API 的方式,我们就可以构造各种类型的 namespace 了。
1.1 UTS namespace
UTS(UNIX Time-sharing System) namespace 提供主机名和域名的隔离,这里使用 unshare 实现 UTS namespace:
root@chunqiu:~# hostname
chunqiu
root@chunqiu:~# echo $$
31124
root@chunqiu:~# readlink /proc/$$/ns/uts
uts:[4026531838]
root@chunqiu:~# unshare --uts /bin/bash
root@chunqiu:~# hostname
chunqiu
root@chunqiu:~# hostname demo
root@chunqiu:~# hostname
demo
root@chunqiu:~# echo $$
31332
root@chunqiu:~# readlink /proc/$$/ns/uts
uts:[4026532208]
root@chunqiu:~# ps -ef | grep 31332 | grep -v grep
root 31332 31124 0 07:51 pts/0 00:00:00 /bin/bash
root 31345 31332 0 07:52 pts/0 00:00:00 ps -ef
root@chunqiu:~# exit
exit
root@chunqiu:~# hostname
chunqiu
1.2 IPC namespace
IPC(Inter-Process Communication) 进程间通信涉及的 IPC 资源包括信号量,消息队列和共享内存。这里使用 clone() 实现 IPC namespace 的隔离:
/* ipc.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 container_stack[STACK_SIZE];
char* const container_args[] = {
"/bin/bash",
NULL
};
int container_main(void* arg)
{
printf("Container - inside the container\n");
execv(container_args[0], container_args);
printf("Something's wrong!\n");
return 1;
}
int main()
{
printf("start a container:\n");
int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWIPC | SIGCHLD, NULL);
waitpid(container_pid, NULL, 0);
printf("container stopped!\n");
return 0;
}
编译并运行 ipc.c:
root@chunqiu:~/chunqiu/docker/container# echo $$
31124
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/ipc
ipc:[4026531839]
root@chunqiu:~/chunqiu/docker/container# ipcmk -Q
Message queue id: 0
root@chunqiu:~/chunqiu/docker/container# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
0xad26491d 0 root 644 0 0
root@chunqiu:~/chunqiu/docker/container# gcc ipc.c -Wall -o ipc.o && ./ipc.o
start a container:
Container - inside the container
root@chunqiu:~/chunqiu/docker/container# echo $$
31961
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/ipc
ipc:[4026532208]
/* different ipc namesapce */
root@chunqiu:~/chunqiu/docker/container# ipcs -q
------ Message Queues --------
key msqid owner perms used-bytes messages
1.3 PID namespace
1.3.1 父子 PID namespace
PID namespace 对进程 PID 重新标号实现隔离效果,使用 clone 方式实现 PID namespace 的隔离:
/* 代码与 IPC namespace 基本一模一样,只将系统调用参数换成 CLONE_NEWPID */
int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWPID | SIGCHLD, NULL);
编译并运行 pid.c:
root@chunqiu:~/chunqiu/docker/container# echo $$
32090
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/pid
pid:[4026531836]
root@chunqiu:~/chunqiu/docker/container# gcc pid.c -Wall -o pid.o && ./pid.o
start a container:
Container - inside the container
root@chunqiu:~/chunqiu/docker/container# echo $$
1
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/pid
pid:[4026531836]
root@chunqiu:~/chunqiu/docker/container# mount -t proc proc /proc
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/pid
pid:[4026532208]
root@chunqiu:~/chunqiu/docker/container# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 08:41 pts/0 00:00:00 /bin/bash
root 14 1 0 08:42 pts/0 00:00:00 ps -ef
root@chunqiu:~/chunqiu/docker/container#
有一点需要注意的是:在 PID namespace 中 init 进程号为 1,但是 readlink 显示还是和父进程一样,这是因为没有对文件系统挂载点进行隔离。在 PID namespace 内使用 mount 挂载 proc 文件系统,重新执行 readlink 发现 pid 不一样了。
那么,PID namespace 中的 init 进程对应到父 PID namespace 中的哪个进程呢?查看父 PID namespace:
root@chunqiu:~# ps -ef
Error, do this: mount -t proc proc /proc
/* proc 文件系统在子 PID namespace 中,需要重新 mount */
root@chunqiu:~# mount -t proc proc /proc
root@chunqiu:~# ps -ef | grep 32090 | grep -v grep
root 32090 32075 0 08:23 pts/0 00:00:00 -bash
root 32659 32090 0 08:41 pts/0 00:00:00 ./pid.o
root@chunqiu:~# ps -ef | grep 32659 | grep -v grep
root 32659 32090 0 08:41 pts/0 00:00:00 ./pid.o
root 32660 32659 0 08:41 pts/0 00:00:00 /bin/bash
可以看到 PID 为 32660 的 bash 进程即为子 PID namespace 的 init 进程。
1.3.2 init 进程与 dockerfile
在 PID namespace 中,init 进程负责收养成为孤儿进程的子进程。因此,init 进程应该是具有资源监控与回收等管理能力的进程,如 bash 进程。
dockerfile 中执行 CMD 命令产生的进程将会成为 PID namespace 中的 init 进程。以 httpd container 为例,其 dockerfile 如下:
...
COPY httpd-foreground /usr/local/bin/
EXPOSE 80
CMD ["httpd-foreground"]
运行 httpd container,ps 查看进程号:
$ ps -ef | grep httpd | grep -v grep
root 7469 7446 0 09:50 ? 00:00:00 httpd -DFOREGROUND
$ ps -ef | grep 7446 | grep -v grep
root 7446 842 0 09:50 ? 00:00:00 containerd-shim -namespace moby -workdir ...
root 7469 7446 0 09:50 ? 00:00:00 httpd -DFOREGROUND
$ ps -ef | grep 842 | grep -v grep
root 842 1 0 09:32 ? 00:00:00 /usr/bin/containerd
可以看到进程号为 7469 的 httpd -DFOREGROUND 进程即为 httpd container 中的 init 进程。
PID namespace 嵌套
PID namespace 是一种层级体系,这里构造一种在子 PID namespace 中嵌套 PID namespace 的场景,如下:
root@chunqiu:~/chunqiu/docker/container# echo $$
32090
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/pid
pid:[4026531836]
root@chunqiu:~/chunqiu/docker/container# ./pid.o
start a container:
Container - inside the container
root@chunqiu:~/chunqiu/docker/container# echo $$
1
root@chunqiu:~/chunqiu/docker/container# mount -t proc proc /proc
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/pid
pid:[4026532209]
/* 子 PID namespace 中创建 PID namespace */
root@chunqiu:~/chunqiu/docker/container# ./pid.o
start a container:
Container - inside the container
root@chunqiu:~/chunqiu/docker/container# echo $$
1
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/pid
pid:[4026532209]
root@chunqiu:~/chunqiu/docker/container# mount -t proc proc /proc
root@chunqiu:~/chunqiu/docker/container# readlink /proc/$$/ns/pid
pid:[4026532214]
root@chunqiu:~/chunqiu/docker/container# exit
exit
container stopped!
root@chunqiu:~/chunqiu/docker/container# exit
exit
container stopped!
1.4 Network namespace
network namespace 参看 这里。
docker 原理之 namespace (上)的更多相关文章
- Docker原理:Namespace
目录 Namespace UTS Namespae PID Namespace Mount Namespace User Namespace Network Namespace 参考 Namespac ...
- docker原理
Docker原理11 Linux Namespace 11 AUFS文件系统17 重新理解Docker的各种命令18 Docker原理 Linux Namespace docker是一个容器引擎,容器 ...
- Docker原理(图解+秒懂+史上最全)
背景:下一个视频版本,从架构师视角,尼恩为大家打造高可用.高并发中间件的原理与实操. 目标:通过视频和博客的方式,为各位潜力架构师,彻底介绍清楚架构师必须掌握的高可用.高并发环境,包括但不限于: 高可 ...
- 理解Docker(3):Docker 使用 Linux namespace 隔离容器的运行环境
本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...
- 一篇不一样的docker原理解析
转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...
- Docker原理探究
问题思考:-------------------------------------Docker浅显原理理解-------------------------------------P1. ubunt ...
- Docker源码分析(七):Docker Container网络 (上)
1.前言(什么是Docker Container) 如今,Docker技术大行其道,大家在尝试以及玩转Docker的同时,肯定离不开一个概念,那就是“容器”或者“Docker Container”.那 ...
- docker原理(转)
转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...
- 一篇文章带你吃透 Docker 原理
容器的实现原理 从本质上,容器其实就是一种沙盒技术.就好像把应用隔离在一个盒子内,使其运行.因为有了盒子边界的存在,应用于应用之间不会相互干扰.并且像集装箱一样,拿来就走,随处运行.其实这就是 Paa ...
- Docker入门与进阶(上)
Docker入门与进阶(上) 作者 刘畅 时间 2020-10-17 目录 1 Docker核心概述与安装 1 1.1 为什么要用容器 1 1.2 docker是什么 1 1.3 docker设计目标 ...
随机推荐
- C#Socket编程详解(一)TCP与UDP简介
一.TCP与UDP(转载) 1.TCP 1.1 定义 TCP(TransmissionControl Protocol)传输控制协议. 是一种可靠的.面向连接的协议(eg:打电话).传输效率低全双工通 ...
- 文心一言 VS 讯飞星火 VS chatgpt (167)-- 算法导论13.1 7题
七.用go语言,试描述一棵含有 n 个关键字的红黑树,使其红色内部结点个数与黑色内部结点个数的比值最大.这个比值是多少? 该比值最小的树又是怎样呢?比值是多少? 文心一言: 红黑树是一种自平衡的二叉查 ...
- 如何从零开始实现TDOA技术的 UWB 精确定位系统(2)
这是一个系列文章<如何从零开始实现TDOA技术的 UWB 精确定位系统>第2部分. 重要提示(劝退说明): Q:做这个定位系统需要基础么?A:文章不是写给小白看的,需要有电子技术和软件编程 ...
- Ubuntu部署NTP服务器和客户端
https://www.cnblogs.com/lsgxeva/p/14265513.html Ubuntu部署NTP服务器和客户端 NTP或网络时间协议是一种协议,用于将网络中的所有系统时钟同步以使 ...
- Unix 文件权限位
简介 在 Unix 或者类 Unix 文件系统中,每个文件(或者目录,目录也被视为文件)都有自己的所属对象和一个与之相关的 Unix 用户组关联,可以通过设置对应的文件的权限标记指定对于所属用户.所属 ...
- 文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题
五.在大小为n的集合中,一个k字符串构成一个k排列的概率是多少?这个问题和生日悖论有什么关系? 文心一言: 在大小为n的集合中,一个k字符串构成一个k排列的概率是1/k!,这是由于排列的总数是k!,而 ...
- 十分钟从入门到精通(上)——OBS权限配置
[摘要]作为公有云的数据底座,大量的应用场景产生的数据都会存储到OBS对象存储服务中,如直播.电商.大数据可视化.机器学习.物联网等.作为公有云的海量存储基础服务, OBS提供了灵活的权限配置功能,解 ...
- 物联网常见协议之Amqp协议及使用场景解析
摘要:本文围绕AMQP协议,为大家详细解析AMQP协议.核心技术亮点.多协议之间的对比以及使用实践. 本文分享自华为云社区<物联网常见协议之Amqp协议及使用场景解析>,作者:张俭. 引言 ...
- Serverless冷启动:如何让函数计算更快更强?
摘要:借助Serverless计算,开发者仅需上传业务代码并进行简单的资源配置便可实现服务的快速构建部署,云服务商则按照函数服务调用量和实际资源使用收费,从而帮助用户实现业务的快速交付和低成本运行. ...
- 4种方法帮你解决IntelliJ IDEA控制台中文乱码问题
摘要:在本文中总结了4 种方法完美解决 IntelliJ IDEA 控制台中文乱码问题. 前言 IntelliJ IDEA 如果不进行配置的话,运行程序时控制台中文乱码问题会非常严重,严重影响我们对信 ...